Skip to main content

rhai_sci/
misc.rs

1use rhai::plugin::*;
2
3#[export_module]
4pub mod misc_functions {
5    use crate::{if_list_convert_to_vec_float_and_do, if_list_do_int_or_do_float};
6    use rhai::{Array, Dynamic, EvalAltResult, Position, FLOAT};
7
8    /// Infinity
9    #[allow(non_upper_case_globals)]
10    pub const inf: FLOAT = FLOAT::INFINITY;
11
12    /// Returns a random number between zero and one.
13    /// ```typescript
14    /// let r = rand();
15    /// assert(r >= 0.0 && r <= 1.0);
16    /// ```
17    #[cfg(feature = "rand")]
18    #[rhai_fn(name = "rand")]
19    pub fn rand_float() -> FLOAT {
20        randlib::random()
21    }
22
23    /// Returns an array of the unique elements in an array.
24    /// ```typescript
25    /// let data = [1, 2, 2, 2, 5, 4, 4, 2, 5, 8];
26    /// let u = unique(data);
27    /// assert_eq(u, [1, 2, 4, 5, 8]);
28    /// ```
29    #[rhai_fn(name = "unique", return_raw, pure)]
30    pub fn unique(arr: &mut Array) -> Result<Array, Box<EvalAltResult>> {
31        if arr.is_empty() {
32            return Ok(Array::new());
33        }
34        if_list_do_int_or_do_float(
35            arr,
36            |arr| {
37                let mut x = crate::array_to_vec_int(arr);
38                x.sort();
39                x.dedup();
40                Ok(x.iter().map(|el| Dynamic::from_int(*el)).collect())
41            },
42            |arr| {
43                let mut x = crate::array_to_vec_float(arr);
44                x.sort_by(|a, b| a.partial_cmp(b).unwrap());
45                x.dedup();
46                Ok(x.iter().map(|el| Dynamic::from_float(*el)).collect())
47            },
48        )
49    }
50
51    /// Given reference data, perform linear interpolation.
52    ///
53    /// Both arrays must be sorted and have the same length.
54    ///
55    /// Out-of-bound xq values are clamped to the minimum and maximum values of y respectively.
56    /// ```typescript
57    /// let x = [0, 1];
58    /// let y = [1, 2];
59    /// let xq = 0.5;
60    /// let yq = interp1(x, y, xq);
61    /// assert_eq(yq, 1.5);
62    /// ```
63    #[rhai_fn(name = "interp1", return_raw)]
64    pub fn interp1(x: &mut Array, y: Array, xq: Dynamic) -> Result<FLOAT, Box<EvalAltResult>> {
65        let new_xq = if xq.is_int() {
66            xq.as_int().unwrap() as FLOAT
67        } else if xq.is_float() {
68            xq.as_float().unwrap()
69        } else {
70            return Err(EvalAltResult::ErrorArithmetic(
71                "xq must be either INT or FLOAT".to_string(),
72                Position::NONE,
73            )
74            .into());
75        };
76
77        let mut y = y;
78
79        if_list_convert_to_vec_float_and_do(&mut y, |new_y| {
80            if_list_convert_to_vec_float_and_do(x, |new_x| {
81                if new_x.len() < 2 {
82                    return Err(EvalAltResult::ErrorArithmetic(
83                        "The arrays must have at least 2 elements".to_string(),
84                        Position::NONE,
85                    )
86                    .into());
87                }
88                if new_x.len() != new_y.len() {
89                    return Err(EvalAltResult::ErrorArithmetic(
90                        "The arrays must have the same length".to_string(),
91                        Position::NONE,
92                    )
93                    .into());
94                }
95
96                if new_xq >= *new_x.last().unwrap() {
97                    return Ok(*new_y.last().unwrap());
98                } else if new_xq <= *new_x.first().unwrap() {
99                    return Ok(*new_y.first().unwrap());
100                }
101
102                // Identify the right index
103                let b = new_x
104                    .iter()
105                    .enumerate()
106                    .find_map(|(i, &el)| (el >= new_xq).then(|| i))
107                    .unwrap();
108
109                let a = b - 1;
110                Ok(new_y[a] + (new_xq - new_x[a]) * (new_y[b] - new_y[a]) / (new_x[b] - new_x[a]))
111            })
112        })
113    }
114}