inari_wasm/
classify.rs

1use crate::interval::*;
2use std::mem::transmute;
3
4impl Interval {
5    pub(crate) fn classify(self) -> IntervalClass {
6
7        // let ge_zero = bitmask(ge(self.rep, zero)) as u8;
8		let inf_ge_zero = (-self.inf >= 0.0) as u8;
9		let sup_ge_zero = (self.sup >= 0.0) as u8;
10        let ge_zero = sup_ge_zero << 1 | inf_ge_zero;
11
12		// let le_zero = bitmask(le(self.rep, zero)) as u8;
13		let inf_le_zero = (-self.inf <= 0.0) as u8;
14		let sup_le_zero = (self.sup <= 0.0) as u8;
15		let le_zero = sup_le_zero << 1 | inf_le_zero;
16
17        unsafe { transmute((le_zero << 2) | ge_zero) }
18    }
19
20    pub(crate) fn classify2(self, rhs: Self) -> IntervalClass2 {
21        unsafe { transmute(((self.classify() as u8) << 4) | rhs.classify() as u8) }
22    }
23}
24
25// The following codes are used to represent the class of an interval:
26//
27//  Code | Description
28// ------+---------------
29//     E | Empty
30//     M | a < 0 < b
31//    N0 | a < 0 ∧ b = 0
32//    N1 | b < 0
33//    P0 | a = 0 ∧ 0 < b
34//    P1 | 0 < a
35//     Z | a = b = 0
36//    N* | a < 0 ∧ b ≤ 0
37//    P* | a = 0 ∧ 0 ≤ b
38// * These codes are used only in comments.
39
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41#[repr(u8)]
42pub(crate) enum IntervalClass {
43    // Each bit represents b ≤ 0, -a ≤ 0, b ≥ 0 and -a ≥ 0, respectively.
44    E = 0b0000,  // empty
45    M = 0b0011,  // b > 0 ∧ -a > 0
46    N0 = 0b1011, // b = 0 ∧ -a > 0
47    N1 = 0b1001, // b < 0 ∧ -a > 0
48    P0 = 0b0111, // b > 0 ∧ -a = 0
49    P1 = 0b0110, // b > 0 ∧ -a < 0
50    Z = 0b1111,  // b = 0 ∧ -a = 0
51}
52
53macro_rules! discr {
54    ($x:ident, $y:ident) => {
55        ((IntervalClass::$x as u8) << 4) | IntervalClass::$y as u8
56    };
57}
58
59#[allow(dead_code)]
60#[allow(non_camel_case_types)] // We could rename E_E to ExE, etc., but that would degrade the legibility.
61#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62#[repr(u8)]
63pub(crate) enum IntervalClass2 {
64    E_E = discr!(E, E),
65    E_M = discr!(E, M),
66    E_N0 = discr!(E, N0),
67    E_N1 = discr!(E, N1),
68    E_P0 = discr!(E, P0),
69    E_P1 = discr!(E, P1),
70    E_Z = discr!(E, Z),
71
72    M_E = discr!(M, E),
73    M_M = discr!(M, M),
74    M_N0 = discr!(M, N0),
75    M_N1 = discr!(M, N1),
76    M_P0 = discr!(M, P0),
77    M_P1 = discr!(M, P1),
78    M_Z = discr!(M, Z),
79
80    N0_E = discr!(N0, E),
81    N0_M = discr!(N0, M),
82    N0_N0 = discr!(N0, N0),
83    N0_N1 = discr!(N0, N1),
84    N0_P0 = discr!(N0, P0),
85    N0_P1 = discr!(N0, P1),
86    N0_Z = discr!(N0, Z),
87
88    N1_E = discr!(N1, E),
89    N1_M = discr!(N1, M),
90    N1_N0 = discr!(N1, N0),
91    N1_N1 = discr!(N1, N1),
92    N1_P0 = discr!(N1, P0),
93    N1_P1 = discr!(N1, P1),
94    N1_Z = discr!(N1, Z),
95
96    P0_E = discr!(P0, E),
97    P0_M = discr!(P0, M),
98    P0_N0 = discr!(P0, N0),
99    P0_N1 = discr!(P0, N1),
100    P0_P0 = discr!(P0, P0),
101    P0_P1 = discr!(P0, P1),
102    P0_Z = discr!(P0, Z),
103
104    P1_E = discr!(P1, E),
105    P1_M = discr!(P1, M),
106    P1_N0 = discr!(P1, N0),
107    P1_N1 = discr!(P1, N1),
108    P1_P0 = discr!(P1, P0),
109    P1_P1 = discr!(P1, P1),
110    P1_Z = discr!(P1, Z),
111
112    Z_E = discr!(Z, E),
113    Z_M = discr!(Z, M),
114    Z_N0 = discr!(Z, N0),
115    Z_N1 = discr!(Z, N1),
116    Z_P0 = discr!(Z, P0),
117    Z_P1 = discr!(Z, P1),
118    Z_Z = discr!(Z, Z),
119}
120
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125    use crate::*;
126    use Interval as I;
127
128    #[test]
129    fn classify() {
130        use IntervalClass::*;
131        assert_eq!(I::EMPTY.classify(), E);
132        assert_eq!(I::ENTIRE.classify(), M);
133        assert_eq!(const_interval!(-1.0, 1.0).classify(), M);
134        assert_eq!(const_interval!(-1.0, 0.0).classify(), N0);
135        assert_eq!(const_interval!(-1.0, -1.0).classify(), N1);
136        assert_eq!(const_interval!(0.0, 1.0).classify(), P0);
137        assert_eq!(const_interval!(1.0, 1.0).classify(), P1);
138        assert_eq!(I::zero().classify(), Z);
139    }
140}