intervals_general/
interval.rs

1use crate::bound_pair::BoundPair;
2use itertools::Either;
3use std::cmp::Ordering;
4
5#[cfg(not(feature = "serde"))]
6mod without_serde {
7    use crate::bound_pair::BoundPair;
8    /// Interval enum capable of general interval representation
9    ///
10    /// Where applicable, using lower bound `a` and upper bound `b`.  An Interval taxonomy was pulled from [proofwiki](https://proofwiki.org/wiki/Definition:Real_Interval_Types).
11    ///
12    /// * Closed -> `[a, b]`
13    /// * Open -> `(a,b)`
14    /// * LeftHalfOpen -> `(a, b]`
15    /// * RightHalfOpen -> `[a, b)`
16    /// * UnboundedClosedRight -> `(-inf, a]`
17    /// * UnboundedOpenRight -> `(-inf, a)`
18    /// * UnboundedClosedLeft -> `[a, inf)`
19    /// * UnboundedOpenLeft -> `(a, inf)`
20    /// * Singeleton -> `[a]`
21    /// * Unbounded -> `(-inf, inf)`
22    /// * Empty
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use intervals_general::bound_pair::BoundPair;
28    /// use intervals_general::interval::Interval;
29    /// # fn main() -> std::result::Result<(), String> {
30    /// let bounds = BoundPair::new(1.0, 2.0).ok_or("invalid BoundPair")?;
31    /// let right_half_open = Interval::RightHalfOpen { bound_pair: bounds }; // [1.0, 2.0)
32    /// # Ok(())
33    /// # }
34    /// ```
35    #[derive(Debug, Copy, Clone, PartialEq)]
36    pub enum Interval<T> {
37        Closed { bound_pair: BoundPair<T> },
38        Open { bound_pair: BoundPair<T> },
39        LeftHalfOpen { bound_pair: BoundPair<T> },
40        RightHalfOpen { bound_pair: BoundPair<T> },
41        UnboundedClosedRight { right: T },
42        UnboundedOpenRight { right: T },
43        UnboundedClosedLeft { left: T },
44        UnboundedOpenLeft { left: T },
45        Singleton { at: T },
46        Unbounded,
47        Empty,
48    }
49}
50
51#[cfg(feature = "serde")]
52mod with_serde {
53    use serde::{Deserialize, Serialize};
54
55    use crate::bound_pair::BoundPair;
56    /// Interval enum capable of general interval representation
57    ///
58    /// Where applicable, using lower bound `a` and upper bound `b`.  An Interval taxonomy was pulled from [proofwiki](https://proofwiki.org/wiki/Definition:Real_Interval_Types).
59    ///
60    /// * Closed -> `[a, b]`
61    /// * Open -> `(a,b)`
62    /// * LeftHalfOpen -> `(a, b]`
63    /// * RightHalfOpen -> `[a, b)`
64    /// * UnboundedClosedRight -> `(-inf, a]`
65    /// * UnboundedOpenRight -> `(-inf, a)`
66    /// * UnboundedClosedLeft -> `[a, inf)`
67    /// * UnboundedOpenLeft -> `(a, inf)`
68    /// * Singeleton -> `[a]`
69    /// * Unbounded -> `(-inf, inf)`
70    /// * Empty
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use intervals_general::bound_pair::BoundPair;
76    /// use intervals_general::interval::Interval;
77    /// # fn main() -> std::result::Result<(), String> {
78    /// let bounds = BoundPair::new(1.0, 2.0).ok_or("invalid BoundPair")?;
79    /// let right_half_open = Interval::RightHalfOpen { bound_pair: bounds }; // [1.0, 2.0)
80    /// # Ok(())
81    /// # }
82    /// ```
83    #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
84    pub enum Interval<T> {
85        Closed { bound_pair: BoundPair<T> },
86        Open { bound_pair: BoundPair<T> },
87        LeftHalfOpen { bound_pair: BoundPair<T> },
88        RightHalfOpen { bound_pair: BoundPair<T> },
89        UnboundedClosedRight { right: T },
90        UnboundedOpenRight { right: T },
91        UnboundedClosedLeft { left: T },
92        UnboundedOpenLeft { left: T },
93        Singleton { at: T },
94        Unbounded,
95        Empty,
96    }
97}
98
99#[cfg(feature = "serde")]
100pub use with_serde::Interval;
101#[cfg(not(feature = "serde"))]
102pub use without_serde::Interval;
103
104// Internally used to simplify matching functions on Intervals
105enum Bound<T> {
106    None,
107    Unbounded,
108    Open(T),
109    Closed(T),
110}
111
112type TwoIntervalIter<T> =
113    std::iter::Chain<std::iter::Once<Interval<T>>, std::iter::Once<Interval<T>>>;
114type OneIntervalIter<T> = std::iter::Once<Interval<T>>;
115
116impl<T> Interval<T>
117where
118    T: Copy,
119    T: std::cmp::PartialOrd,
120{
121    /// Verify whether self contains the specified interval
122    ///
123    /// Interval I1.contains(I2) if and only if:
124    ///
125    /// * The left bound of I1 is bounded and less than or equal to the left
126    ///   bound of I2 OR
127    /// * the left bound of I1 is unbounded and the left bound of I2 is
128    ///   unbounded
129    ///
130    /// AND
131    ///
132    /// * The right bound of I1 is bounded and greater than or equal to the
133    ///   right bound of I2 OR
134    /// * The right bound of I1 isunbounded and the left bound of I2 is
135    ///   unbounded
136    ///
137    /// Additionally:
138    ///
139    /// * The Empty interval does not contain the Empty interval
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// use intervals_general::bound_pair::BoundPair;
145    /// use intervals_general::interval::Interval;
146    /// # fn main() -> std::result::Result<(), String> {
147    /// let right_half_open = Interval::RightHalfOpen {
148    ///     bound_pair: BoundPair::new(1.0, 5.0).ok_or("invalid BoundPair")?,
149    /// };
150    /// let contained_interval = Interval::Open {
151    ///     bound_pair: BoundPair::new(1.0, 2.0).ok_or("invalid BoundPair")?,
152    /// };
153    /// let non_contained_interval = Interval::Closed {
154    ///     bound_pair: BoundPair::new(4.0, 5.0).ok_or("invalid BoundPair")?,
155    /// };
156    /// assert_eq!(right_half_open.contains(&contained_interval), true);
157    /// assert_eq!(right_half_open.contains(&non_contained_interval), false);
158    /// # Ok(())
159    /// # }
160    /// ```
161    pub fn contains(&self, other: &Interval<T>) -> bool {
162        let self_right_bound = self.right_bound();
163        let other_right_bound = other.right_bound();
164        let self_left_bound = self.left_bound();
165        let other_left_bound = other.left_bound();
166
167        let left_contained = match (self_left_bound, other_left_bound) {
168            // The Empty Interval contains no other Intervals (even Empty)
169            (Bound::None, _) => false,
170            // The Empty interval is contained in all non-Empty Intervals
171            (_, Bound::None) => true,
172            // If self left interval is unbounded, it will contain any other left bound
173            (Bound::Unbounded, _) => true,
174            // Given self left interval is not unbounded and right is unbounded, self cannot contain
175            // other
176            (_, Bound::Unbounded) => false,
177            (Bound::Closed(ref self_val), Bound::Closed(ref other_val))
178            | (Bound::Closed(ref self_val), Bound::Open(ref other_val))
179            | (Bound::Open(ref self_val), Bound::Open(ref other_val)) => self_val <= other_val,
180            (Bound::Open(ref self_val), Bound::Closed(ref other_val)) => self_val < other_val,
181        };
182
183        let right_contained = match (self_right_bound, other_right_bound) {
184            // The Empty interval does not contain the Empty interval
185            (Bound::None, _) => false,
186            (_, Bound::None) => false,
187            // If self left interval is unbounded, it will contain any other left bound
188            (Bound::Unbounded, _) => true,
189            // Given self left interval is not unbounded and right is unbounded, self cannot contain
190            // other
191            (_, Bound::Unbounded) => false,
192            (Bound::Closed(ref self_val), Bound::Closed(ref other_val))
193            | (Bound::Closed(ref self_val), Bound::Open(ref other_val))
194            | (Bound::Open(ref self_val), Bound::Open(ref other_val)) => self_val >= other_val,
195            (Bound::Open(ref self_val), Bound::Closed(ref other_val)) => self_val > other_val,
196        };
197
198        left_contained && right_contained
199    }
200
201    /// Intersect an with the specified Interval
202    ///
203    /// Take the intersection of self with the specified Interval.
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// use intervals_general::bound_pair::BoundPair;
209    /// use intervals_general::interval::Interval;
210    ///
211    /// # fn main() -> std::result::Result<(), String> {
212    /// let i1 = Interval::RightHalfOpen {
213    ///     bound_pair: BoundPair::new(1, 5).ok_or("invalid BoundPair")?,
214    /// };
215    /// let i2 = Interval::Open {
216    ///     bound_pair: BoundPair::new(-1, 2).ok_or("invalid BoundPair")?,
217    /// };
218    ///
219    /// assert_eq!(
220    ///     i1.intersect(&i2),
221    ///     Interval::RightHalfOpen {
222    ///         bound_pair: BoundPair::new(1, 2).ok_or("invalid BoundPair")?
223    ///     }
224    /// );
225    /// # Ok(())
226    /// # }
227    /// ```
228    pub fn intersect(&self, other: &Interval<T>) -> Interval<T> {
229        let left_cmp_partial = self.left_partial_cmp(other);
230        let right_cmp_partial = self.right_partial_cmp(other);
231        if left_cmp_partial.is_none() || right_cmp_partial.is_none() {
232            return Interval::Empty;
233        }
234
235        let left_bound = if left_cmp_partial != Some(Ordering::Less) {
236            self.left_bound()
237        } else {
238            other.left_bound()
239        };
240        let right_bound = if right_cmp_partial != Some(Ordering::Greater) {
241            self.right_bound()
242        } else {
243            other.right_bound()
244        };
245
246        match (left_bound, right_bound) {
247            (Bound::None, _) => Interval::Empty,
248            (_, Bound::None) => Interval::Empty,
249            (Bound::Closed(left), Bound::Closed(right)) => {
250                if left > right {
251                    Interval::Empty
252                } else if left == right {
253                    Interval::Singleton { at: left }
254                } else {
255                    Interval::Closed {
256                        bound_pair: BoundPair { left, right },
257                    }
258                }
259            }
260            (Bound::Open(left), Bound::Open(right)) => {
261                if left >= right {
262                    Interval::Empty
263                } else {
264                    Interval::Open {
265                        bound_pair: BoundPair { left, right },
266                    }
267                }
268            }
269            (Bound::Open(left), Bound::Closed(right)) => {
270                if left >= right {
271                    Interval::Empty
272                } else {
273                    Interval::LeftHalfOpen {
274                        bound_pair: BoundPair { left, right },
275                    }
276                }
277            }
278            (Bound::Closed(left), Bound::Open(right)) => {
279                if left >= right {
280                    Interval::Empty
281                } else {
282                    Interval::RightHalfOpen {
283                        bound_pair: BoundPair { left, right },
284                    }
285                }
286            }
287            (Bound::Unbounded, Bound::Closed(right)) => Interval::UnboundedClosedRight { right },
288            (Bound::Unbounded, Bound::Open(right)) => Interval::UnboundedOpenRight { right },
289            (Bound::Closed(left), Bound::Unbounded) => Interval::UnboundedClosedLeft { left },
290            (Bound::Open(left), Bound::Unbounded) => Interval::UnboundedOpenLeft { left },
291            (Bound::Unbounded, Bound::Unbounded) => Interval::Unbounded,
292        }
293    }
294
295    fn left_bound(&self) -> Bound<T> {
296        match self {
297            Interval::Empty => Bound::None,
298            Interval::Singleton { ref at } => Bound::Closed(*at),
299            // The cases where left bound of self is open -inf
300            Interval::Unbounded
301            | Interval::UnboundedClosedRight { .. }
302            | Interval::UnboundedOpenRight { .. } => Bound::Unbounded,
303            // The cases where left bound of self is Closed and Bounded
304            Interval::Closed {
305                bound_pair: BoundPair { ref left, .. },
306            }
307            | Interval::RightHalfOpen {
308                bound_pair: BoundPair { ref left, .. },
309            }
310            | Interval::UnboundedClosedLeft { ref left, .. } => Bound::Closed(*left),
311            // The cases where left bound of self is Open and Bounded
312            Interval::Open {
313                bound_pair: BoundPair { ref left, .. },
314            }
315            | Interval::LeftHalfOpen {
316                bound_pair: BoundPair { ref left, .. },
317            }
318            | Interval::UnboundedOpenLeft { ref left, .. } => Bound::Open(*left),
319        }
320    }
321
322    fn right_bound(&self) -> Bound<T> {
323        match self {
324            Interval::Empty => Bound::None,
325            Interval::Singleton { ref at } => Bound::Closed(*at),
326            // The cases where right bound of self is open +inf
327            Interval::Unbounded
328            | Interval::UnboundedClosedLeft { .. }
329            | Interval::UnboundedOpenLeft { .. } => Bound::Unbounded,
330            // The cases where right bound of self is Closed and Bounded
331            Interval::Closed {
332                bound_pair: BoundPair { ref right, .. },
333            }
334            | Interval::LeftHalfOpen {
335                bound_pair: BoundPair { ref right, .. },
336            }
337            | Interval::UnboundedClosedRight { ref right, .. } => Bound::Closed(*right),
338            // The cases where right bound of self is Open and Bounded
339            Interval::Open {
340                bound_pair: BoundPair { ref right, .. },
341            }
342            | Interval::RightHalfOpen {
343                bound_pair: BoundPair { ref right, .. },
344            }
345            | Interval::UnboundedOpenRight { ref right, .. } => Bound::Open(*right),
346        }
347    }
348
349    /// The PartialOrd::partial_cmp implementation for left Bounds
350    ///
351    /// Though Intervals on some generics (e.g. integers) can supply [Ord](https://doc.rust-lang.org/std/cmp/trait.Ord.html) because they form a [total order](https://en.wikipedia.org/wiki/Total_order),
352    /// unfortunately our floating point implementations break such properties.
353    /// Therefore the best we can do under some generics is satisfy [PartialOrd](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html).
354    ///
355    /// # Examples
356    ///
357    /// ```
358    /// use intervals_general::bound_pair::BoundPair;
359    /// use intervals_general::interval::Interval;
360    /// use std::cmp::Ordering;
361    ///
362    /// # fn main() -> std::result::Result<(), String> {
363    /// let right_half_open = Interval::RightHalfOpen {
364    ///     bound_pair: BoundPair::new(1.0, 5.0).ok_or("invalid BoundPair")?,
365    /// };
366    /// let contained_interval = Interval::Open {
367    ///     bound_pair: BoundPair::new(1.0, 2.0).ok_or("invalid BoundPair")?,
368    /// };
369    ///
370    /// assert_eq!(
371    ///     contained_interval.left_partial_cmp(&right_half_open),
372    ///     Some(Ordering::Greater)
373    /// );
374    /// # Ok(())
375    /// # }
376    /// ```
377    pub fn left_partial_cmp(&self, other: &Interval<T>) -> Option<Ordering> {
378        let self_left_bound = self.left_bound();
379        let other_left_bound = other.left_bound();
380
381        match (self_left_bound, other_left_bound) {
382            (Bound::None, _) => None,
383            (_, Bound::None) => None,
384            // Handle all cases in which one left bound is Unbounded
385            (Bound::Unbounded, Bound::Unbounded) => Some(Ordering::Equal),
386            (Bound::Unbounded, _) => Some(Ordering::Less),
387            (_, Bound::Unbounded) => Some(Ordering::Greater),
388            // The cases where left bound of self is Closed and Bounded
389            (Bound::Closed(self_val), Bound::Closed(other_val)) => {
390                if self_val < other_val {
391                    Some(Ordering::Less)
392                } else if self_val > other_val {
393                    Some(Ordering::Greater)
394                } else {
395                    Some(Ordering::Equal)
396                }
397            }
398            (Bound::Closed(self_val), Bound::Open(other_val)) => {
399                if self_val <= other_val {
400                    Some(Ordering::Less)
401                } else {
402                    Some(Ordering::Greater)
403                }
404            }
405            // The cases where left bound of self is Open and Bounded
406            (Bound::Open(self_val), Bound::Closed(other_val)) => {
407                if self_val < other_val {
408                    Some(Ordering::Less)
409                } else {
410                    Some(Ordering::Greater)
411                }
412            }
413            (Bound::Open(self_val), Bound::Open(other_val)) => {
414                if self_val < other_val {
415                    Some(Ordering::Less)
416                } else if self_val > other_val {
417                    Some(Ordering::Greater)
418                } else {
419                    Some(Ordering::Equal)
420                }
421            }
422        }
423    }
424
425    /// The PartialOrd::partial_cmp implementation for right Bounds
426    ///
427    /// Though Intervals on some generics (e.g. integers) can supply [Ord](https://doc.rust-lang.org/std/cmp/trait.Ord.html) because they form a [total order](https://en.wikipedia.org/wiki/Total_order),
428    /// unfortunately our floating point implementations break such properties.
429    /// Therefore the best we can do under some generics is satisfy [PartialOrd](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html).
430    ///
431    /// # Examples
432    ///
433    /// ```
434    /// use intervals_general::bound_pair::BoundPair;
435    /// use intervals_general::interval::Interval;
436    /// use std::cmp::Ordering;
437    ///
438    /// # fn main() -> std::result::Result<(), String> {
439    /// let right_half_open = Interval::RightHalfOpen {
440    ///     bound_pair: BoundPair::new(1.0, 5.0).ok_or("invalid BoundPair")?,
441    /// };
442    /// let contained_interval = Interval::Open {
443    ///     bound_pair: BoundPair::new(1.0, 2.0).ok_or("invalid BoundPair")?,
444    /// };
445    ///
446    /// assert_eq!(
447    ///     contained_interval.right_partial_cmp(&right_half_open),
448    ///     Some(Ordering::Less)
449    /// );
450    /// # Ok(())
451    /// # }
452    /// ```
453    pub fn right_partial_cmp(&self, other: &Interval<T>) -> Option<Ordering> {
454        let self_right_bound = self.right_bound();
455        let other_right_bound = other.right_bound();
456
457        match (self_right_bound, other_right_bound) {
458            (Bound::None, _) => None,
459            (_, Bound::None) => None,
460            // Handle all cases in which one right bound is Unbounded
461            (Bound::Unbounded, Bound::Unbounded) => Some(Ordering::Equal),
462            (Bound::Unbounded, _) => Some(Ordering::Greater),
463            (_, Bound::Unbounded) => Some(Ordering::Less),
464            // The cases where right bound of self is Closed and Bounded
465            (Bound::Closed(self_val), Bound::Closed(other_val)) => {
466                if self_val < other_val {
467                    Some(Ordering::Less)
468                } else if self_val > other_val {
469                    Some(Ordering::Greater)
470                } else {
471                    Some(Ordering::Equal)
472                }
473            }
474            (Bound::Closed(self_val), Bound::Open(other_val)) => {
475                if self_val < other_val {
476                    Some(Ordering::Less)
477                } else {
478                    Some(Ordering::Greater)
479                }
480            }
481            // The cases where right bound of self is Open and Bounded
482            (Bound::Open(self_val), Bound::Closed(other_val)) => {
483                if self_val <= other_val {
484                    Some(Ordering::Less)
485                } else {
486                    Some(Ordering::Greater)
487                }
488            }
489            (Bound::Open(self_val), Bound::Open(other_val)) => {
490                if self_val < other_val {
491                    Some(Ordering::Less)
492                } else if self_val > other_val {
493                    Some(Ordering::Greater)
494                } else {
495                    Some(Ordering::Equal)
496                }
497            }
498        }
499    }
500
501    /// Compute the width of the interval
502    ///
503    /// Returns right - left bound, so long as finite, else None
504    /// TODO How to handle overflow detection? I do not have access to check_sub
505    /// due to generic? Presently for interval widths exceeding the Boundary
506    /// type representation, panic occurs in debug mode and wrapping occurs
507    /// in production mode.
508    ///
509    /// # Examples
510    ///
511    /// ```
512    /// use intervals_general::bound_pair::BoundPair;
513    /// use intervals_general::interval::Interval;
514    ///
515    /// # fn main() -> std::result::Result<(), String> {
516    /// let interval = Interval::RightHalfOpen {
517    ///     bound_pair: BoundPair::new(1, 5).ok_or("invalid BoundPair")?,
518    /// };
519    ///
520    /// let width: i32 = interval.width().ok_or("width was None")?;
521    /// assert_eq!(width, 4);
522    /// # Ok(())
523    /// # }
524    /// ```
525    pub fn width(&self) -> Option<<T as std::ops::Sub>::Output>
526    where
527        T: std::ops::Sub,
528    {
529        let self_left_bound = self.left_bound();
530        let self_right_bound = self.right_bound();
531
532        match (self_left_bound, self_right_bound) {
533            (Bound::None, _) => None,
534            (_, Bound::None) => None,
535            (Bound::Unbounded, _) => None,
536            (_, Bound::Unbounded) => None,
537            (Bound::Closed(left), Bound::Closed(right)) => Some(right - left),
538            (Bound::Closed(left), Bound::Open(right)) => Some(right - left),
539            (Bound::Open(left), Bound::Closed(right)) => Some(right - left),
540            (Bound::Open(left), Bound::Open(right)) => Some(right - left),
541        }
542    }
543
544    /// Take the complement of the Interval, return one or two Intervals
545    ///
546    /// The return value is iterable and contains exclusively one or two
547    /// Intervals, depending upon result.
548    ///
549    /// # Example
550    ///
551    /// ```
552    /// use intervals_general::bound_pair::BoundPair;
553    /// use intervals_general::interval::Interval;
554    ///
555    /// # fn main() -> std::result::Result<(), String> {
556    /// let mut result_it =
557    ///     Interval::Closed {
558    ///         bound_pair: BoundPair::new(1, 5).ok_or("invalid BoundPair")?,
559    ///     }
560    ///     .complement();
561    ///
562    /// assert_eq!(
563    ///     result_it.next(),
564    ///     Some(Interval::UnboundedOpenRight { right: 1 })
565    /// );
566    /// assert_eq!(
567    ///     result_it.next(),
568    ///     Some(Interval::UnboundedOpenLeft{ left: 5 })
569    /// );
570    /// assert_eq!(
571    ///     result_it.next(),
572    ///     None
573    /// );
574    /// # Ok(())
575    /// # }
576    /// ```
577    pub fn complement(&self) -> itertools::Either<OneIntervalIter<T>, TwoIntervalIter<T>> {
578        match self {
579            Interval::Closed { bound_pair } => {
580                let BoundPair { left, right } = *bound_pair;
581                Either::Right(
582                    std::iter::once(Interval::UnboundedOpenRight { right: left })
583                        .chain(std::iter::once(Interval::UnboundedOpenLeft { left: right })),
584                )
585            }
586            Interval::Open { bound_pair } => {
587                let BoundPair { left, right } = *bound_pair;
588                Either::Right(
589                    std::iter::once(Interval::UnboundedClosedRight { right: left }).chain(
590                        std::iter::once(Interval::UnboundedClosedLeft { left: right }),
591                    ),
592                )
593            }
594            Interval::LeftHalfOpen { bound_pair } => {
595                let BoundPair { left, right } = *bound_pair;
596                Either::Right(
597                    std::iter::once(Interval::UnboundedClosedRight { right: left })
598                        .chain(std::iter::once(Interval::UnboundedOpenLeft { left: right })),
599                )
600            }
601            Interval::RightHalfOpen { bound_pair } => {
602                let BoundPair { left, right } = *bound_pair;
603                Either::Right(
604                    std::iter::once(Interval::UnboundedOpenRight { right: left }).chain(
605                        std::iter::once(Interval::UnboundedClosedLeft { left: right }),
606                    ),
607                )
608            }
609            Interval::UnboundedClosedRight { right } => {
610                Either::Left(std::iter::once(Interval::UnboundedOpenLeft {
611                    left: *right,
612                }))
613            }
614            Interval::UnboundedOpenRight { right } => {
615                Either::Left(std::iter::once(Interval::UnboundedClosedLeft {
616                    left: *right,
617                }))
618            }
619            Interval::UnboundedClosedLeft { left } => {
620                Either::Left(std::iter::once(Interval::UnboundedOpenRight {
621                    right: *left,
622                }))
623            }
624            Interval::UnboundedOpenLeft { left } => {
625                Either::Left(std::iter::once(Interval::UnboundedClosedRight {
626                    right: *left,
627                }))
628            }
629            Interval::Singleton { at } => Either::Right(
630                std::iter::once(Interval::UnboundedOpenRight { right: *at })
631                    .chain(std::iter::once(Interval::UnboundedOpenLeft { left: *at })),
632            ),
633            Interval::Unbounded => Either::Left(std::iter::once(Interval::Empty)),
634            Interval::Empty => Either::Left(std::iter::once(Interval::Unbounded)),
635        }
636    }
637}
638
639/// Implement the Display trait for Intervals
640///
641/// Here I uses [Wirth Interval Notation](https://proofwiki.org/wiki/Mathematician:Niklaus_Emil_Wirth).
642///
643/// # Examples
644///
645/// ```
646/// use intervals_general::bound_pair::BoundPair;
647/// use intervals_general::interval::Interval;
648///
649/// # fn main() -> std::result::Result<(), String> {
650/// let bp = BoundPair::new(1, 5).ok_or("invalid BoundPair")?;
651///
652/// assert_eq!(format!("{}", Interval::Closed { bound_pair: bp }), "[1..5]");
653/// assert_eq!(
654///     format!("{}", Interval::UnboundedOpenRight { right: 5 }),
655///     "(←..5)"
656/// );
657/// # Ok(())
658/// # }
659/// ```
660impl<T> std::fmt::Display for Interval<T>
661where
662    T: std::fmt::Debug,
663{
664    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
665        match self {
666            Interval::Closed {
667                bound_pair:
668                    BoundPair {
669                        ref left,
670                        ref right,
671                    },
672            } => write!(f, "[{:?}..{:?}]", left, right),
673            Interval::Open {
674                bound_pair:
675                    BoundPair {
676                        ref left,
677                        ref right,
678                    },
679            } => write!(f, "({:?}..{:?})", left, right),
680            Interval::LeftHalfOpen {
681                bound_pair:
682                    BoundPair {
683                        ref left,
684                        ref right,
685                    },
686            } => write!(f, "({:?}..{:?}]", left, right),
687            Interval::RightHalfOpen {
688                bound_pair:
689                    BoundPair {
690                        ref left,
691                        ref right,
692                    },
693            } => write!(f, "[{:?}..{:?})", left, right),
694            Interval::UnboundedClosedRight { ref right } => write!(f, "(←..{:?}]", right),
695            Interval::UnboundedOpenRight { ref right } => write!(f, "(←..{:?})", right),
696            Interval::UnboundedClosedLeft { ref left } => write!(f, "[{:?}..→)", left),
697            Interval::UnboundedOpenLeft { ref left } => write!(f, "({:?}..→)", left),
698            Interval::Singleton { ref at } => write!(f, "[{:?}]", at),
699            Interval::Unbounded => write!(f, "(←..→)"),
700            Interval::Empty => write!(f, "Empty"),
701        }
702    }
703}
704
705#[cfg(test)]
706mod tests {
707    use crate::bound_pair::BoundPair;
708    use crate::interval::Interval;
709    use itertools::Either;
710    use quickcheck::Arbitrary;
711    use quickcheck::Gen;
712    use quickcheck::TestResult;
713    use quickcheck_macros::quickcheck;
714
715    impl<T> Arbitrary for Interval<T>
716    where
717        T: Arbitrary + Copy + Clone + PartialOrd + Send + 'static,
718    {
719        fn arbitrary(g: &mut Gen) -> Interval<T> {
720            const VARIANT_COUNT: usize = 12;
721            let variant_idx = g.size() % VARIANT_COUNT;
722
723            match variant_idx {
724                0 => {
725                    let bound_pair = loop {
726                        let left = T::arbitrary(g);
727                        let right = T::arbitrary(g);
728                        if let Some(bp) = BoundPair::new(left, right) {
729                            break bp;
730                        }
731                    };
732                    Interval::Closed { bound_pair }
733                }
734                1 => {
735                    let bound_pair = loop {
736                        let left = T::arbitrary(g);
737                        let right = T::arbitrary(g);
738                        if let Some(bp) = BoundPair::new(left, right) {
739                            break bp;
740                        }
741                    };
742                    Interval::Open { bound_pair }
743                }
744                2 => {
745                    let bound_pair = loop {
746                        let left = T::arbitrary(g);
747                        let right = T::arbitrary(g);
748                        if let Some(bp) = BoundPair::new(left, right) {
749                            break bp;
750                        }
751                    };
752                    Interval::LeftHalfOpen { bound_pair }
753                }
754                3 => {
755                    let bound_pair = loop {
756                        let left = T::arbitrary(g);
757                        let right = T::arbitrary(g);
758                        if let Some(bp) = BoundPair::new(left, right) {
759                            break bp;
760                        }
761                    };
762                    Interval::LeftHalfOpen { bound_pair }
763                }
764                4 => {
765                    let bound_pair = loop {
766                        let left = T::arbitrary(g);
767                        let right = T::arbitrary(g);
768                        if let Some(bp) = BoundPair::new(left, right) {
769                            break bp;
770                        }
771                    };
772                    Interval::RightHalfOpen { bound_pair }
773                }
774                5 => Interval::UnboundedClosedRight {
775                    right: T::arbitrary(g),
776                },
777                6 => Interval::UnboundedOpenRight {
778                    right: T::arbitrary(g),
779                },
780                7 => Interval::UnboundedClosedLeft {
781                    left: T::arbitrary(g),
782                },
783                8 => Interval::UnboundedOpenLeft {
784                    left: T::arbitrary(g),
785                },
786                9 => Interval::Singleton {
787                    at: T::arbitrary(g),
788                },
789                10 => Interval::Unbounded,
790                11 => Interval::Empty,
791                _ => unreachable!("variant_idx is always < VARIANT_COUNT"),
792            }
793        }
794
795        // fn shrink(&self) -> Box<Iterator<Item = Self>> {
796        //     match self {
797        //         // &Interval::Unbounded => Box::new(Interval::Unbounded),
798        //         // &Qqq::Kokoko(ref x) => Box::new(x.shrink().map(|s| Qqq::Kokoko(s))),
799        //         _ => quickcheck::empty_shrinker(),
800        //     }
801        // }
802    }
803
804    #[test]
805    fn test_bounded_complements() {
806        let bp = BoundPair::new(1, 5).unwrap();
807        let mut it = Interval::Closed { bound_pair: bp }.complement();
808        assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 1 }));
809        assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 5 }));
810        assert_eq!(it.next(), None);
811
812        it = Interval::Open { bound_pair: bp }.complement();
813        assert_eq!(it.next(), Some(Interval::UnboundedClosedRight { right: 1 }));
814        assert_eq!(it.next(), Some(Interval::UnboundedClosedLeft { left: 5 }));
815        assert_eq!(it.next(), None);
816
817        it = Interval::LeftHalfOpen { bound_pair: bp }.complement();
818        assert_eq!(it.next(), Some(Interval::UnboundedClosedRight { right: 1 }));
819        assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 5 }));
820        assert_eq!(it.next(), None);
821
822        it = Interval::RightHalfOpen { bound_pair: bp }.complement();
823        assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 1 }));
824        assert_eq!(it.next(), Some(Interval::UnboundedClosedLeft { left: 5 }));
825        assert_eq!(it.next(), None);
826    }
827
828    #[test]
829    fn test_unbounded_complements() {
830        let mut it = Interval::UnboundedClosedRight { right: 5 }.complement();
831        assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 5 }));
832        assert_eq!(it.next(), None);
833
834        it = Interval::UnboundedOpenRight { right: 5 }.complement();
835        assert_eq!(it.next(), Some(Interval::UnboundedClosedLeft { left: 5 }));
836        assert_eq!(it.next(), None);
837
838        it = Interval::UnboundedClosedLeft { left: 1 }.complement();
839        assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 1 }));
840        assert_eq!(it.next(), None);
841
842        it = Interval::UnboundedOpenLeft { left: 1 }.complement();
843        assert_eq!(it.next(), Some(Interval::UnboundedClosedRight { right: 1 }));
844        assert_eq!(it.next(), None);
845
846        let mut it = Interval::Singleton { at: 2.0 }.complement();
847        assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 2.0 }));
848        assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 2.0 }));
849        assert_eq!(it.next(), None);
850
851        it = Interval::Unbounded.complement();
852        assert_eq!(it.next(), Some(Interval::Empty));
853        assert_eq!(it.next(), None);
854
855        it = Interval::Empty.complement();
856        assert_eq!(it.next(), Some(Interval::Unbounded));
857        assert_eq!(it.next(), None);
858    }
859
860    #[test]
861    fn interval_display() {
862        let bp = BoundPair::new(1, 5).ok_or("invalid BoundPair").unwrap();
863
864        assert_eq!(format!("{}", Interval::Closed { bound_pair: bp }), "[1..5]");
865        assert_eq!(format!("{}", Interval::Open { bound_pair: bp }), "(1..5)");
866        assert_eq!(
867            format!("{}", Interval::LeftHalfOpen { bound_pair: bp }),
868            "(1..5]"
869        );
870        assert_eq!(
871            format!("{}", Interval::RightHalfOpen { bound_pair: bp }),
872            "[1..5)"
873        );
874        assert_eq!(
875            format!("{}", Interval::UnboundedClosedRight { right: 5 }),
876            "(←..5]"
877        );
878        assert_eq!(
879            format!("{}", Interval::UnboundedOpenRight { right: 5 }),
880            "(←..5)"
881        );
882        assert_eq!(
883            format!("{}", Interval::UnboundedClosedLeft { left: 1 }),
884            "[1..→)"
885        );
886        assert_eq!(
887            format!("{}", Interval::UnboundedOpenLeft { left: 1 }),
888            "(1..→)"
889        );
890        assert_eq!(format!("{}", Interval::Singleton { at: 3.0 }), "[3.0]");
891        assert_eq!(format!("{}", Interval::Unbounded::<u32> {}), "(←..→)");
892        assert_eq!(format!("{}", Interval::Empty::<u32> {}), "Empty");
893    }
894
895    #[quickcheck]
896    fn intersect_strictly_shrinks_u32(l1: u32, l2: u32, r1: u32, r2: u32) -> TestResult {
897        if let (Some(bp1), Some(bp2)) = (BoundPair::new(l1, r1), BoundPair::new(l2, r2)) {
898            let i1 = Interval::LeftHalfOpen { bound_pair: bp1 };
899            let i2 = Interval::LeftHalfOpen { bound_pair: bp2 };
900            let intersection = i1.intersect(&i2);
901            TestResult::from_bool(
902                !(intersection.width() > i1.width() || intersection.width() > i2.width()),
903            )
904        } else {
905            // Discard invalid randomly generated intervals
906            TestResult::discard()
907        }
908    }
909
910    #[quickcheck]
911    fn intersect_strictly_shrinks_f32(l1: f32, l2: f32, r1: f32, r2: f32) -> TestResult {
912        if let (Some(bp1), Some(bp2)) = (BoundPair::new(l1, r1), BoundPair::new(l2, r2)) {
913            let i1 = Interval::LeftHalfOpen { bound_pair: bp1 };
914            let i2 = Interval::LeftHalfOpen { bound_pair: bp2 };
915            let intersection = i1.intersect(&i2);
916            TestResult::from_bool(
917                !(intersection.width() > i1.width() || intersection.width() > i2.width()),
918            )
919        } else {
920            // Discard invalid randomly generated intervals
921            TestResult::discard()
922        }
923    }
924
925    #[quickcheck]
926    fn complement_symmetric_u32(i: Interval<u32>) -> TestResult {
927        let double_complement = match i.complement() {
928            Either::Left(mut interval) => interval.next().unwrap().complement().next().unwrap(),
929            Either::Right(mut intervals) => {
930                let [i1, i2] = [intervals.next().unwrap(), intervals.next().unwrap()];
931                i1.complement()
932                    .next()
933                    .unwrap()
934                    .intersect(&i2.complement().next().unwrap())
935            }
936        };
937
938        TestResult::from_bool(double_complement == i)
939    }
940}