intervalues/
interval.rs

1use crate::BaseInterval;
2use intfloat::IntFloat;
3use num_traits::{Num, ToPrimitive};
4use rust_decimal::Decimal;
5use std::cmp::PartialOrd;
6use std::fmt;
7use std::fmt::{Debug, Display, Formatter};
8
9#[derive(Clone, Copy, Hash, Eq, PartialEq)]
10/// Interval struct that contains a lowerbound, upperbound and value/count of the range within the
11/// interval. These can be aggregated together using intervalues::combine_intervals().
12///
13/// # Examples
14///
15/// ```
16/// use intervalues::Interval;
17///
18/// let x = Interval::new(0, 1, 2.5);
19/// assert_eq!(x.get_lb(), 0);
20/// assert_eq!(x.get_ub(), 1);
21/// assert_eq!(x.get_value(), 2.5);
22/// ```
23pub struct Interval<T: Num, U: Num> {
24    lb: T,
25    ub: T,
26    val: U,
27}
28
29impl<T, U> Default for Interval<T, U>
30where
31    T: Num + PartialOrd + Clone,
32    U: Num,
33{
34    fn default() -> Self {
35        Interval {
36            lb: T::zero(),
37            ub: T::one(),
38            val: U::one(),
39        }
40    }
41}
42
43impl<T, U> Debug for Interval<T, U>
44where
45    T: Num + PartialOrd + Clone + Display,
46    U: Num + PartialOrd + Display,
47{
48    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
49        write!(f, "{}", self.print())
50    }
51}
52
53impl<T, U> Display for Interval<T, U>
54where
55    T: Num + PartialOrd + Clone + Display,
56    U: Num + PartialOrd + Display,
57{
58    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59        write!(f, "{}", self.print())
60    }
61}
62
63impl<T, U> Interval<T, U>
64where
65    T: Num + PartialOrd + Clone + Display,
66    U: Num + PartialOrd + Display,
67{
68    pub fn new(lb: T, ub: T, val: U) -> Self {
69        if ub > lb {
70            Interval { lb, ub, val }
71        } else {
72            Interval {
73                lb: ub,
74                ub: lb,
75                val,
76            }
77        }
78    }
79
80    pub fn print(&self) -> String {
81        format!("[{};{}]x{}", self.lb, self.ub, self.val)
82    }
83
84    pub fn to_tuple(self) -> (T, T, U) {
85        (self.lb, self.ub, self.val)
86    }
87
88    pub fn get_bounds(self) -> (T, T) {
89        (self.lb, self.ub)
90    }
91
92    pub fn get_lb(self) -> T {
93        self.lb
94    }
95
96    pub fn get_ub(self) -> T {
97        self.ub
98    }
99
100    pub fn get_width(self) -> T {
101        self.ub - self.lb
102    }
103
104    pub fn get_value(self) -> U {
105        self.val
106    }
107
108    pub fn len(self) -> T {
109        self.ub - self.lb
110    }
111
112    pub fn contains(self, num: T) -> bool {
113        if (num >= self.lb) & (num <= self.ub) {
114            true
115        } else {
116            false
117        }
118    }
119
120    // TODO explore if T can be U here
121    pub fn superset(self, other: Interval<T, U>) -> bool {
122        if (other.ub <= self.ub) && (other.lb >= self.lb) {
123            true
124        } else {
125            false
126        }
127    }
128
129    pub fn subset(self, other: Interval<T, U>) -> bool {
130        other.superset(self)
131    }
132
133    pub fn left_overlaps(&self, other: &Interval<T, U>) -> bool {
134        if (self.lb <= other.lb) & (self.ub <= other.ub) & (other.lb <= self.ub) {
135            true
136        } else {
137            false
138        }
139    }
140
141    pub fn right_overlaps(self, other: &Interval<T, U>) -> bool {
142        other.left_overlaps(&self)
143    }
144
145    pub fn overlaps(self, other: &Interval<T, U>) -> bool {
146        self.left_overlaps(other) || self.right_overlaps(other)
147    }
148
149    pub fn can_join(self, other: &Interval<T, U>) -> bool {
150        if ((self.ub == other.lb) || (other.ub == self.lb)) && (self.val == other.val) {
151            true
152        } else if (self.ub == other.ub) && (self.lb == other.lb) {
153            true
154        } else {
155            false
156        }
157    }
158
159    pub fn join(self, other: Interval<T, U>) -> Interval<T, U> {
160        // Two options to enter this -> same range, or bordering range but same val
161        // So test (and if so, return for) option 1, and then continue with option 2
162        if (self.ub == other.ub) && (self.lb == other.lb) {
163            return Interval::new(self.lb, self.ub, self.val + other.val);
164        }
165
166        // Option 2 from above
167        let (lb, ub) = if self.lb < other.lb {
168            (self.lb, other.ub)
169        } else {
170            (other.lb, self.ub)
171        };
172        Interval::new(lb, ub, self.val)
173    }
174
175    pub fn can_join_as_set(self, other: &Interval<T, U>) -> bool {
176        if self.overlaps(other) {
177            true
178        } else {
179            false
180        }
181    }
182
183    pub fn join_ign_value(self, other: Interval<T, U>) -> Interval<T, U> {
184        let lb = if self.lb < other.lb {
185            self.lb
186        } else {
187            other.lb
188        };
189        let ub = if self.ub > other.ub {
190            self.ub
191        } else {
192            other.ub
193        };
194        Interval::new(lb, ub, U::one())
195    }
196
197    pub fn join_as_set(self, other: Interval<T, U>) -> BaseInterval<T> {
198        let lb = if self.lb < other.lb {
199            self.lb
200        } else {
201            other.lb
202        };
203        let ub = if self.ub > other.ub {
204            self.ub
205        } else {
206            other.ub
207        };
208        BaseInterval::new(lb, ub)
209    }
210
211    pub fn to_base(self) -> BaseInterval<T> {
212        BaseInterval::new(self.lb, self.ub)
213    }
214}
215
216impl<T> Interval<T, T>
217where
218    T: Num,
219{
220    pub fn get_total_value(self) -> T {
221        (self.ub - self.lb) * self.val
222    }
223}
224
225impl<T, U> Interval<T, U>
226where
227    T: Num + Clone + PartialOrd + Display,
228    U: Num + PartialOrd + ToPrimitive,
229{
230    pub fn val_to_count(self) -> Interval<T, usize> {
231        // To test if this works
232        if self.val >= U::one() {
233            Interval::new(self.lb, self.ub, self.val.to_usize().unwrap())
234        } else {
235            Interval::new(self.lb, self.ub, 0)
236        }
237    }
238}
239
240impl Interval<IntFloat, IntFloat> {
241    pub fn to_f32(self) -> (f32, f32, f32) {
242        (
243            self.lb.to_f32().unwrap(),
244            self.ub.to_f32().unwrap(),
245            self.val.to_f32().unwrap(),
246        )
247    }
248}
249
250impl Interval<Decimal, Decimal> {
251    pub fn to_f32(self) -> (f32, f32, f32) {
252        (
253            self.lb.to_f32().unwrap(),
254            self.ub.to_f32().unwrap(),
255            self.val.to_f32().unwrap(),
256        )
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use super::*;
263    use intfloat::IntFloat;
264    use num_traits::{FromPrimitive, One};
265
266    #[test]
267    fn test_create_int_interval() {
268        let a = Interval::new(1, 2, 1);
269        assert_eq!(a.len(), 1);
270        assert_eq!(a.get_value(), 1)
271    }
272
273    #[test]
274    fn test_create_float_interval() {
275        let a = Interval::new(1.0, 4.0, 2.0);
276        assert_eq!(a.len(), 3.0);
277        assert_eq!(a.get_value(), 2.0);
278        assert_eq!(a.get_total_value(), 6.0)
279    }
280
281    #[test]
282    fn test_create_mixed_interval() {
283        let a = Interval::new(1.0, 2.0, 1);
284        assert_eq!(a.len(), 1.0);
285        assert_eq!(a.get_value(), 1)
286    }
287
288    #[test]
289    fn test_create_mixed_interval2() {
290        let a = Interval::new(1, 2, 1.0);
291        assert_eq!(a.len(), 1);
292        assert_eq!(a.get_value(), 1.0)
293    }
294
295    #[test]
296    fn test_create_intfloat_interval() {
297        let a = Interval::new(
298            IntFloat::one(),
299            IntFloat::from(3.0, 0),
300            IntFloat::from(3.0, 0),
301        );
302        assert_eq!(a.len(), IntFloat::from(2.0, 0));
303        assert_eq!(a.get_value(), IntFloat::from(3.0, 0));
304        assert_eq!(a.get_total_value(), IntFloat::from(6.0, 0))
305    }
306
307    #[test]
308    fn test_bounds() {
309        let a = Interval::new(3, 7, 2);
310        assert_eq!(a.to_tuple(), (3, 7, 2));
311        assert_eq!(a.get_bounds(), (3, 7));
312        assert_eq!(a.get_lb(), 3);
313        assert_eq!(a.get_ub(), 7);
314        assert_eq!(a.get_width(), 4);
315    }
316
317    #[test]
318    fn test_total_value() {
319        let a = Interval::new(3, 7, 2);
320        assert_eq!(a.get_total_value(), 8);
321        assert_eq!(a.get_value(), 2);
322    }
323
324    #[test]
325    fn test_contains() {
326        let a = Interval::new(3, 7, 2);
327        assert!(a.contains(4));
328        assert!(a.contains(3));
329        assert!(a.contains(7));
330        assert!(!a.contains(0));
331    }
332
333    #[test]
334    fn test_superset_subset() {
335        let a = Interval::new(3, 7, 2);
336        let b = Interval::new(4, 6, 1);
337
338        assert!(a.superset(b));
339        assert!(b.subset(a));
340        assert!(!a.subset(b));
341        assert!(!b.superset(a));
342    }
343
344    #[test]
345    fn test_overlaps() {
346        let a = Interval::new(3, 6, 1);
347        let b = Interval::new(4, 7, 2);
348
349        assert!(a.left_overlaps(&b));
350        assert!(b.right_overlaps(&a));
351        assert!(!a.right_overlaps(&b));
352        assert!(!b.left_overlaps(&a));
353    }
354
355    #[test]
356    fn test_join() {
357        let a = Interval::new(0, 2, 1);
358        let b = Interval::new(2, 4, 2);
359        let c = Interval::new(4, 6, 2);
360
361        assert!(!a.can_join(&b));
362        assert!(c.can_join(&b));
363        assert!(b.can_join(&c));
364        assert!(!a.can_join(&c));
365
366        let d = Interval::new(0, 2, 2);
367        let e = Interval::new(2, 6, 2);
368
369        assert_eq!(a.join(a), d);
370        assert_eq!(c.join(b), e);
371    }
372
373    #[test]
374    fn test_join_ign_value() {
375        let a = Interval::new(0, 2, 2);
376        let b = Interval::new(1, 4, 3);
377        let c = Interval::new(3, 6, 6);
378
379        assert!(a.can_join_as_set(&b));
380        assert!(c.can_join_as_set(&b));
381        assert!(b.can_join_as_set(&c));
382        assert!(!a.can_join_as_set(&c));
383
384        let d = BaseInterval::new(0, 4);
385        let e = BaseInterval::new(1, 6);
386        let d2 = Interval::new(0, 4, 1);
387        let e2 = Interval::new(1, 6, 1);
388
389        assert_eq!(a.join_as_set(b), d);
390        assert_eq!(c.join_as_set(b), e);
391
392        assert_eq!(a.join_ign_value(b), d2);
393        assert_eq!(c.join_ign_value(b), e2);
394    }
395
396    #[test]
397    fn test_val_to_count() {
398        let a = Interval::new(0, 2, 3.5);
399        let b = Interval::new(0, 2, 3);
400        assert_eq!(a.val_to_count(), b);
401
402        let c = Interval::new(0, 2, -3.5);
403        let d = Interval::new(0, 2, 0);
404        assert_eq!(c.val_to_count(), d);
405    }
406
407    #[test]
408    fn test_to_base() {
409        let a = Interval::new(0, 2, 3.5);
410        let b = BaseInterval::new(0, 2);
411        assert_eq!(a.to_base(), b)
412    }
413
414    #[test]
415    fn test_to_f32() {
416        let a = Interval::new(
417            Decimal::from_f32(1.2).unwrap(),
418            Decimal::from_f32(3.5).unwrap(),
419            Decimal::from_f32(2.5).unwrap(),
420        );
421        let b = Interval::new(
422            IntFloat::from(1.2, 1),
423            IntFloat::from(3.5, 1),
424            IntFloat::from(2.5, 1),
425        );
426        assert_eq!(a.to_f32(), b.to_f32());
427    }
428}