use crate::generic::{Contain, Displacement, MinDist, Overlap};
use std::cmp::{Eq, PartialEq, PartialOrd};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::marker::PhantomData;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct Interval<T> {
pub lb: T,
pub ub: T,
pub _marker: PhantomData<T>,
}
impl<T> Interval<T> {
#[inline]
pub const fn new(lb: T, ub: T) -> Self {
Self {
lb,
ub,
_marker: PhantomData,
}
}
}
impl<T: Copy> Interval<T> {
#[inline]
pub const fn lb(&self) -> T {
self.lb
}
#[inline]
pub const fn ub(&self) -> T {
self.ub
}
}
impl<T: PartialOrd> Interval<T> {
#[inline]
pub fn is_invalid(&self) -> bool {
self.lb > self.ub
}
}
impl<T: Copy + Sub<Output = T>> Interval<T> {
#[inline]
pub fn length(&self) -> T {
self.ub - self.lb
}
}
impl<T> Display for Interval<T>
where
T: PartialOrd + Copy + Display,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "[{}, {}]", self.lb, self.ub)
}
}
impl<T: Sub<Output = T>> Sub for Interval<T> {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self {
lb: self.lb - other.lb,
ub: self.ub - other.ub,
_marker: PhantomData,
}
}
}
impl<T> Neg for Interval<T>
where
T: Copy + Neg<Output = T>,
{
type Output = Interval<T>;
#[inline]
fn neg(self) -> Self::Output {
Interval {
lb: -self.ub,
ub: -self.lb,
_marker: self._marker,
}
}
}
impl<T> AddAssign<T> for Interval<T>
where
T: Copy + AddAssign<T>,
{
#[inline]
fn add_assign(&mut self, rhs: T) {
self.lb += rhs;
self.ub += rhs;
}
}
impl<T> Add<T> for Interval<T>
where
T: Copy + Add<Output = T>,
{
type Output = Interval<T>;
#[inline]
fn add(self, rhs: T) -> Self::Output {
Interval {
lb: self.lb + rhs,
ub: self.ub + rhs,
_marker: self._marker,
}
}
}
impl<T> SubAssign<T> for Interval<T>
where
T: Copy + SubAssign<T>,
{
#[inline]
fn sub_assign(&mut self, rhs: T) {
self.lb -= rhs;
self.ub -= rhs;
}
}
impl<T: Add<Output = T>> Add for Interval<T> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self {
lb: self.lb + other.lb,
ub: self.ub + other.ub,
_marker: PhantomData,
}
}
}
impl<T> Sub<T> for Interval<T>
where
T: Copy + Sub<Output = T>,
{
type Output = Interval<T>;
#[inline]
fn sub(self, rhs: T) -> Self::Output {
Interval {
lb: self.lb - rhs,
ub: self.ub - rhs,
_marker: self._marker,
}
}
}
impl<T> MulAssign<T> for Interval<T>
where
T: Copy + MulAssign<T>,
{
#[inline]
fn mul_assign(&mut self, rhs: T) {
self.lb *= rhs;
self.ub *= rhs;
}
}
impl<T> Mul<T> for Interval<T>
where
T: Copy + Mul<Output = T>,
{
type Output = Interval<T>;
#[inline]
fn mul(self, rhs: T) -> Self::Output {
Interval {
lb: self.lb * rhs,
ub: self.ub * rhs,
_marker: self._marker,
}
}
}
pub trait Enlarge<Alpha> {
type Output;
fn enlarge_with(&self, alpha: Alpha) -> Self::Output;
}
impl Enlarge<i32> for i32 {
type Output = Interval<i32>;
#[inline]
fn enlarge_with(&self, alpha: i32) -> Interval<i32> {
Interval {
lb: *self - alpha,
ub: *self + alpha,
_marker: PhantomData,
}
}
}
impl<T> Enlarge<T> for Interval<T>
where
T: Copy + Add<Output = T> + Sub<Output = T>,
{
type Output = Interval<T>;
#[inline]
fn enlarge_with(&self, alpha: T) -> Self {
Interval {
lb: self.lb - alpha,
ub: self.ub + alpha,
_marker: self._marker,
}
}
}
impl<T: PartialOrd> PartialOrd for Interval<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.ub < other.lb {
Some(std::cmp::Ordering::Less)
} else if other.ub < self.lb {
Some(std::cmp::Ordering::Greater)
} else {
Some(std::cmp::Ordering::Equal)
}
}
}
impl<T: PartialOrd> Overlap<Interval<T>> for Interval<T> {
#[inline]
fn overlaps(&self, other: &Interval<T>) -> bool {
self.ub >= other.lb && other.ub >= self.lb
}
}
impl<T: PartialOrd> Overlap<T> for Interval<T> {
#[inline]
fn overlaps(&self, other: &T) -> bool {
self.ub >= *other && *other >= self.lb
}
}
impl<T: PartialOrd> Overlap<Interval<T>> for T {
#[inline]
fn overlaps(&self, other: &Interval<T>) -> bool {
*self >= other.lb && other.ub >= *self
}
}
impl<T: PartialOrd> Contain<Interval<T>> for Interval<T> {
#[inline]
fn contains(&self, other: &Interval<T>) -> bool {
self.lb <= other.lb && other.ub <= self.ub
}
}
impl<T: PartialOrd> Contain<T> for Interval<T> {
#[inline]
fn contains(&self, other: &T) -> bool {
self.lb <= *other && *other <= self.ub
}
}
impl<T: PartialOrd> Contain<Interval<T>> for T {
#[inline]
fn contains(&self, _other: &Interval<T>) -> bool {
false
}
}
impl<T> Displacement<Interval<T>> for Interval<T>
where
T: Displacement<T, Output = T>,
{
type Output = Interval<T>;
#[inline]
fn displace(&self, other: &Interval<T>) -> Self::Output {
Self::Output::new(self.lb.displace(&other.lb), self.ub.displace(&other.ub))
}
}
impl MinDist<Interval<i32>> for Interval<i32> {
#[inline]
fn min_dist_with(&self, other: &Interval<i32>) -> u32 {
if self.ub < other.lb {
(other.lb - self.ub) as u32
} else if other.ub < self.lb {
(self.lb - other.ub) as u32
} else {
0
}
}
}
impl MinDist<i32> for Interval<i32> {
#[inline]
fn min_dist_with(&self, other: &i32) -> u32 {
if self.ub < *other {
(*other - self.ub) as u32
} else if *other < self.lb {
(self.lb - *other) as u32
} else {
0
}
}
}
impl MinDist<Interval<i32>> for i32 {
#[inline]
fn min_dist_with(&self, other: &Interval<i32>) -> u32 {
if *self < other.lb {
(other.lb - *self) as u32
} else if other.ub < *self {
(*self - other.ub) as u32
} else {
0
}
}
}
pub trait Hull<T: ?Sized> {
type Output;
fn hull_with(&self, other: &T) -> Self::Output;
}
impl Hull<i32> for i32 {
type Output = Interval<i32>;
#[inline]
fn hull_with(&self, other: &i32) -> Self::Output {
if *self < *other {
Interval::new(*self, *other)
} else {
Interval::new(*other, *self)
}
}
}
impl<T> Hull<Interval<T>> for Interval<T>
where
T: Copy + Ord,
{
type Output = Interval<T>;
#[inline]
fn hull_with(&self, other: &Interval<T>) -> Self::Output {
Self::Output {
lb: self.lb.min(other.lb),
ub: self.ub.max(other.ub),
_marker: self._marker,
}
}
}
impl<T> Hull<T> for Interval<T>
where
T: Copy + Ord,
{
type Output = Interval<T>;
#[inline]
fn hull_with(&self, other: &T) -> Self::Output {
Self::Output {
lb: self.lb.min(*other),
ub: self.ub.max(*other),
_marker: self._marker,
}
}
}
impl<T> Hull<Interval<T>> for T
where
T: Copy + Ord,
{
type Output = Interval<T>;
#[inline]
fn hull_with(&self, other: &Interval<T>) -> Self::Output {
other.hull_with(self)
}
}
pub trait Intersect<T: ?Sized> {
type Output;
fn intersect_with(&self, other: &T) -> Self::Output;
}
impl Intersect<i32> for i32 {
type Output = Interval<i32>;
#[inline]
fn intersect_with(&self, other: &i32) -> Self::Output {
Self::Output {
lb: (*self).max(*other),
ub: (*self).min(*other),
_marker: PhantomData,
}
}
}
impl<T> Intersect<Interval<T>> for Interval<T>
where
T: Copy + Ord,
{
type Output = Interval<T>;
#[inline]
fn intersect_with(&self, other: &Interval<T>) -> Self::Output {
Self::Output {
lb: self.lb.max(other.lb),
ub: self.ub.min(other.ub),
_marker: self._marker,
}
}
}
impl<T> Intersect<T> for Interval<T>
where
T: Copy + Ord,
{
type Output = Interval<T>;
#[inline]
fn intersect_with(&self, other: &T) -> Self::Output {
Self::Output {
lb: self.lb.max(*other),
ub: self.ub.min(*other),
_marker: self._marker,
}
}
}
impl<T> Intersect<Interval<T>> for T
where
T: Copy + Ord,
{
type Output = Interval<T>;
#[inline]
fn intersect_with(&self, other: &Interval<T>) -> Self::Output {
other.intersect_with(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_interval() {
let interval_a = Interval::new(4, 8);
let interval_b = Interval::new(5, 6);
assert!(interval_a <= interval_b);
assert!(interval_b <= interval_a);
assert!(interval_a >= interval_b);
assert!(interval_b >= interval_a);
assert!(interval_a.overlaps(&interval_b));
assert!(interval_b.overlaps(&interval_a));
assert!(interval_a.contains(&4));
assert!(interval_a.contains(&8));
assert!(interval_a.contains(&interval_b));
assert_eq!(interval_a, interval_a);
assert_eq!(interval_b, interval_b);
assert_ne!(interval_a, interval_b);
assert_ne!(interval_b, interval_a);
assert!(interval_a.overlaps(&interval_a));
assert!(interval_b.overlaps(&interval_b));
assert!(interval_a.contains(&interval_a));
assert!(interval_b.contains(&interval_b));
assert!(interval_a.overlaps(&interval_b));
assert!(interval_b.overlaps(&interval_a));
}
#[test]
fn test_hull_more_cases() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(1, 7);
assert_eq!(interval_a.hull_with(&interval_b), Interval::new(1, 7));
let interval_c = Interval::new(-2, 2);
assert_eq!(interval_a.hull_with(&interval_c), Interval::new(-2, 5));
let val_d = 4;
assert_eq!(interval_a.hull_with(&val_d), Interval::new(3, 5));
let val_e = 8;
assert_eq!(interval_a.hull_with(&val_e), Interval::new(3, 8));
let val_f = 0;
assert_eq!(interval_a.hull_with(&val_f), Interval::new(0, 5));
}
#[test]
fn test_interval1() {
let interval_a = Interval::new(4, 5);
let interval_b = Interval::new(6, 8);
assert!(interval_a < interval_b);
assert!(!(interval_b == interval_a));
assert!(interval_b != interval_a);
}
#[test]
fn test_interval2() {
let interval_a = Interval::new(4, 8);
let interval_b = Interval::new(5, 6);
assert!(interval_a.contains(&4));
assert!(interval_a.contains(&8));
assert!(interval_a.contains(&interval_b));
assert!(!interval_b.contains(&interval_a));
assert!(interval_a.overlaps(&interval_b));
assert!(interval_b.overlaps(&interval_a));
}
#[test]
fn test_interval3() {
let interval_a = Interval::new(3, 4);
assert!(interval_a.lb == 3);
assert!(interval_a.ub == 4);
assert!(interval_a.contains(&3));
assert!(interval_a.contains(&4));
assert!(!interval_a.contains(&5));
assert!(interval_a.contains(&Interval::new(3, 4)));
assert!(!interval_a.contains(&Interval::new(3, 5)));
assert!(!interval_a.contains(&Interval::new(2, 3)));
assert!(!interval_a.contains(&2));
assert!(interval_a.contains(&4));
assert!(!interval_a.contains(&5));
}
#[test]
fn test_arithmetic() {
let mut interval_a = Interval::new(3, 5);
assert_eq!(interval_a + 1, Interval::new(4, 6));
assert_eq!(interval_a - 1, Interval::new(2, 4));
assert_eq!(interval_a * 2, Interval::new(6, 10));
assert!(-interval_a == Interval::new(-5, -3));
interval_a += 1;
assert!(interval_a == Interval::new(4, 6));
interval_a -= 1;
assert!(interval_a == Interval::new(3, 5));
interval_a *= 2;
assert!(interval_a == Interval::new(6, 10));
}
#[test]
fn test_overlap() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(5, 7);
let interval_c = Interval::new(7, 8);
assert!(interval_a.overlaps(&interval_b));
assert!(interval_b.overlaps(&interval_c));
assert!(!interval_a.overlaps(&interval_c));
assert!(!interval_c.overlaps(&interval_a));
let val_d = 4;
assert!(interval_a.overlaps(&val_d));
assert!(!interval_a.overlaps(&6));
assert!(val_d.overlaps(&interval_a));
assert!(val_d.overlaps(&val_d));
}
#[test]
fn test_contains() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(5, 7);
let interval_c = Interval::new(7, 8);
assert!(!interval_a.contains(&interval_b));
assert!(!interval_b.contains(&interval_c));
assert!(!interval_a.contains(&interval_c));
assert!(!interval_c.contains(&interval_a));
let val_d = 4;
assert!(interval_a.contains(&val_d));
assert!(!interval_a.contains(&6));
assert!(!val_d.contains(&interval_a));
assert!(val_d.contains(&val_d));
}
#[test]
fn test_intersect() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(5, 7);
let interval_c = Interval::new(7, 8);
assert_eq!(interval_a.intersect_with(&interval_b), Interval::new(5, 5));
assert_eq!(interval_b.intersect_with(&interval_c), Interval::new(7, 7));
assert!(interval_a.intersect_with(&interval_c).is_invalid());
assert_eq!(interval_a.intersect_with(&interval_b), Interval::new(5, 5));
assert_eq!(interval_b.intersect_with(&interval_c), Interval::new(7, 7));
let val_d = 4;
assert_eq!(interval_a.intersect_with(&val_d), Interval::new(4, 4));
assert!(interval_a.intersect_with(&6).is_invalid());
assert_eq!(interval_a.intersect_with(&val_d), Interval::new(4, 4));
assert_eq!(val_d.intersect_with(&interval_a), Interval::new(4, 4));
assert_eq!(val_d.intersect_with(&val_d), Interval::new(4, 4));
}
#[test]
fn test_hull() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(5, 7);
let interval_c = Interval::new(7, 8);
assert_eq!(interval_a.hull_with(&interval_b), Interval::new(3, 7));
assert_eq!(interval_b.hull_with(&interval_c), Interval::new(5, 8));
assert_eq!(interval_a.hull_with(&interval_c), Interval::new(3, 8));
let val_d = 4;
assert_eq!(interval_a.hull_with(&val_d), Interval::new(3, 5));
assert_eq!(interval_a.hull_with(&6), Interval::new(3, 6));
}
#[test]
fn test_min_dist() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(5, 7);
let interval_c = Interval::new(7, 8);
assert_eq!(interval_a.min_dist_with(&interval_b), 0);
assert_eq!(interval_a.min_dist_with(&interval_c), 2);
assert_eq!(interval_b.min_dist_with(&interval_c), 0);
let val_d = 4;
assert_eq!(interval_a.min_dist_with(&val_d), 0);
assert_eq!(val_d.min_dist_with(&interval_a), 0);
assert_eq!(interval_a.min_dist_with(&6), 1);
assert_eq!(6.min_dist_with(&interval_a), 1);
}
#[test]
fn test_displacement() {
let interval_a = Interval::new(3, 5);
let interval_b = Interval::new(5, 7);
let interval_c = Interval::new(7, 8);
assert_eq!(interval_a.displace(&interval_b), Interval::new(-2, -2));
assert_eq!(interval_a.displace(&interval_c), Interval::new(-4, -3));
assert_eq!(interval_b.displace(&interval_c), Interval::new(-2, -1));
let val_d = 4;
assert_eq!(val_d.displace(&val_d), 0);
assert_eq!(val_d.displace(&6), -2);
assert_eq!(6.displace(&val_d), 2);
}
#[test]
fn test_enlarge() {
let interval_a = Interval::new(3, 5);
assert!(interval_a.enlarge_with(2) == Interval::new(1, 7));
let val_d = 4;
assert_eq!(val_d.enlarge_with(6), Interval::new(-2, 10));
assert_eq!(6.enlarge_with(val_d), Interval::new(2, 10));
}
#[test]
fn test_min_dist_with_interval_other_ub_less_self_lb() {
use crate::generic::MinDist;
let a = Interval::new(10, 20);
let b = Interval::new(0, 5);
assert_eq!(a.min_dist_with(&b), 5);
}
#[test]
fn test_min_dist_with_scalar_other_less_self_lb() {
use crate::generic::MinDist;
let a = Interval::new(10, 20);
assert_eq!(a.min_dist_with(&5), 5);
}
#[test]
fn test_min_dist_with_scalar_self_less_interval_lb() {
let val = 3;
let other = Interval::new(10, 20);
assert_eq!(val.min_dist_with(&other), 7);
}
}
#[test]
fn test_interval_length() {
let interval = Interval::new(3, 8);
assert_eq!(interval.length(), 5);
let interval2 = Interval::new(-2, 3);
assert_eq!(interval2.length(), 5);
}
#[test]
fn test_interval_display() {
let interval = Interval::new(3, 8);
let display_str = format!("{}", interval);
assert_eq!(display_str, "[3, 8]");
let interval2 = Interval::new(-5, 10);
let display_str2 = format!("{}", interval2);
assert_eq!(display_str2, "[-5, 10]");
}
#[test]
fn test_interval_sub_interval() {
let interval_a = Interval::new(5, 10);
let interval_b = Interval::new(2, 3);
let result = interval_a - interval_b;
assert_eq!(result, Interval::new(3, 7));
}
#[test]
fn test_interval_add_interval() {
let interval_a = Interval::new(1, 3);
let interval_b = Interval::new(2, 5);
let result = interval_a + interval_b;
assert_eq!(result, Interval::new(3, 8));
}
#[test]
fn test_interval_is_invalid() {
let valid_interval = Interval::new(1, 5);
assert!(!valid_interval.is_invalid());
let invalid_interval = Interval::new(5, 1);
assert!(invalid_interval.is_invalid());
}
#[test]
fn test_interval_sub_assign_interval() {
let mut interval = Interval::new(10, 20);
interval -= 3;
assert_eq!(interval, Interval::new(7, 17));
}
#[test]
fn test_interval_hull_t_for_t() {
let val = 5;
let interval = Interval::new(3, 8);
let result = val.hull_with(&interval);
assert_eq!(result.lb, 3);
assert_eq!(result.ub, 8);
}
#[test]
fn test_interval_contains_interval_t() {
let interval = Interval::new(3, 8);
let val = 5;
assert!(!val.contains(&interval));
}
#[test]
fn test_interval_overlap_interval_t() {
let val = 5;
let interval = Interval::new(3, 8);
assert!(val.overlaps(&interval));
let val2 = 10;
assert!(!val2.overlaps(&interval));
}
#[test]
fn test_interval_partial_cmp_greater() {
let interval_a = Interval::new(8, 10);
let interval_b = Interval::new(3, 5);
let cmp = interval_a.partial_cmp(&interval_b);
assert_eq!(cmp, Some(std::cmp::Ordering::Greater));
}