rust_fuzzylogic/membership/
trapezoidal.rs

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