rust_fuzzylogic/membership/
triangular.rs

1use super::{slope, validate_order, Float, MembershipFn};
2
3///Struct for triangular membership function.
4///Initialize by calling the new() function.
5#[derive(Clone, Copy, PartialEq, Debug)]
6pub struct Triangular {
7    left: Float,
8    center: Float,
9    right: Float,
10}
11
12impl MembershipFn for Triangular {
13    ///Evaluates the membership value for the input x against the membership struct.
14    fn eval(&self, x: Float) -> Float {
15        //out of bounds check
16        if x <= self.left {
17            return 0.0;
18        }
19        if x >= self.right {
20            return 0.0;
21        }
22
23        //calculation within membership function
24        if (x - self.center).abs() < 1e-9 {
25            1.0
26        } else if x < self.center {
27            slope(x, self.left, self.center, 1.0)
28        } else {
29            slope(x, self.center, self.right, -1.0)
30        }
31    }
32}
33
34impl Triangular {
35    ///Initializes the struct. Note that it requires left < center < right.
36    pub fn new(l: Float, c: Float, r: Float) -> crate::error::Result<Self> {
37        validate_order(&[l, c, r])?;
38        return Ok(Triangular {
39            left: l,
40            center: c,
41            right: r,
42        });
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn test_triangular() {
52        let membership_func = Triangular::new(-1.0, 0.0, 1.0);
53        let eps = crate::Float::EPSILON;
54
55        assert_eq!(
56            Triangular::new(0.0, 0.0, -1.0),
57            Err(crate::error::FuzzyError::BadArity)
58        );
59
60        assert!((membership_func.clone().unwrap().eval(0.0) - 1.0).abs() < eps);
61        assert!((membership_func.clone().unwrap().eval(0.5) - 0.5).abs() < eps);
62        assert!((membership_func.unwrap().eval(1.0)).abs() < eps);
63    }
64}