inari/
absmax.rs

1use crate::{classify::*, interval::*, simd::*};
2
3impl Interval {
4    /// Returns the absolute value of `self`.
5    ///
6    /// The domain and the range of the point function are:
7    ///
8    /// | Domain | Range     |
9    /// | ------ | --------- |
10    /// | $\R$   | $\[0, ∞)$ |
11    #[must_use]
12    pub fn abs(self) -> Self {
13        use IntervalClass::*;
14        match self.classify() {
15            E | P0 | P1 | Z => self,
16            M => {
17                // [0, max(-a, b)] = [0; max(-a, b)]
18                let x = self.rep; // [-a; b]
19                let r = max(x, swap(x)); // [max(-a, b); _]
20                Self {
21                    rep: shuffle02(splat(0.0), r),
22                }
23            }
24            N0 | N1 => {
25                // [-b, -a] = [b; -a]
26                Self {
27                    rep: swap(self.rep),
28                }
29            }
30        }
31    }
32
33    /// Returns the maximum of `self` and `rhs`.
34    ///
35    /// The domain and the range of the point function are:
36    ///
37    /// | Domain | Range |
38    /// | ------ | ----- |
39    /// | $\R^2$ | $\R$  |
40    #[must_use]
41    pub fn max(self, rhs: Self) -> Self {
42        if HAS_MAXIMUM {
43            // [max(a, c), max(b, d)] = [-max(a, c); max(b, d)] = [min(-a, -c); max(b, d)]
44            let min = minimum(self.rep, rhs.rep); // [min(-a, -c); min(b, d)]
45            let max = maximum(self.rep, rhs.rep); // [max(-a, -c); max(b, d)]
46            Self {
47                rep: shuffle03(min, max),
48            }
49        } else {
50            if self.either_empty(rhs) {
51                return Self::EMPTY;
52            }
53
54            let min = min(self.rep, rhs.rep);
55            let max = max(self.rep, rhs.rep);
56            Self {
57                rep: shuffle03(min, max),
58            }
59        }
60    }
61
62    /// Returns the minimum of `self` and `rhs`.
63    ///
64    /// The domain and the range of the point function are:
65    ///
66    /// | Domain | Range |
67    /// | ------ | ----- |
68    /// | $\R^2$ | $\R$  |
69    #[must_use]
70    pub fn min(self, rhs: Self) -> Self {
71        if HAS_MAXIMUM {
72            // [min(a, c), min(b, d)] = [-min(a, c); min(b, d)] = [max(-a, -c); min(b, d)]
73            let max = maximum(self.rep, rhs.rep); // [max(-a, -c); max(b, d)]
74            let min = minimum(self.rep, rhs.rep); // [min(-a, -c); min(b, d)]
75            Self {
76                rep: shuffle03(max, min),
77            }
78        } else {
79            if self.either_empty(rhs) {
80                return Self::EMPTY;
81            }
82
83            let max = max(self.rep, rhs.rep);
84            let min = min(self.rep, rhs.rep);
85            Self {
86                rep: shuffle03(max, min),
87            }
88        }
89    }
90}
91
92impl DecInterval {
93    /// The decorated version of [`Interval::abs`].
94    ///
95    /// A NaI is returned if `self` is NaI.
96    #[must_use]
97    pub fn abs(self) -> Self {
98        if self.is_nai() {
99            return self;
100        }
101
102        Self::set_dec(self.x.abs(), self.d)
103    }
104
105    /// The decorated version of [`Interval::max`].
106    ///
107    /// A NaI is returned if `self` or `rhs` is NaI.
108    #[must_use]
109    pub fn max(self, rhs: Self) -> Self {
110        if self.is_nai() {
111            return self;
112        }
113
114        Self::set_dec(self.x.max(rhs.x), self.d.min(rhs.d))
115    }
116
117    /// The decorated version of [`Interval::min`].
118    ///
119    /// A NaI is returned if `self` or `rhs` is NaI.
120    #[must_use]
121    pub fn min(self, rhs: Self) -> Self {
122        if self.is_nai() {
123            return self;
124        }
125
126        Self::set_dec(self.x.min(rhs.x), self.d.min(rhs.d))
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use crate::*;
133    use DecInterval as DI;
134    use Interval as I;
135
136    #[test]
137    fn empty() {
138        assert!(I::EMPTY.abs().is_empty());
139
140        assert!(I::EMPTY.max(I::PI).is_empty());
141        assert!(I::PI.max(I::EMPTY).is_empty());
142
143        assert!(I::EMPTY.min(I::PI).is_empty());
144        assert!(I::PI.min(I::EMPTY).is_empty());
145
146        assert!(DI::EMPTY.abs().is_empty());
147
148        assert!(DI::EMPTY.max(DI::PI).is_empty());
149        assert!(DI::PI.max(DI::EMPTY).is_empty());
150
151        assert!(DI::EMPTY.min(DI::PI).is_empty());
152        assert!(DI::PI.min(DI::EMPTY).is_empty());
153    }
154
155    #[test]
156    fn nai() {
157        assert!(DI::NAI.abs().is_nai());
158
159        assert!(DI::NAI.max(DI::PI).is_nai());
160        assert!(DI::PI.max(DI::NAI).is_nai());
161
162        assert!(DI::NAI.min(DI::PI).is_nai());
163        assert!(DI::PI.min(DI::NAI).is_nai());
164    }
165}