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