1use num_traits::float::FloatCore;
9use num_traits::Num;
10use std::ops::RangeBounds;
11use std::ops::{Add, Div, Mul, Neg, Sub};
12use std::ops::{RangeFrom, RangeInclusive, RangeToInclusive};
13
14#[derive(Debug, PartialEq)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub enum Interval<T>
162where
163 T: PartialOrd,
164{
165 TwoSided(T, T), UpperOneSided(T), LowerOneSided(T), }
186
187impl<T: PartialOrd> Interval<T> {
188 pub fn new(low: T, high: T) -> Result<Self, IntervalError> {
207 if low > high {
208 Err(IntervalError::InvalidBounds)
209 } else {
210 Ok(Interval::TwoSided(low, high))
211 }
212 }
213
214 pub fn new_upper(low: T) -> Self {
231 Interval::UpperOneSided(low)
232 }
233
234 pub fn new_lower(high: T) -> Self {
251 Interval::LowerOneSided(high)
252 }
253
254 pub fn is_two_sided(&self) -> bool {
258 matches!(self, Interval::TwoSided(_, _))
259 }
260
261 pub fn is_one_sided(&self) -> bool {
265 !self.is_two_sided()
266 }
267
268 pub fn is_upper(&self) -> bool {
272 matches!(self, Interval::UpperOneSided(_))
273 }
274
275 pub fn is_lower(&self) -> bool {
279 matches!(self, Interval::LowerOneSided(_))
280 }
281
282 pub fn contains(&self, x: &T) -> bool {
296 match self {
297 Interval::TwoSided(low, high) => low <= x && x <= high,
298 Interval::UpperOneSided(low) => low <= x,
299 Interval::LowerOneSided(high) => x <= high,
300 }
301 }
302
303 pub fn intersects(&self, other: &Self) -> bool {
320 match (self, other) {
321 (Interval::UpperOneSided(_), Interval::UpperOneSided(_)) => true,
322 (Interval::LowerOneSided(_), Interval::LowerOneSided(_)) => true,
323 (Interval::UpperOneSided(x), Interval::LowerOneSided(y) | Interval::TwoSided(_, y)) => {
324 x <= y
325 }
326 (Interval::LowerOneSided(x), Interval::UpperOneSided(y) | Interval::TwoSided(_, y)) => {
327 x <= y
328 }
329 (Interval::TwoSided(x, y), Interval::UpperOneSided(z) | Interval::LowerOneSided(z)) => {
330 x <= z && z <= y
331 }
332 (Interval::TwoSided(x, y), Interval::TwoSided(a, b)) => x <= b && a <= y,
333 }
334 }
335
336 pub fn is_included_in(&self, other: &Self) -> bool {
342 other.includes(self)
343 }
344
345 pub fn includes(&self, other: &Self) -> bool {
351 match (self, other) {
352 (Interval::UpperOneSided(x), Interval::UpperOneSided(y)) => x <= y,
353 (Interval::LowerOneSided(x), Interval::LowerOneSided(y)) => x >= y,
354 (Interval::UpperOneSided(x), Interval::TwoSided(y, _)) => x <= y,
355 (Interval::LowerOneSided(x), Interval::TwoSided(_, y)) => x >= y,
356 (Interval::TwoSided(x, y), Interval::TwoSided(a, b)) => x <= a && b <= y,
357 (Interval::UpperOneSided(_), Interval::LowerOneSided(_))
358 | (Interval::LowerOneSided(_), Interval::UpperOneSided(_))
359 | (Interval::TwoSided(_, _), Interval::UpperOneSided(_))
360 | (Interval::TwoSided(_, _), Interval::LowerOneSided(_)) => false,
361 }
362 }
363
364 pub fn left(&self) -> Option<&T> {
368 match self {
369 Interval::UpperOneSided(x) | Interval::TwoSided(x, _) => Some(x),
370 Interval::LowerOneSided(_) => None,
371 }
372 }
373
374 pub fn right(&self) -> Option<&T> {
378 match self {
379 Interval::LowerOneSided(x) | Interval::TwoSided(_, x) => Some(x),
380 Interval::UpperOneSided(_) => None,
381 }
382 }
383}
384
385impl<T: PartialOrd + PartialEq> Interval<T> {
386 pub fn is_degenerate(&self) -> bool {
392 match self {
393 Interval::TwoSided(x, y) => x == y,
394 _ => false,
395 }
396 }
397}
398
399impl<T: PartialOrd + Clone> Interval<T> {
400 pub fn low(&self) -> Option<T> {
406 self.left().cloned()
407 }
408
409 pub fn high(&self) -> Option<T> {
415 self.right().cloned()
416 }
417}
418
419impl<T: num_traits::Float> Interval<T> {
420 pub fn low_f(&self) -> T {
425 match self {
426 Interval::TwoSided(low, _) => *low,
427 Interval::UpperOneSided(low) => *low,
428 Interval::LowerOneSided(_) => T::neg_infinity(),
429 }
430 }
431
432 pub fn high_f(&self) -> T {
437 match self {
438 Interval::TwoSided(_, high) => *high,
439 Interval::UpperOneSided(_) => T::infinity(),
440 Interval::LowerOneSided(high) => *high,
441 }
442 }
443
444 pub fn relative_to(&self, reference: &Interval<T>) -> Interval<T> {
451 match (reference, self) {
452 (Interval::TwoSided(a, b), _) if a.is_zero() || b.is_zero() => {
453 panic!("Cannot compute relative interval to a zero interval");
454 }
455 (Interval::LowerOneSided(a) | Interval::UpperOneSided(a), _) if a.is_zero() => {
456 panic!("Cannot compute relative interval to a zero interval");
457 }
458 (&Interval::TwoSided(a, b), &Interval::TwoSided(x, y)) => {
459 Interval::TwoSided((x - b) / b, (y - a) / a)
460 }
461 (
462 &Interval::UpperOneSided(a) | &Interval::TwoSided(a, _),
463 &Interval::LowerOneSided(y) | &Interval::TwoSided(_, y),
464 ) => Interval::LowerOneSided((y - a) / a),
465 (
466 &Interval::LowerOneSided(b) | &Interval::TwoSided(_, b),
467 &Interval::UpperOneSided(x) | &Interval::TwoSided(x, _),
468 ) => Interval::UpperOneSided((x - b) / b),
469 (&Interval::UpperOneSided(_), &Interval::UpperOneSided(_))
470 | (&Interval::LowerOneSided(_), &Interval::LowerOneSided(_)) => {
471 panic!(
472 "Cannot compute relative interval to one-sided interval with same direction"
473 );
474 }
475 }
476 }
477}
478
479impl<T: num_traits::PrimInt + num_traits::Signed> Interval<T> {
480 pub fn low_i(&self) -> T {
485 match self {
486 Interval::TwoSided(low, _) => *low,
487 Interval::UpperOneSided(low) => *low,
488 Interval::LowerOneSided(_) => <T>::min_value(),
489 }
490 }
491
492 pub fn high_i(&self) -> T {
497 match self {
498 Interval::TwoSided(_, high) => *high,
499 Interval::UpperOneSided(_) => <T>::max_value(),
500 Interval::LowerOneSided(high) => *high,
501 }
502 }
503}
504impl<T: num_traits::PrimInt + num_traits::Unsigned> Interval<T> {
505 pub fn low_u(&self) -> T {
510 match self {
511 Interval::TwoSided(low, _) => *low,
512 Interval::UpperOneSided(low) => *low,
513 Interval::LowerOneSided(_) => <T>::min_value(),
514 }
515 }
516
517 pub fn high_u(&self) -> T {
522 match self {
523 Interval::TwoSided(_, high) => *high,
524 Interval::UpperOneSided(_) => <T>::max_value(),
525 Interval::LowerOneSided(high) => *high,
526 }
527 }
528}
529
530impl<T: PartialOrd> Interval<T> {
531 pub fn low_as_ref(&self) -> Option<&T> {
537 self.left()
538 }
539
540 pub fn high_as_ref(&self) -> Option<&T> {
546 self.right()
547 }
548}
549impl<T: PartialOrd + Copy> Interval<T> {
550 fn applied<F>(&self, f_low: F, f_high: F) -> Self
551 where
552 F: FnOnce(T) -> T,
553 {
554 match self {
555 Interval::TwoSided(low, high) => Interval::TwoSided(f_low(*low), f_high(*high)),
556 Interval::LowerOneSided(low) => Interval::UpperOneSided(f_low(*low)),
557 Interval::UpperOneSided(high) => Interval::LowerOneSided(f_high(*high)),
558 }
559 }
560
561 fn applied_both<F>(&self, f: F) -> Self
562 where
563 F: Fn(T) -> T,
564 {
565 self.applied(&f, &f)
566 }
567}
568
569#[cfg(feature = "approx")]
570impl<T: approx::AbsDiffEq + PartialOrd> approx::AbsDiffEq for Interval<T>
571where
572 T::Epsilon: Copy,
573{
574 type Epsilon = T::Epsilon;
575
576 fn default_epsilon() -> T::Epsilon {
577 T::default_epsilon()
578 }
579
580 fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
581 match (self, other) {
582 (Interval::TwoSided(a, b), Interval::TwoSided(x, y)) => {
583 T::abs_diff_eq(a, x, epsilon) && T::abs_diff_eq(b, y, epsilon)
584 }
585 (Interval::UpperOneSided(a), Interval::UpperOneSided(x)) => {
586 T::abs_diff_eq(a, x, epsilon)
587 }
588 (Interval::LowerOneSided(b), Interval::LowerOneSided(y)) => {
589 T::abs_diff_eq(b, y, epsilon)
590 }
591 _ => false,
592 }
593 }
594}
595
596#[cfg(feature = "approx")]
597impl<T: approx::RelativeEq + PartialOrd> approx::RelativeEq for Interval<T>
598where
599 T::Epsilon: Copy,
600{
601 fn default_max_relative() -> T::Epsilon {
602 T::default_max_relative()
603 }
604
605 fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
606 match (self, other) {
607 (Interval::TwoSided(a, b), Interval::TwoSided(x, y)) => {
608 T::relative_eq(a, x, epsilon, max_relative)
609 && T::relative_eq(b, y, epsilon, max_relative)
610 }
611 (Interval::UpperOneSided(a), Interval::UpperOneSided(x)) => {
612 T::relative_eq(a, x, epsilon, max_relative)
613 }
614 (Interval::LowerOneSided(b), Interval::LowerOneSided(y)) => {
615 T::relative_eq(b, y, epsilon, max_relative)
616 }
617 _ => false,
618 }
619 }
620}
621
622#[cfg(feature = "approx")]
623impl<T: approx::UlpsEq + PartialOrd> approx::UlpsEq for Interval<T>
624where
625 T::Epsilon: Copy,
626{
627 fn default_max_ulps() -> u32 {
628 T::default_max_ulps()
629 }
630
631 fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
632 match (self, other) {
633 (Interval::TwoSided(a, b), Interval::TwoSided(x, y)) => {
634 T::ulps_eq(a, x, epsilon, max_ulps) && T::ulps_eq(b, y, epsilon, max_ulps)
635 }
636 (Interval::UpperOneSided(a), Interval::UpperOneSided(x)) => {
637 T::ulps_eq(a, x, epsilon, max_ulps)
638 }
639 (Interval::LowerOneSided(b), Interval::LowerOneSided(y)) => {
640 T::ulps_eq(b, y, epsilon, max_ulps)
641 }
642 _ => false,
643 }
644 }
645}
646
647impl<F: Mul<F, Output = F> + PartialOrd + Copy> Mul<F> for Interval<F> {
648 type Output = Self;
649
650 fn mul(self, rhs: F) -> Self::Output {
651 self.applied_both(|x| x * rhs)
652 }
653}
654
655impl<F: Div<F, Output = F> + PartialOrd + Copy> Div<F> for Interval<F> {
656 type Output = Self;
657
658 fn div(self, rhs: F) -> Self::Output {
659 self.applied_both(|x| x / rhs)
660 }
661}
662
663impl<F: Add<F, Output = F> + PartialOrd + Copy> Add<F> for Interval<F> {
664 type Output = Self;
665
666 fn add(self, rhs: F) -> Self::Output {
667 self.applied_both(|x| x + rhs)
668 }
669}
670
671impl<F: Sub<F, Output = F> + PartialOrd + Copy> Sub<F> for Interval<F> {
672 type Output = Self;
673
674 fn sub(self, rhs: F) -> Self::Output {
675 self.applied_both(|x| x - rhs)
676 }
677}
678
679impl<F: Neg<Output = F> + PartialOrd + Copy> Neg for Interval<F> {
680 type Output = Self;
681
682 fn neg(self) -> Self::Output {
683 self.applied_both(|x| -x)
684 }
685}
686
687impl<F: Num + PartialOrd + Copy> Add for Interval<F> {
688 type Output = Self;
689
690 fn add(self, rhs: Self) -> Self::Output {
691 match (self, rhs) {
692 (Interval::TwoSided(a, b), Interval::TwoSided(x, y)) => {
693 Interval::TwoSided(a + x, b + y)
694 }
695 (Interval::TwoSided(a, _) | Interval::UpperOneSided(a), Interval::UpperOneSided(x)) => {
696 Interval::UpperOneSided(a + x)
697 }
698 (Interval::TwoSided(_, b) | Interval::LowerOneSided(b), Interval::LowerOneSided(y)) => {
699 Interval::LowerOneSided(b + y)
700 }
701 (Interval::UpperOneSided(a), Interval::TwoSided(x, _)) => {
702 Interval::UpperOneSided(a + x)
703 }
704 (Interval::LowerOneSided(b), Interval::TwoSided(_, y)) => {
705 Interval::LowerOneSided(b + y)
706 }
707 (Interval::UpperOneSided(_), Interval::LowerOneSided(_))
708 | (Interval::LowerOneSided(_), Interval::UpperOneSided(_)) => {
709 panic!("Cannot add one-sided intervals with different directions (all values interval)")
710 }
711 }
712 }
713}
714
715impl<F: Num + PartialOrd + Copy> Sub for Interval<F> {
716 type Output = Self;
717
718 fn sub(self, rhs: Self) -> Self::Output {
719 match (self, rhs) {
720 (Interval::TwoSided(a, b), Interval::TwoSided(x, y)) => {
721 Interval::TwoSided(a - y, b - x)
722 }
723 (Interval::TwoSided(_, b) | Interval::LowerOneSided(b), Interval::UpperOneSided(x)) => {
724 Interval::LowerOneSided(b - x)
725 }
726 (Interval::TwoSided(a, _) | Interval::UpperOneSided(a), Interval::LowerOneSided(y)) => {
727 Interval::UpperOneSided(a - y)
728 }
729 (Interval::UpperOneSided(a), Interval::TwoSided(_, y)) => {
730 Interval::UpperOneSided(a - y)
731 }
732 (Interval::LowerOneSided(b), Interval::TwoSided(x, _)) => {
733 Interval::LowerOneSided(b - x)
734 }
735 (Interval::UpperOneSided(_), Interval::UpperOneSided(_))
736 | (Interval::LowerOneSided(_), Interval::LowerOneSided(_)) => {
737 panic!(
738 "Cannot subtract one-sided intervals of the same directions (empty interval)"
739 )
740 }
741 }
742 }
743}
744
745impl<T: PartialOrd> TryFrom<(T, T)> for Interval<T> {
746 type Error = IntervalError;
747
748 fn try_from(value: (T, T)) -> Result<Self, Self::Error> {
754 if value.0 <= value.1 {
755 Interval::new(value.0, value.1)
756 } else {
757 Err(IntervalError::InvalidBounds)
758 }
759 }
760}
761
762impl<T: PartialOrd> TryFrom<(Option<T>, Option<T>)> for Interval<T> {
763 type Error = IntervalError;
764
765 fn try_from(value: (Option<T>, Option<T>)) -> Result<Self, Self::Error> {
772 match value {
773 (Some(low), Some(high)) => Interval::new(low, high),
774 (Some(low), None) => Ok(Interval::new_upper(low)),
775 (None, Some(high)) => Ok(Interval::new_lower(high)),
776 (None, None) => Err(IntervalError::EmptyInterval),
777 }
778 }
779}
780
781impl<T: PartialOrd + Clone> From<Interval<T>> for (Option<T>, Option<T>) {
782 fn from(interval: Interval<T>) -> Self {
788 match interval {
789 Interval::TwoSided(low, high) => (Some(low), Some(high)),
790 Interval::UpperOneSided(low) => (Some(low), None),
791 Interval::LowerOneSided(high) => (None, Some(high)),
792 }
793 }
794}
795
796macro_rules! impl_for_ints {
797 ( $( $x:ty ),+ ) => {
798 $(
799 impl From<Interval<$x>> for ($x, $x) {
800 fn from(value: Interval<$x>) -> Self {
801 match value {
802 Interval::TwoSided(low, high) => (low, high),
803 Interval::UpperOneSided(low) => (low, <$x>::max_value()),
804 Interval::LowerOneSided(high) => (<$x>::min_value(), high),
805 }
806 }
807 }
808 )*
809 };
810}
811impl_for_ints!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize);
812
813macro_rules! impl_for_floats {
814 ( $( $x:ty ),+ ) => {
815 $(
816 impl From<Interval<$x>> for ($x, $x) {
817 fn from(value: Interval<$x>) -> Self {
818 match value {
819 Interval::TwoSided(low, high) => (low, high),
820 Interval::UpperOneSided(low) => (low, <$x>::infinity()),
821 Interval::LowerOneSided(high) => (<$x>::neg_infinity(), high),
822 }
823 }
824 }
825 )*
826 };
827}
828impl_for_floats!(f32, f64);
829
830impl<T: PartialOrd> TryFrom<RangeInclusive<T>> for Interval<T> {
831 type Error = IntervalError;
832
833 fn try_from(range: RangeInclusive<T>) -> Result<Self, Self::Error> {
844 let (start, end) = range.into_inner();
845 Interval::new(start, end)
846 }
847}
848
849impl<T: PartialOrd> From<RangeFrom<T>> for Interval<T> {
850 fn from(range: RangeFrom<T>) -> Self {
861 Interval::new_upper(range.start)
862 }
863}
864
865impl<T: PartialOrd> From<RangeToInclusive<T>> for Interval<T> {
866 fn from(range: RangeToInclusive<T>) -> Self {
877 Interval::new_lower(range.end)
878 }
879}
880
881impl<T: PartialOrd> RangeBounds<T> for Interval<T> {
882 fn start_bound(&self) -> std::ops::Bound<&T> {
883 match self.left() {
884 Some(low) => std::ops::Bound::Included(low),
885 None => std::ops::Bound::Unbounded,
886 }
887 }
888
889 fn end_bound(&self) -> std::ops::Bound<&T> {
890 match self.right() {
891 Some(high) => std::ops::Bound::Excluded(high),
892 None => std::ops::Bound::Unbounded,
893 }
894 }
895}
896
897impl<T: PartialOrd + Sub<Output = T> + num_traits::Zero + Clone> Interval<T> {
898 pub fn width(&self) -> Option<T> {
903 match self {
904 Interval::LowerOneSided(_) | Interval::UpperOneSided(_) => None,
905 Interval::TwoSided(low, high) => Some(high.clone() - low.clone()),
906 }
907 }
908}
909
910impl<T: PartialOrd + Clone> Clone for Interval<T> {
911 fn clone(&self) -> Self {
912 match self {
913 Interval::TwoSided(low, high) => Interval::TwoSided(low.clone(), high.clone()),
914 Interval::UpperOneSided(low) => Interval::UpperOneSided(low.clone()),
915 Interval::LowerOneSided(high) => Interval::LowerOneSided(high.clone()),
916 }
917 }
918}
919
920impl<T: PartialOrd + Copy> Copy for Interval<T> {}
921
922use std::fmt::Display;
923impl<T: PartialOrd + Display> Display for Interval<T> {
924 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
925 match self {
926 Interval::TwoSided(low, high) => write!(f, "[{}, {}]", low, high),
927 Interval::UpperOneSided(low) => write!(f, "[{},->)", low),
928 Interval::LowerOneSided(high) => write!(f, "(<-,{}]", high),
929 }
930 }
931}
932
933use std::hash::Hash;
934impl<T: PartialOrd + Hash> Hash for Interval<T> {
935 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
936 match self {
937 Interval::TwoSided(low, high) => {
938 0.hash(state);
939 low.hash(state);
940 high.hash(state);
941 }
942 Interval::UpperOneSided(low) => {
943 1.hash(state);
944 low.hash(state);
945 }
946 Interval::LowerOneSided(high) => {
947 2.hash(state);
948 high.hash(state);
949 }
950 }
951 }
952}
953
954impl<T: PartialOrd> AsRef<Self> for Interval<T> {
955 fn as_ref(&self) -> &Self {
956 self
957 }
958}
959
960impl<T: PartialOrd> PartialOrd for Interval<T> {
961 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
988 use std::cmp::Ordering::*;
989 match (self, other) {
990 (xy, ab) if xy == ab => Some(Equal),
991 (
992 Interval::UpperOneSided(low) | Interval::TwoSided(low, _),
993 Interval::LowerOneSided(high) | Interval::TwoSided(_, high),
994 ) if low >= high => Some(Greater),
995 (
996 Interval::LowerOneSided(high) | Interval::TwoSided(_, high),
997 Interval::UpperOneSided(low) | Interval::TwoSided(low, _),
998 ) if low >= high => Some(Less),
999 _ => None,
1000 }
1001 }
1002}
1003
1004#[allow(missing_docs)]
1008#[derive(thiserror::Error, Debug)]
1009pub enum IntervalError {
1010 #[error("Invalid bounds: the left bound is greater than the right bound")]
1011 InvalidBounds,
1012
1013 #[error("Empty interval")]
1014 EmptyInterval,
1015}
1016
1017#[cfg(test)]
1026mod tests {
1027 use super::*;
1028
1029 #[test]
1030 fn test_interval_new() -> Result<(), IntervalError> {
1031 let interval = Interval::new(0., 1.)?;
1032 assert_eq!(interval.low(), Some(0.));
1033 assert_eq!(interval.high(), Some(1.));
1034 assert_eq!(interval.low_f(), 0.);
1035 assert_eq!(interval.high_f(), 1.);
1036 assert!(interval.contains(&0.5));
1037 assert!(!interval.contains(&2.));
1038 assert!(!interval.is_degenerate());
1039 assert!(interval.is_two_sided());
1040 assert!(!interval.is_one_sided());
1041 assert!(!interval.is_lower());
1042 assert!(!interval.is_upper());
1043
1044 let interval = Interval::new_lower(0.);
1045 assert_eq!(interval.low(), None);
1046 assert_eq!(interval.high(), Some(0.));
1047 assert_eq!(interval.low_f(), f64::NEG_INFINITY);
1048 assert_ne!(interval.low_f(), f64::MIN);
1049 assert_eq!(interval.high_f(), 0.);
1050 assert!(!interval.is_degenerate());
1051 assert!(!interval.is_two_sided());
1052 assert!(interval.is_one_sided());
1053 assert!(interval.is_lower());
1054 assert!(!interval.is_upper());
1055
1056 let interval = Interval::new_upper(0.);
1057 assert_eq!(interval.low(), Some(0.));
1058 assert_eq!(interval.high(), None);
1059 assert_eq!(interval.low_f(), 0.);
1060 assert_eq!(interval.high_f(), f64::INFINITY);
1061 assert_ne!(interval.high_f(), f64::MAX);
1062 assert!(!interval.is_degenerate());
1063 assert!(!interval.is_two_sided());
1064 assert!(interval.is_one_sided());
1065 assert!(!interval.is_lower());
1066 assert!(interval.is_upper());
1067
1068 let interval = Interval::new(10, 20)?;
1069 assert_eq!(interval.low(), Some(10));
1070 assert_eq!(interval.high(), Some(20));
1071 assert_eq!(interval.low_i(), 10);
1072 assert_eq!(interval.high_i(), 20);
1073 assert!(interval.contains(&15));
1074 assert!(!interval.contains(&30));
1075 assert!(!interval.is_degenerate());
1076 assert!(interval.is_two_sided());
1077 assert!(!interval.is_one_sided());
1078 assert!(!interval.is_lower());
1079 assert!(!interval.is_upper());
1080
1081 let interval = Interval::new_lower(10_i64);
1082 assert_eq!(interval.low(), None);
1083 assert_eq!(interval.high(), Some(10));
1084 assert_eq!(interval.low_i(), std::i64::MIN);
1085 assert_eq!(interval.high_i(), 10);
1086 assert!(!interval.is_degenerate());
1087 assert!(!interval.is_two_sided());
1088 assert!(interval.is_one_sided());
1089 assert!(interval.is_lower());
1090 assert!(!interval.is_upper());
1091
1092 let interval = Interval::new_lower(10_usize);
1093 assert_eq!(interval.low(), None);
1094 assert_eq!(interval.high(), Some(10));
1095 assert_eq!(interval.low_u(), 0);
1096 assert_eq!(interval.high_u(), 10);
1097 assert!(!interval.is_degenerate());
1098 assert!(!interval.is_two_sided());
1099 assert!(interval.is_one_sided());
1100 assert!(interval.is_lower());
1101 assert!(!interval.is_upper());
1102
1103 let interval = Interval::new(10, 10)?;
1104 assert_eq!(interval.low(), Some(10));
1105 assert_eq!(interval.high(), Some(10));
1106 assert!(interval.is_degenerate());
1107 assert!(interval.is_two_sided());
1108 assert!(!interval.is_one_sided());
1109 assert!(!interval.is_lower());
1110 assert!(!interval.is_upper());
1111 Ok(())
1112 }
1113
1114 #[test]
1115 fn test_interval_contains() -> Result<(), IntervalError> {
1116 let interval = Interval::new(0., 1.)?;
1117 assert!(interval.contains(&0.5));
1118 assert!(!interval.contains(&2.));
1119 Ok(())
1120 }
1121
1122 #[test]
1123 fn test_interval_includes() -> Result<(), IntervalError> {
1124 let interval1 = Interval::new(0., 10.)?;
1125 let interval2 = Interval::new(0., 1.)?;
1126 let interval3 = Interval::new(0., 10.)?;
1127 let interval4 = Interval::new(1., 11.)?;
1128 let interval5 = Interval::new(10., 20.)?;
1129 let interval6 = Interval::new_upper(0.);
1130 let interval7 = Interval::new_upper(11.);
1131 let interval8 = Interval::new_upper(20.);
1132 let interval9 = Interval::new_lower(10.);
1133 let interval10 = Interval::new_lower(1.);
1134 let interval11 = Interval::new_lower(-1.);
1135
1136 assert!(interval1.includes(&interval2));
1137 assert!(interval1.includes(&interval3));
1138 assert!(!interval1.includes(&interval4));
1139 assert!(!interval1.includes(&interval5));
1140 assert!(!interval1.includes(&interval6));
1141 assert!(!interval1.includes(&interval7));
1142 assert!(!interval1.includes(&interval8));
1143 assert!(!interval1.includes(&interval9));
1144 assert!(!interval1.includes(&interval10));
1145
1146 assert!(!interval2.includes(&interval1));
1147 assert!(interval3.includes(&interval1));
1148 assert!(!interval4.includes(&interval1));
1149 assert!(!interval5.includes(&interval1));
1150 assert!(interval6.includes(&interval1));
1151 assert!(!interval7.includes(&interval1));
1152 assert!(!interval8.includes(&interval1));
1153 assert!(interval9.includes(&interval1));
1154 assert!(!interval10.includes(&interval1));
1155 assert!(!interval11.includes(&interval1));
1156
1157 Ok(())
1158 }
1159
1160 #[test]
1161 fn test_interval_compare() -> Result<(), IntervalError> {
1162 use std::cmp::Ordering::*;
1163
1164 let interval1 = Interval::new(0., 10.)?;
1165 let interval2 = Interval::new(0., 1.)?;
1166 let interval3 = Interval::new(0., 10.)?;
1167 let interval4 = Interval::new(1., 11.)?;
1168 let interval5 = Interval::new(10., 20.)?;
1169 let interval6 = Interval::new_upper(0.);
1170 let interval7 = Interval::new_upper(11.);
1171 let interval8 = Interval::new_upper(20.);
1172 let interval9 = Interval::new_lower(10.);
1173 let interval10 = Interval::new_lower(1.);
1174 let interval11 = Interval::new_lower(-1.);
1175
1176 assert_eq!(interval1.partial_cmp(&interval2), None);
1177 assert_eq!(interval1.partial_cmp(&interval3), Some(Equal));
1178 assert_eq!(interval1.partial_cmp(&interval4), None);
1179 assert_eq!(interval1.partial_cmp(&interval5), Some(Less));
1180 assert_eq!(interval1.partial_cmp(&interval6), None);
1181 assert_eq!(interval1.partial_cmp(&interval7), Some(Less));
1182 assert_eq!(interval1.partial_cmp(&interval8), Some(Less));
1183 assert_eq!(interval1.partial_cmp(&interval9), None);
1184 assert_eq!(interval1.partial_cmp(&interval10), None);
1185 assert_eq!(interval1.partial_cmp(&interval11), Some(Greater));
1186
1187 Ok(())
1188 }
1189
1190 #[test]
1191 fn test_interval_from_range() -> Result<(), IntervalError> {
1192 let interval = Interval::try_from(0..=3)?;
1193 assert_eq!(interval, Interval::new(0, 3)?);
1194 assert_eq!(interval.low(), Some(0));
1195 assert_eq!(interval.high(), Some(3));
1196 assert!(interval.contains(&1));
1197 assert!(!interval.contains(&10));
1198
1199 let interval = Interval::from(10..);
1200 assert_eq!(interval, Interval::new_upper(10));
1201 assert_eq!(interval.low(), Some(10));
1202 assert_eq!(interval.high(), None);
1203 assert!(interval.contains(&10));
1204 assert!(interval.contains(&100));
1205 assert!(!interval.contains(&0));
1206
1207 let interval = Interval::from(..=10);
1208 assert_eq!(interval, Interval::new_lower(10));
1209 assert_eq!(interval.low(), None);
1210 assert_eq!(interval.high(), Some(10));
1211 assert!(interval.contains(&10));
1212 assert!(!interval.contains(&100));
1213 assert!(interval.contains(&0));
1214
1215 Ok(())
1216 }
1217
1218 #[test]
1219 fn test_special_case() {
1220 assert!(Interval::new(10, 10).is_ok());
1221 assert!(Interval::new(10, 8).is_err());
1222 }
1223
1224 #[test]
1225 fn test_interval_intersection() -> Result<(), IntervalError> {
1226 let interval1 = Interval::new(0, 10)?;
1227 let interval2 = Interval::new(5, 15)?;
1228 let interval3 = Interval::new(10, 20)?;
1229 let interval4 = Interval::new(15, 25)?;
1230
1231 assert!(interval1.intersects(&interval2));
1232 assert!(interval2.intersects(&interval1));
1233 assert!(interval2.intersects(&interval3));
1234 assert!(interval3.intersects(&interval2));
1235 assert!(interval3.intersects(&interval4));
1236 assert!(interval4.intersects(&interval3));
1237
1238 assert!(interval1.intersects(&interval3));
1240 assert!(interval3.intersects(&interval1));
1241
1242 assert!(!interval1.intersects(&interval4));
1243 assert!(!interval4.intersects(&interval1));
1244
1245 Ok(())
1246 }
1247
1248 #[test]
1249 fn test_interval_equality() -> Result<(), IntervalError> {
1250 let interval1 = Interval::new(0, 10)?;
1251 let interval2 = Interval::new(0, 10)?;
1252 let interval3 = Interval::new(0, 11)?;
1253 let interval4 = Interval::new(1, 10)?;
1254 let interval5 = Interval::new(1, 11)?;
1255
1256 assert_eq!(interval1, interval2);
1257 assert_ne!(interval1, interval3);
1258 assert_ne!(interval1, interval4);
1259 assert_ne!(interval1, interval5);
1260
1261 Ok(())
1262 }
1263
1264 #[test]
1265 fn test_width() -> Result<(), IntervalError> {
1266 assert_eq!(Interval::new(0, 10)?.width(), Some(10));
1267 assert_eq!(Interval::new(0, 0)?.width(), Some(0));
1268 assert_eq!(Interval::new(-10, 0)?.width(), Some(10));
1269 assert_eq!(Interval::new(-10, -10)?.width(), Some(0));
1270
1271 Ok(())
1272 }
1273
1274 #[test]
1275 fn test_from() -> Result<(), IntervalError> {
1276 let interval = Interval::try_from(0..=10)?;
1277 assert_eq!(interval.low(), Some(0));
1278 assert_eq!(interval.high(), Some(10));
1279
1280 let tuple: (i32, i32) = interval.into();
1281 assert_eq!(tuple, (0, 10));
1282
1283 let tuple: (f64, f64) = Interval::new_lower(0.).into();
1284 let (lo, hi) = tuple;
1285 assert!(lo.is_infinite());
1286 assert!(lo.is_sign_negative());
1287 assert_eq!(hi, 0.);
1288
1289 let tuple: (f64, f64) = Interval::new_upper(0.).into();
1290 assert_eq!(tuple, (0., f64::INFINITY));
1291 assert_eq!(tuple, (0., f64::infinity()));
1292
1293 let tuple: (f64, f64) = Interval::new_lower(0.).into();
1294 assert_eq!(tuple, (f64::NEG_INFINITY, 0.));
1295 assert_eq!(tuple, (f64::neg_infinity(), 0.));
1296
1297 let tuple: (usize, usize) = Interval::new_lower(10).into();
1298 assert_eq!(tuple, (0, 10));
1299
1300 let tuple: (usize, usize) = Interval::new_upper(10).into();
1301 assert_eq!(tuple, (10, usize::MAX));
1302 Ok(())
1303 }
1304
1305 #[test]
1306 fn test_send() {
1307 fn assert_send<T: Send>() {}
1308 assert_send::<Interval<f64>>();
1309 }
1310
1311 #[test]
1312 fn test_sync() {
1313 fn assert_sync<T: Sync>() {}
1314 assert_sync::<Interval<f64>>();
1315 }
1316
1317 #[test]
1318 fn test_approx() {
1319 use approx::*;
1320
1321 let interval1 = Interval::new(0., 10.).unwrap();
1322 let interval2 = Interval::new(1e-7, 10.000000001).unwrap();
1323 assert!(interval1.abs_diff_eq(&interval2, 1e-6));
1324 assert_abs_diff_eq!(interval1, interval2, epsilon = 1e-6);
1325 }
1326}