Skip to main content

physdes/
interval.rs

1use crate::generic::{Contain, Displacement, MinDist, Overlap};
2
3use std::cmp::{Eq, PartialEq, PartialOrd};
4use std::fmt::{Display, Formatter, Result as FmtResult};
5use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
6
7/// A range of values with a lower bound (`lb`) and an upper bound (`ub`).
8///
9/// ```svgbob
10///  lb        ub
11///   |---------|
12///   *=========*-----> T
13/// ```
14///
15/// An interval is valid when `lb <= ub`. The `is_invalid()` method checks for the
16/// invalid case `lb > ub`.
17///
18/// # Examples
19///
20/// ```
21/// use physdes::interval::Interval;
22///
23/// let interval = Interval::new(1, 5);
24/// assert_eq!(interval.lb, 1);
25/// assert_eq!(interval.ub, 5);
26/// ```
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
29pub struct Interval<T> {
30    pub lb: T,
31    pub ub: T,
32}
33
34impl<T> Interval<T> {
35    /// Creates a new interval with the given lower and upper bounds.
36    ///
37    /// Note: No validity check is performed. An interval where `lb > ub` is considered
38    /// invalid and can be checked with `is_invalid()`.
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use physdes::interval::Interval;
44    ///
45    /// let interval = Interval::new(1, 5);
46    /// assert_eq!(interval.lb, 1);
47    /// assert_eq!(interval.ub, 5);
48    ///
49    /// let interval = Interval::new(5, 1);  // Invalid interval but still created
50    /// assert_eq!(interval.lb, 5);
51    /// assert_eq!(interval.ub, 1);
52    /// ```
53    #[inline]
54    pub const fn new(lb: T, ub: T) -> Self {
55        Self { lb, ub }
56    }
57}
58
59impl<T: Copy> Interval<T> {
60    /// Returns the lower bound.
61    #[inline]
62    pub const fn lb(&self) -> T {
63        self.lb
64    }
65
66    /// Returns the upper bound.
67    #[inline]
68    pub const fn ub(&self) -> T {
69        self.ub
70    }
71}
72
73impl<T: PartialOrd> Interval<T> {
74    /// Returns `true` if the lower bound exceeds the upper bound (invalid interval).
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// use physdes::interval::Interval;
80    ///
81    /// let valid_interval = Interval::new(1, 5);
82    /// assert!(!valid_interval.is_invalid());
83    ///
84    /// let invalid_interval = Interval::new(5, 1);
85    /// assert!(invalid_interval.is_invalid());
86    /// ```
87    #[inline]
88    pub fn is_invalid(&self) -> bool {
89        self.lb > self.ub
90    }
91}
92
93impl<T: Copy + Sub<Output = T>> Interval<T> {
94    /// Computes the length of the interval: `ub - lb`.
95    ///
96    /// $$L = ub - lb$$
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use physdes::interval::Interval;
102    ///
103    /// let interval = Interval::new(2, 8);
104    /// assert_eq!(interval.length(), 6);
105    ///
106    /// let interval = Interval::new(-3, 5);
107    /// assert_eq!(interval.length(), 8);
108    /// ```
109    #[inline]
110    pub fn length(&self) -> T {
111        self.ub - self.lb
112    }
113}
114
115impl<T> Display for Interval<T>
116where
117    T: PartialOrd + Copy + Display,
118{
119    /// Formats the interval as `[lb, ub]`.
120    #[inline]
121    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
122        write!(f, "[{}, {}]", self.lb, self.ub)
123    }
124}
125
126/// Interval subtraction (component-wise): $\[a,b\] - \[c,d\] = \[a-c,\; b-d\]$
127impl<T: Sub<Output = T>> Sub for Interval<T> {
128    type Output = Self;
129
130    fn sub(self, other: Self) -> Self::Output {
131        Self {
132            lb: self.lb - other.lb,
133            ub: self.ub - other.ub,
134        }
135    }
136}
137
138/// Interval negation: $-\[a,b\] = \[-b,\; -a\]$
139impl<T> Neg for Interval<T>
140where
141    T: Copy + Neg<Output = T>,
142{
143    type Output = Interval<T>;
144
145    #[inline]
146    fn neg(self) -> Self::Output {
147        Interval {
148            lb: -self.ub,
149            ub: -self.lb,
150        }
151    }
152}
153
154impl<T> AddAssign<T> for Interval<T>
155where
156    T: Copy + AddAssign<T>,
157{
158    /// Shift the interval by a scalar: $\[a,b\] \mathrel{+}= t \implies \[a+t,\; b+t\]$
159    #[inline]
160    fn add_assign(&mut self, rhs: T) {
161        self.lb += rhs;
162        self.ub += rhs;
163    }
164}
165
166impl<T> Add<T> for Interval<T>
167where
168    T: Copy + Add<Output = T>,
169{
170    type Output = Interval<T>;
171
172    /// Shift the interval by a scalar: $\[a,b\] + t = \[a+t,\; b+t\]$
173    #[inline]
174    fn add(self, rhs: T) -> Self::Output {
175        Interval {
176            lb: self.lb + rhs,
177            ub: self.ub + rhs,
178        }
179    }
180}
181
182impl<T> SubAssign<T> for Interval<T>
183where
184    T: Copy + SubAssign<T>,
185{
186    /// Shift the interval by a negative scalar: $\[a,b\] \mathrel{-}= t \implies \[a-t,\; b-t\]$
187    #[inline]
188    fn sub_assign(&mut self, rhs: T) {
189        self.lb -= rhs;
190        self.ub -= rhs;
191    }
192}
193
194/// Interval addition (component-wise): $\[a,b\] + \[c,d\] = \[a+c,\; b+d\]$
195impl<T: Add<Output = T>> Add for Interval<T> {
196    type Output = Self;
197
198    fn add(self, other: Self) -> Self::Output {
199        Self {
200            lb: self.lb + other.lb,
201            ub: self.ub + other.ub,
202        }
203    }
204}
205
206impl<T> Sub<T> for Interval<T>
207where
208    T: Copy + Sub<Output = T>,
209{
210    type Output = Interval<T>;
211
212    /// Shift the interval by a negative scalar: $\[a,b\] - t = \[a-t,\; b-t\]$
213    #[inline]
214    fn sub(self, rhs: T) -> Self::Output {
215        Interval {
216            lb: self.lb - rhs,
217            ub: self.ub - rhs,
218        }
219    }
220}
221
222impl<T> MulAssign<T> for Interval<T>
223where
224    T: Copy + MulAssign<T>,
225{
226    /// Scale the interval by a scalar: $\[a,b\] \mathrel{*}= t \implies \[a \cdot t,\; b \cdot t\]$
227    #[inline]
228    fn mul_assign(&mut self, rhs: T) {
229        self.lb *= rhs;
230        self.ub *= rhs;
231    }
232}
233
234impl<T> Mul<T> for Interval<T>
235where
236    T: Copy + Mul<Output = T>,
237{
238    type Output = Interval<T>;
239
240    /// Scale the interval by a scalar: $\[a,b\] \cdot t = \[a \cdot t,\; b \cdot t\]$
241    #[inline]
242    fn mul(self, rhs: T) -> Self::Output {
243        Interval {
244            lb: self.lb * rhs,
245            ub: self.ub * rhs,
246        }
247    }
248}
249
250/// Trait for enlarging a value by a given margin.
251pub trait Enlarge<Alpha> {
252    type Output;
253
254    fn enlarge_with(&self, alpha: Alpha) -> Self::Output;
255}
256
257impl Enlarge<i32> for i32 {
258    type Output = Interval<i32>;
259
260    /// Enlarges a scalar to an interval: $\text{enlarge}(x, \alpha) = \[x-\alpha,\; x+\alpha\]$
261    #[inline]
262    fn enlarge_with(&self, alpha: i32) -> Interval<i32> {
263        Interval {
264            lb: *self - alpha,
265            ub: *self + alpha,
266        }
267    }
268}
269
270impl<T> Enlarge<T> for Interval<T>
271where
272    T: Copy + Add<Output = T> + Sub<Output = T>,
273{
274    type Output = Interval<T>;
275
276    /// Enlarges the interval by `alpha` on both sides: $\text{enlarge}(\[a,b\], \alpha) = \[a-\alpha,\; b+\alpha\]$
277    #[inline]
278    fn enlarge_with(&self, alpha: T) -> Self {
279        Interval {
280            lb: self.lb - alpha,
281            ub: self.ub + alpha,
282        }
283    }
284}
285
286impl<T: PartialOrd> PartialOrd for Interval<T> {
287    /// Orders intervals by their position: Less if `ub < other.lb`, Greater if `other.ub < self.lb`, Equal otherwise.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// use physdes::interval::Interval;
293    /// use std::marker::PhantomData;
294    /// assert_eq!(Interval::new(1, 2).partial_cmp(&Interval::new(3, 4)), Some(std::cmp::Ordering::Less));
295    /// ```
296    #[inline]
297    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
298        if self.ub < other.lb {
299            Some(std::cmp::Ordering::Less)
300        } else if other.ub < self.lb {
301            Some(std::cmp::Ordering::Greater)
302        } else {
303            Some(std::cmp::Ordering::Equal)
304        }
305    }
306}
307
308impl<T: PartialOrd> Overlap<Interval<T>> for Interval<T> {
309    /// Checks if two intervals overlap: $\[a,b\] \cap \[c,d\] \neq \varnothing \iff a \le d \land c \le b$
310    #[inline]
311    fn overlaps(&self, other: &Interval<T>) -> bool {
312        self.ub >= other.lb && other.ub >= self.lb
313    }
314}
315
316impl<T: PartialOrd> Overlap<T> for Interval<T> {
317    /// Checks if the interval contains a scalar value: $x \in \[a,b\] \iff a \le x \le b$
318    #[inline]
319    fn overlaps(&self, other: &T) -> bool {
320        self.ub >= *other && *other >= self.lb
321    }
322}
323
324impl<T: PartialOrd> Overlap<Interval<T>> for T {
325    /// Checks if this value falls within the given interval.
326    #[inline]
327    fn overlaps(&self, other: &Interval<T>) -> bool {
328        *self >= other.lb && other.ub >= *self
329    }
330}
331
332impl<T: PartialOrd> Contain<Interval<T>> for Interval<T> {
333    /// Checks if `self` entirely contains `other`: $\[a,b\] \supseteq \[c,d\] \iff a \le c \land d \le b$
334    #[inline]
335    fn contains(&self, other: &Interval<T>) -> bool {
336        self.lb <= other.lb && other.ub <= self.ub
337    }
338}
339
340impl<T: PartialOrd> Contain<T> for Interval<T> {
341    /// Checks if the interval contains a scalar value: $x \in \[a,b\] \iff a \le x \le b$
342    #[inline]
343    fn contains(&self, other: &T) -> bool {
344        self.lb <= *other && *other <= self.ub
345    }
346}
347
348impl<T: PartialOrd> Contain<Interval<T>> for T {
349    /// The function `contains` always returns `false` and takes a reference to another `Interval` as
350    /// input.
351    ///
352    /// Arguments:
353    ///
354    /// * `_other`: The `_other` parameter is a reference to an `Interval` object of the same type `T`
355    ///   as the current object.
356    ///
357    /// Returns:
358    ///
359    /// The `contains` function is returning a boolean value `false`.
360    #[inline]
361    fn contains(&self, _other: &Interval<T>) -> bool {
362        false
363    }
364}
365
366impl<T> Displacement<Interval<T>> for Interval<T>
367where
368    T: Displacement<T, Output = T>,
369{
370    type Output = Interval<T>;
371
372    /// Computes the component-wise displacement between two intervals.
373    #[inline]
374    fn displace(&self, other: &Interval<T>) -> Self::Output {
375        Self::Output::new(self.lb.displace(&other.lb), self.ub.displace(&other.ub))
376    }
377}
378
379impl MinDist<Interval<i32>> for Interval<i32> {
380    /// Computes the minimum distance between two intervals:
381    ///
382    /// $$d = \begin{cases} c-b & \text{if } b < c \\ a-d & \text{if } d < a \\ 0 & \text{otherwise} \end{cases}$$
383    #[inline]
384    fn min_dist_with(&self, other: &Interval<i32>) -> u32 {
385        if self.ub < other.lb {
386            (other.lb - self.ub) as u32
387        } else if other.ub < self.lb {
388            (self.lb - other.ub) as u32
389        } else {
390            0
391        }
392    }
393}
394
395impl MinDist<i32> for Interval<i32> {
396    /// Computes the minimum distance between an interval and a scalar value.
397    #[inline]
398    fn min_dist_with(&self, other: &i32) -> u32 {
399        if self.ub < *other {
400            (*other - self.ub) as u32
401        } else if *other < self.lb {
402            (self.lb - *other) as u32
403        } else {
404            0
405        }
406    }
407}
408
409impl MinDist<Interval<i32>> for i32 {
410    /// Computes the minimum distance between a scalar and an interval.
411    #[inline]
412    fn min_dist_with(&self, other: &Interval<i32>) -> u32 {
413        if *self < other.lb {
414            (other.lb - *self) as u32
415        } else if other.ub < *self {
416            (*self - other.ub) as u32
417        } else {
418            0
419        }
420    }
421}
422
423/// Trait for computing the convex hull (bounding interval) of two values.
424pub trait Hull<T: ?Sized> {
425    type Output;
426
427    fn hull_with(&self, other: &T) -> Self::Output;
428}
429
430impl Hull<i32> for i32 {
431    type Output = Interval<i32>;
432
433    /// Computes the hull of two scalars: $\text{hull}(a,b) = \[\\min(a,b),\; \\max(a,b)\]$
434    #[inline]
435    fn hull_with(&self, other: &i32) -> Self::Output {
436        if *self < *other {
437            Interval::new(*self, *other)
438        } else {
439            Interval::new(*other, *self)
440        }
441    }
442}
443
444impl<T> Hull<Interval<T>> for Interval<T>
445where
446    T: Copy + Ord,
447{
448    type Output = Interval<T>;
449
450    /// Computes the hull (bounding interval) of two intervals:
451    ///
452    /// $$\text{hull}(\[a,b\],\[c,d\]) = \[\\min(a,c),\; \\max(b,d)\]$$
453    #[inline]
454    fn hull_with(&self, other: &Interval<T>) -> Self::Output {
455        Self::Output {
456            lb: self.lb.min(other.lb),
457            ub: self.ub.max(other.ub),
458        }
459    }
460}
461
462impl<T> Hull<T> for Interval<T>
463where
464    T: Copy + Ord,
465{
466    type Output = Interval<T>;
467
468    /// The `hull_with` function calculates the hull (minimum and maximum values) between two values.
469    ///
470    /// Arguments:
471    ///
472    /// * `other`: The `other` parameter is a reference to a value of type `T`, which is the same type
473    ///   as the values stored in the struct implementing the `hull_with` method. In this method, the
474    ///   `other` value is used to update the lower bound (`lb`) and upper bound (`
475    #[inline]
476    fn hull_with(&self, other: &T) -> Self::Output {
477        Self::Output {
478            lb: self.lb.min(*other),
479            ub: self.ub.max(*other),
480        }
481    }
482}
483
484impl<T> Hull<Interval<T>> for T
485where
486    T: Copy + Ord,
487{
488    type Output = Interval<T>;
489
490    /// Computes the hull of a scalar value with an interval (delegates to `Interval::hull_with`).
491    #[inline]
492    fn hull_with(&self, other: &Interval<T>) -> Self::Output {
493        other.hull_with(self)
494    }
495}
496
497/// Trait for computing the intersection of two values.
498pub trait Intersect<T: ?Sized> {
499    type Output;
500
501    fn intersect_with(&self, other: &T) -> Self::Output;
502}
503
504impl Intersect<i32> for i32 {
505    type Output = Interval<i32>;
506
507    /// Computes the intersection of two scalars: $\text{intersect}(a,b) = \[\\max(a,b),\; \\min(a,b)\]$
508    #[inline]
509    fn intersect_with(&self, other: &i32) -> Self::Output {
510        Self::Output {
511            lb: (*self).max(*other),
512            ub: (*self).min(*other),
513        }
514    }
515}
516
517impl<T> Intersect<Interval<T>> for Interval<T>
518where
519    T: Copy + Ord,
520{
521    type Output = Interval<T>;
522
523    /// Computes the intersection of two intervals:
524    ///
525    /// $$\text{intersect}(\[a,b\],\[c,d\]) = \[\\max(a,c),\; \\min(b,d)\]$$
526    #[inline]
527    fn intersect_with(&self, other: &Interval<T>) -> Self::Output {
528        Self::Output {
529            lb: self.lb.max(other.lb),
530            ub: self.ub.min(other.ub),
531        }
532    }
533}
534
535impl<T> Intersect<T> for Interval<T>
536where
537    T: Copy + Ord,
538{
539    type Output = Interval<T>;
540
541    /// Computes the intersection of an interval and a scalar value.
542    #[inline]
543    fn intersect_with(&self, other: &T) -> Self::Output {
544        Self::Output {
545            lb: self.lb.max(*other),
546            ub: self.ub.min(*other),
547        }
548    }
549}
550
551impl<T> Intersect<Interval<T>> for T
552where
553    T: Copy + Ord,
554{
555    type Output = Interval<T>;
556
557    /// Computes the intersection of a scalar value with an interval.
558    #[inline]
559    fn intersect_with(&self, other: &Interval<T>) -> Self::Output {
560        other.intersect_with(self)
561    }
562}
563
564#[cfg(test)]
565mod tests {
566    use super::*;
567
568    #[test]
569    fn test_interval() {
570        let interval_a = Interval::new(4, 8);
571        let interval_b = Interval::new(5, 6);
572
573        assert!(interval_a <= interval_b);
574        assert!(interval_b <= interval_a);
575        assert!(interval_a >= interval_b);
576        assert!(interval_b >= interval_a);
577
578        assert!(interval_a.overlaps(&interval_b));
579        assert!(interval_b.overlaps(&interval_a));
580        // assert!(!contain(&interval_a, &interval_b));
581        assert!(interval_a.contains(&4));
582        assert!(interval_a.contains(&8));
583        assert!(interval_a.contains(&interval_b));
584        assert_eq!(interval_a, interval_a);
585        assert_eq!(interval_b, interval_b);
586        assert_ne!(interval_a, interval_b);
587        assert_ne!(interval_b, interval_a);
588        assert!(interval_a.overlaps(&interval_a));
589        assert!(interval_b.overlaps(&interval_b));
590        assert!(interval_a.contains(&interval_a));
591        assert!(interval_b.contains(&interval_b));
592        assert!(interval_a.overlaps(&interval_b));
593        assert!(interval_b.overlaps(&interval_a));
594    }
595
596    #[test]
597    fn test_hull_more_cases() {
598        let interval_a = Interval::new(3, 5);
599        let interval_b = Interval::new(1, 7);
600        assert_eq!(interval_a.hull_with(&interval_b), Interval::new(1, 7));
601
602        let interval_c = Interval::new(-2, 2);
603        assert_eq!(interval_a.hull_with(&interval_c), Interval::new(-2, 5));
604
605        let val_d = 4;
606        assert_eq!(interval_a.hull_with(&val_d), Interval::new(3, 5));
607
608        let val_e = 8;
609        assert_eq!(interval_a.hull_with(&val_e), Interval::new(3, 8));
610
611        let val_f = 0;
612        assert_eq!(interval_a.hull_with(&val_f), Interval::new(0, 5));
613    }
614
615    #[test]
616    fn test_interval1() {
617        let interval_a = Interval::new(4, 5);
618        let interval_b = Interval::new(6, 8);
619        assert!(interval_a < interval_b);
620        assert!(!(interval_b == interval_a));
621        assert!(interval_b != interval_a);
622    }
623
624    #[test]
625    fn test_interval2() {
626        let interval_a = Interval::new(4, 8);
627        let interval_b = Interval::new(5, 6);
628
629        assert!(interval_a.contains(&4));
630        assert!(interval_a.contains(&8));
631        assert!(interval_a.contains(&interval_b));
632        // assert!(interval_a.intersect_with(&8) == Interval::new(8, 8));
633        // assert!(interval_a.intersect_with(interval_b) == interval_b);
634        assert!(!interval_b.contains(&interval_a));
635        assert!(interval_a.overlaps(&interval_b));
636        assert!(interval_b.overlaps(&interval_a));
637    }
638
639    #[test]
640    fn test_interval3() {
641        let interval_a = Interval::new(3, 4);
642        assert!(interval_a.lb == 3);
643        assert!(interval_a.ub == 4);
644        // assert!(interval_a.length() == 1);
645        assert!(interval_a.contains(&3));
646        assert!(interval_a.contains(&4));
647        assert!(!interval_a.contains(&5));
648        assert!(interval_a.contains(&Interval::new(3, 4)));
649        assert!(!interval_a.contains(&Interval::new(3, 5)));
650        assert!(!interval_a.contains(&Interval::new(2, 3)));
651        assert!(!interval_a.contains(&2));
652        assert!(interval_a.contains(&4));
653        assert!(!interval_a.contains(&5));
654    }
655
656    #[test]
657    fn test_arithmetic() {
658        let mut interval_a = Interval::new(3, 5);
659        // interval_b = Interval::new(5, 7);
660        // interval_c = Interval::new(7, 8);
661        assert_eq!(interval_a + 1, Interval::new(4, 6));
662        assert_eq!(interval_a - 1, Interval::new(2, 4));
663        assert_eq!(interval_a * 2, Interval::new(6, 10));
664        assert!(-interval_a == Interval::new(-5, -3));
665        interval_a += 1;
666        assert!(interval_a == Interval::new(4, 6));
667        interval_a -= 1;
668        assert!(interval_a == Interval::new(3, 5));
669        interval_a *= 2;
670        assert!(interval_a == Interval::new(6, 10));
671    }
672
673    #[test]
674    fn test_overlap() {
675        let interval_a = Interval::new(3, 5);
676        let interval_b = Interval::new(5, 7);
677        let interval_c = Interval::new(7, 8);
678        assert!(interval_a.overlaps(&interval_b));
679        assert!(interval_b.overlaps(&interval_c));
680        assert!(!interval_a.overlaps(&interval_c));
681        assert!(!interval_c.overlaps(&interval_a));
682
683        let val_d = 4;
684        assert!(interval_a.overlaps(&val_d));
685        assert!(!interval_a.overlaps(&6));
686        assert!(val_d.overlaps(&interval_a));
687        assert!(val_d.overlaps(&val_d));
688    }
689
690    #[test]
691    fn test_contains() {
692        let interval_a = Interval::new(3, 5);
693        let interval_b = Interval::new(5, 7);
694        let interval_c = Interval::new(7, 8);
695        assert!(!interval_a.contains(&interval_b));
696        assert!(!interval_b.contains(&interval_c));
697        assert!(!interval_a.contains(&interval_c));
698        assert!(!interval_c.contains(&interval_a));
699
700        let val_d = 4;
701        assert!(interval_a.contains(&val_d));
702        assert!(!interval_a.contains(&6));
703        assert!(!val_d.contains(&interval_a));
704        assert!(val_d.contains(&val_d));
705    }
706
707    #[test]
708    fn test_intersect() {
709        let interval_a = Interval::new(3, 5);
710        let interval_b = Interval::new(5, 7);
711        let interval_c = Interval::new(7, 8);
712        assert_eq!(interval_a.intersect_with(&interval_b), Interval::new(5, 5));
713        assert_eq!(interval_b.intersect_with(&interval_c), Interval::new(7, 7));
714        assert!(interval_a.intersect_with(&interval_c).is_invalid());
715        assert_eq!(interval_a.intersect_with(&interval_b), Interval::new(5, 5));
716        assert_eq!(interval_b.intersect_with(&interval_c), Interval::new(7, 7));
717        let val_d = 4;
718        assert_eq!(interval_a.intersect_with(&val_d), Interval::new(4, 4));
719        assert!(interval_a.intersect_with(&6).is_invalid());
720        assert_eq!(interval_a.intersect_with(&val_d), Interval::new(4, 4));
721        assert_eq!(val_d.intersect_with(&interval_a), Interval::new(4, 4));
722        assert_eq!(val_d.intersect_with(&val_d), Interval::new(4, 4));
723    }
724
725    #[test]
726    fn test_hull() {
727        let interval_a = Interval::new(3, 5);
728        let interval_b = Interval::new(5, 7);
729        let interval_c = Interval::new(7, 8);
730        assert_eq!(interval_a.hull_with(&interval_b), Interval::new(3, 7));
731        assert_eq!(interval_b.hull_with(&interval_c), Interval::new(5, 8));
732        assert_eq!(interval_a.hull_with(&interval_c), Interval::new(3, 8));
733        let val_d = 4;
734        assert_eq!(interval_a.hull_with(&val_d), Interval::new(3, 5));
735        assert_eq!(interval_a.hull_with(&6), Interval::new(3, 6));
736        // assert_eq!(hull(interval_a, val_d), Interval::new(3, 5));
737        // assert_eq!(hull(interval_a, 6), Interval::new(3, 6));
738        // assert_eq!(hull(val_d, interval_a), Interval::new(3, 5));
739        // assert!(hull(6, interval_a) == Interval::new(3, 6));
740        // assert!(hull(val_d, 6) == Interval::new(4, 6));
741    }
742
743    #[test]
744    fn test_min_dist() {
745        let interval_a = Interval::new(3, 5);
746        let interval_b = Interval::new(5, 7);
747        let interval_c = Interval::new(7, 8);
748        assert_eq!(interval_a.min_dist_with(&interval_b), 0);
749        assert_eq!(interval_a.min_dist_with(&interval_c), 2);
750        assert_eq!(interval_b.min_dist_with(&interval_c), 0);
751        let val_d = 4;
752        assert_eq!(interval_a.min_dist_with(&val_d), 0);
753        assert_eq!(val_d.min_dist_with(&interval_a), 0);
754        assert_eq!(interval_a.min_dist_with(&6), 1);
755        assert_eq!(6.min_dist_with(&interval_a), 1);
756    }
757
758    #[test]
759    fn test_displacement() {
760        let interval_a = Interval::new(3, 5);
761        let interval_b = Interval::new(5, 7);
762        let interval_c = Interval::new(7, 8);
763        assert_eq!(interval_a.displace(&interval_b), Interval::new(-2, -2));
764        assert_eq!(interval_a.displace(&interval_c), Interval::new(-4, -3));
765        assert_eq!(interval_b.displace(&interval_c), Interval::new(-2, -1));
766        let val_d = 4;
767        assert_eq!(val_d.displace(&val_d), 0);
768        assert_eq!(val_d.displace(&6), -2);
769        assert_eq!(6.displace(&val_d), 2);
770    }
771
772    #[test]
773    fn test_enlarge() {
774        let interval_a = Interval::new(3, 5);
775        assert!(interval_a.enlarge_with(2) == Interval::new(1, 7));
776        let val_d = 4;
777        assert_eq!(val_d.enlarge_with(6), Interval::new(-2, 10));
778        assert_eq!(6.enlarge_with(val_d), Interval::new(2, 10));
779    }
780
781    #[test]
782    fn test_min_dist_with_interval_other_ub_less_self_lb() {
783        use crate::generic::MinDist;
784        let a = Interval::new(10, 20);
785        let b = Interval::new(0, 5);
786        assert_eq!(a.min_dist_with(&b), 5);
787    }
788
789    #[test]
790    fn test_min_dist_with_scalar_other_less_self_lb() {
791        use crate::generic::MinDist;
792        let a = Interval::new(10, 20);
793        assert_eq!(a.min_dist_with(&5), 5);
794    }
795
796    #[test]
797    fn test_min_dist_with_scalar_self_less_interval_lb() {
798        let val = 3;
799        let other = Interval::new(10, 20);
800        assert_eq!(val.min_dist_with(&other), 7);
801    }
802}
803
804#[test]
805fn test_interval_length() {
806    let interval = Interval::new(3, 8);
807    assert_eq!(interval.length(), 5);
808
809    let interval2 = Interval::new(-2, 3);
810    assert_eq!(interval2.length(), 5);
811}
812
813#[test]
814fn test_interval_display() {
815    let interval = Interval::new(3, 8);
816    let display_str = format!("{}", interval);
817    assert_eq!(display_str, "[3, 8]");
818
819    let interval2 = Interval::new(-5, 10);
820    let display_str2 = format!("{}", interval2);
821    assert_eq!(display_str2, "[-5, 10]");
822}
823
824#[test]
825fn test_interval_sub_interval() {
826    let interval_a = Interval::new(5, 10);
827    let interval_b = Interval::new(2, 3);
828    let result = interval_a - interval_b;
829    assert_eq!(result, Interval::new(3, 7));
830}
831
832#[test]
833fn test_interval_add_interval() {
834    let interval_a = Interval::new(1, 3);
835    let interval_b = Interval::new(2, 5);
836    let result = interval_a + interval_b;
837    assert_eq!(result, Interval::new(3, 8));
838}
839
840#[test]
841fn test_interval_is_invalid() {
842    let valid_interval = Interval::new(1, 5);
843    assert!(!valid_interval.is_invalid());
844
845    let invalid_interval = Interval::new(5, 1);
846    assert!(invalid_interval.is_invalid());
847}
848
849#[test]
850fn test_interval_sub_assign_interval() {
851    let mut interval = Interval::new(10, 20);
852    interval -= 3;
853    assert_eq!(interval, Interval::new(7, 17));
854}
855
856#[test]
857fn test_interval_hull_t_for_t() {
858    let val = 5;
859    let interval = Interval::new(3, 8);
860    // T as Hull<Interval<T>>
861    let result = val.hull_with(&interval);
862    assert_eq!(result.lb, 3);
863    assert_eq!(result.ub, 8);
864}
865
866#[test]
867fn test_interval_contains_interval_t() {
868    let interval = Interval::new(3, 8);
869    // Contain<Interval<T>> for T - always returns false
870    let val = 5;
871    assert!(!val.contains(&interval));
872}
873
874#[test]
875fn test_interval_overlap_interval_t() {
876    // Overlap<Interval<T>> for T
877    let val = 5;
878    let interval = Interval::new(3, 8);
879    assert!(val.overlaps(&interval));
880
881    let val2 = 10;
882    assert!(!val2.overlaps(&interval));
883}
884
885#[test]
886fn test_interval_partial_cmp_greater() {
887    let interval_a = Interval::new(8, 10);
888    let interval_b = Interval::new(3, 5);
889    // interval_a is greater than interval_b (no overlap, ub > other.lb)
890    let cmp = interval_a.partial_cmp(&interval_b);
891    assert_eq!(cmp, Some(std::cmp::Ordering::Greater));
892}