timekeep_rs/
set.rs

1//! # Interval Set Operations Module
2//!
3//! This module provides implementations for interval set operations through the [`IntervalSet`] type,
4//! which manages collections of [`AtomicInterval`]s and supports various set operations.
5//!
6//! ## Main Types
7//!
8//! - [`IntervalSet<T>`]: A collection of atomic intervals supporting set operations
9//!
10//! ## Operations
11//!
12//! The module supports these primary set operations:
13//!
14//! - **Union**: Combines intervals, merging overlapping or adjacent ones
15//! - **Intersection**: Finds common regions between intervals
16//! - **Difference**: Computes regions present in one interval but not another
17//!
18//! ## Example
19//!
20//! ```rust
21//! use timekeep_rs::{IntervalSet, AtomicInterval};
22//!
23//! // Create two intervals
24//! let a = IntervalSet::from(AtomicInterval::closed(1, 5));
25//! let b = IntervalSet::from(AtomicInterval::closed(3, 7));
26//!
27//! // Perform set operations
28//! let union = a.union(&b);                    // Results in [1, 7]
29//! let intersection = a.intersection(&b);       // Results in [3, 5]
30//! let difference = a.difference(&b);          // Results in [1, 3)
31//! ```
32//!
33//! ## Type Parameters
34//!
35//! - `T`: Represents the boundary type for intervals
36//!   - Must implement [`Clone`]
37//!   - Must implement [`PartialOrd`] for set operations
38use crate::atomic::AtomicInterval;
39
40#[derive(Debug, Clone, PartialEq)]
41pub struct IntervalSet<T> {
42    /// A vector of AtomicIntervals that make up the IntervalSet
43    pub intervals: Vec<AtomicInterval<T>>,
44}
45
46impl<T: ToString> ToString for IntervalSet<T> {
47    /// Converts the interval set to a string representation.
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use timekeep_rs::AtomicInterval;
53    /// use timekeep_rs::IntervalSet;
54    ///
55    /// let interval = IntervalSet::from(AtomicInterval::closed(1, 5));
56    /// assert_eq!(interval.to_string(), "[[1, 5]]");
57    /// ```
58    fn to_string(&self) -> String {
59        let mut result = String::from("[");
60        for interval in &self.intervals {
61            result.push_str(&interval.to_string());
62        }
63        result.push_str("]");
64        result
65    }
66    
67}
68
69impl<T: Clone> IntervalSet<T> {
70    /// Returns `true` if this interval set has no intervals or is empty.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use timekeep_rs::IntervalSet;
76    ///
77    /// // Suppose `interval` is an `Interval` with no intervals.
78    /// let interval = IntervalSet::<i32> { intervals: vec![] };
79    ///
80    /// assert!(interval.is_empty());
81    /// ```
82    pub fn is_empty(&self) -> bool {
83        self.intervals.is_empty()
84    }
85
86    /// Returns an empty `IntervalSet`.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// use timekeep_rs::IntervalSet;
92    ///
93    /// // Suppose `interval` is an `Interval` with no intervals.
94    /// let interval = IntervalSet::<i32>::new();
95    ///
96    /// assert!(interval.is_empty());
97    /// ```
98    pub fn new() -> IntervalSet<T> {
99        return IntervalSet { intervals: vec![] }
100    }
101
102}
103
104impl<T: Clone> From<AtomicInterval<T>> for IntervalSet<T> {
105    /// Creates a new `IntervalSet<T>` from an `AtomicInterval<T>`.
106    ///
107    /// This implementation allows converting a single atomic interval into an `IntervalSet<T>`
108    /// collection by wrapping it in a vector.
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// use timekeep_rs::AtomicInterval;
114    /// use timekeep_rs::IntervalSet;
115    ///
116    /// let atomic = AtomicInterval::closed(1, 5);
117    /// let interval: IntervalSet<i32> = atomic.into();
118    /// ```
119    fn from(interval: AtomicInterval<T>) -> Self {
120        IntervalSet {
121            intervals: vec![interval],
122        }
123    }
124}
125
126/// A trait implementation for `IntervalSet<T>` where `T` implements `PartialOrd` and `Clone`.
127/// Provides set operations for interval sets.
128impl<T: PartialOrd + Clone> IntervalSet<T> {
129    /// Computes the union of two interval sets.
130    ///
131    /// The union of two interval sets is a new interval set that contains all the intervals
132    /// from both input sets, merging any overlapping or adjacent intervals.
133    ///
134    /// # Arguments
135    ///
136    /// * `other` - Another interval set to compute the union with
137    ///
138    /// # Returns
139    ///
140    /// A new `IntervalSet<T>` representing the union of both interval sets
141    ///
142    /// # Examples
143    ///
144    /// ```
145    /// use timekeep_rs::AtomicInterval;
146    /// use timekeep_rs::IntervalSet;
147    ///
148    /// // Create two interval sets
149    /// let interval1 = IntervalSet::from(AtomicInterval::closed(1, 5));
150    /// let interval2 = IntervalSet::from(AtomicInterval::closed(3, 7));
151    ///
152    /// // Compute union (results in [1, 7])
153    /// let union = interval1.union(&interval2);
154    /// ```
155    pub fn union(&self, other: &Self) -> Self {
156        let mut intervals = self.intervals.clone();
157        intervals.extend(other.intervals.iter().cloned());
158
159        // Sort intervals by the value of their left boundary.
160        intervals.sort_by(
161            |a, b| a.left().value().partial_cmp(b.left().value()).unwrap()
162        );
163
164        let mut merged: Vec<AtomicInterval<T>> = Vec::new();
165
166        for interval in intervals {
167            if let Some(last) = merged.last_mut() {
168                let union_vec = AtomicInterval::union(last, &interval);
169    
170                if union_vec.len() == 1 {
171                    // Successfully merged, update last interval
172                    *last = union_vec.into_iter().next().unwrap();
173                    continue;
174                } else if union_vec.len() > 1 {
175                    // If union() returned multiple intervals, replace last and insert the new one
176                    *last = union_vec[0].clone();
177                    merged.extend(union_vec.into_iter().skip(1));
178                    continue;
179                }
180            }
181            merged.push(interval);
182        }
183
184        IntervalSet { intervals: merged }
185    }
186
187    /// Computes the intersection of two interval sets.
188    ///
189    /// The intersection of two interval sets is a new interval set that contains all the intervals
190    /// that are common to both input sets.
191    ///
192    /// # Arguments
193    ///
194    /// * `other` - Another interval set to compute the intersection with
195    ///
196    /// # Returns
197    ///
198    /// * `Some(IntervalSet<T>)` if the interval sets intersect
199    /// * `None` if the interval sets are disjoint
200    ///
201    /// # Examples
202    ///
203    /// ```
204    /// use timekeep_rs::AtomicInterval;
205    /// use timekeep_rs::IntervalSet;
206    ///
207    /// // Create two interval sets
208    /// let interval1 = IntervalSet::from(AtomicInterval::closed(1, 5));
209    /// let interval2 = IntervalSet::from(AtomicInterval::closed(3, 7));
210    ///
211    /// // Compute intersection (results in [3, 5])
212    /// let intersection = interval1.intersection(&interval2);
213    /// ```
214    pub fn intersection(&self, other: &Self) -> Self {
215        let mut intervals = Vec::new();
216
217        for interval in &self.intervals {
218            for other_interval in &other.intervals {
219                interval.intersection(other_interval).iter().for_each(
220                    |x| intervals.push(x.clone())
221                );
222                // if intersection_vec.len() > 1 {
223                //     panic!("Unexpected behavior from intersection.")
224                // } else if intersection_vec.len() == 1 {
225                //     intervals.push(intersection);
226
227                // }
228                // if let Some(intersection) = interval.intersection(other_interval) {
229                //     intervals.push(intersection);
230                // }
231            }
232        }
233
234        if intervals.is_empty() {
235            IntervalSet::new()
236        } else {
237            IntervalSet { intervals }
238        }
239    }
240
241    /// Computes the difference between two interval sets.
242    ///
243    /// The difference A - B contains all points that are in A but not in B.
244    ///
245    /// # Arguments
246    ///
247    /// * `other` - Another interval set to subtract from this interval set
248    ///
249    /// # Returns
250    ///
251    /// A new `IntervalSet<T>` representing the difference between the interval sets
252    ///
253    /// # Examples
254    ///
255    /// ```
256    /// use timekeep_rs::AtomicInterval;
257    /// use timekeep_rs::IntervalSet;
258    ///
259    /// // Create two interval sets
260    /// let interval1 = IntervalSet::from(AtomicInterval::closed(1, 5));
261    /// let interval2 = IntervalSet::from(AtomicInterval::closed(3, 7));
262    ///
263    /// // Compute difference (results in [1, 3))
264    /// let difference = interval1.difference(&interval2);
265    /// ```
266    pub fn difference(&self, other: &Self) -> Self {
267        let mut result = Vec::new();
268
269        for interval in &self.intervals {
270            let mut remaining = vec![interval.clone()];
271            for other_interval in &other.intervals {
272                let mut new_remaining = Vec::new();
273                for part in remaining {
274                    new_remaining.extend(part.difference(other_interval));
275                }
276                remaining = new_remaining;
277            }
278            result.extend(remaining);
279        }
280
281        IntervalSet { intervals: result }
282    }
283}
284
285#[cfg(test)]
286mod tests {
287    use super::*;
288
289    #[test]
290    fn test_interval_from_atomic_interval() {
291        let atomic_interval = AtomicInterval::closed(1, 5);
292        let interval_set: IntervalSet<i32> = IntervalSet::from(atomic_interval.clone());
293        assert_eq!(interval_set.intervals.len(), 1);
294        assert_eq!(interval_set.intervals[0], atomic_interval);
295    }
296
297    #[test]
298    fn test_union_between_two_overlapping_intervals() {
299        let interval1 = AtomicInterval::closed(1, 3);
300        let interval2 = AtomicInterval::closed(4, 7);
301        let interval3 = AtomicInterval::closed(2, 4);
302        let interval4 = AtomicInterval::closed(7, 8);
303        let union = IntervalSet::from(interval1).union(&IntervalSet::from(interval2));
304        let union = union.union(&IntervalSet::from(interval3));
305        let union = union.union(&IntervalSet::from(interval4));
306        assert_eq!(union.intervals.len(), 1);
307        assert_eq!(union.intervals[0], AtomicInterval::closed(1, 8));
308    }
309
310    #[test]
311    fn test_union_between_two_disjoint_intervals() {
312        let interval1 = AtomicInterval::closed(1, 3);
313        let interval2 = AtomicInterval::closed(4, 7);
314        let interval3 = AtomicInterval::closed(5, 8);
315        let union = IntervalSet::from(interval1).union(&IntervalSet::from(interval2));
316        let union = union.union(&IntervalSet::from(interval3));
317        assert_eq!(union.intervals.len(), 2);
318        assert_eq!(union.intervals[0], AtomicInterval::closed(1, 3));
319        assert_eq!(union.intervals[1], AtomicInterval::closed(4, 8));
320    }
321
322    #[test]
323    fn test_intersection_between_two_overlapping_intervals() {
324        let interval1 = AtomicInterval::closed(1, 5);
325        let interval2 = AtomicInterval::closed(3, 7);
326        let interval1 = IntervalSet::from(interval1);
327        let interval2 = IntervalSet::from(interval2);
328        let intersection = interval1.intersection(&interval2);
329        assert_eq!(intersection.intervals.len(), 1);
330        assert_eq!(intersection.intervals[0], AtomicInterval::closed(3, 5));
331    }
332
333    #[test]
334    fn test_intersection_between_two_disjoint_intervals() {
335        let interval1 = AtomicInterval::closed(1, 3);
336        let interval2 = AtomicInterval::closed(4, 7);
337        let interval1 = IntervalSet::from(interval1);
338        let interval2 = IntervalSet::from(interval2);
339        let intersection = interval1.intersection(&interval2);
340        assert!(intersection.is_empty());
341    }
342
343    #[test]
344    fn test_difference_between_two_overlapping_intervals() {
345        let interval1 = AtomicInterval::closed(1, 5);
346        let interval2 = AtomicInterval::closed(3, 7);
347        let interval1 = IntervalSet::from(interval1);
348        let interval2 = IntervalSet::from(interval2);
349        let difference = interval1.difference(&interval2);
350        assert_eq!(difference.intervals.len(), 1);
351        assert_eq!(difference.intervals[0], AtomicInterval::closed_open(1, 3));
352    }
353
354    #[test]
355    fn test_difference_between_two_disjoint_intervals() {
356        let interval1 = AtomicInterval::closed(1, 3);
357        let interval2 = AtomicInterval::closed(4, 7);
358        let interval1 = IntervalSet::from(interval1);
359        let interval2 = IntervalSet::from(interval2);
360        let difference = interval1.difference(&interval2);
361        assert_eq!(difference.intervals.len(), 1);
362        assert_eq!(difference.intervals[0], AtomicInterval::closed(1, 3));
363    }
364}