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}