Skip to main content

ruda_dataset/transform/
window.rs

1use std::{cmp::max, marker::PhantomData, num::NonZeroUsize};
2
3use crate::Dataset;
4
5/// Functionality to create a window.
6pub trait Window<I> {
7    /// Creates a window of a collection.
8    ///
9    /// # Returns
10    ///
11    /// A `Vec<I>` representing the window.
12    fn window(&self, current: usize, size: NonZeroUsize) -> Option<Vec<I>>;
13}
14
15impl<I, T: Dataset<I> + ?Sized> Window<I> for T {
16    fn window(&self, current: usize, size: NonZeroUsize) -> Option<Vec<I>> {
17        (current..current + size.get())
18            .map(|x| self.get(x))
19            .collect()
20    }
21}
22
23/// Functionality to create a `WindowsIterator`.
24pub trait Windows<I> {
25    /// Creates and returns an iterator over all the windows of length `size`.
26    fn windows(&self, size: usize) -> WindowsIterator<'_, I>;
27}
28
29impl<I, T: Dataset<I>> Windows<I> for T {
30    /// Is empty if the `Dataset` is shorter than `size`.
31    ///
32    /// # Panics
33    ///
34    /// Panics if `size` is 0.    
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use crate::ruda_dataset::{
40    ///    transform::{Windows, WindowsDataset},
41    ///    Dataset, InMemDataset,
42    /// };
43    ///
44    /// let items = [1, 2, 3, 4].to_vec();
45    /// let dataset = InMemDataset::new(items.clone());
46    ///
47    /// for window in dataset.windows(2) {
48    ///  // do sth with window
49    /// }
50    /// ```
51    fn windows(&self, size: usize) -> WindowsIterator<'_, I> {
52        let size = NonZeroUsize::new(size).expect("window size must be non-zero");
53        WindowsIterator::new(self, size)
54    }
55}
56
57/// Overlapping windows iterator.
58pub struct WindowsIterator<'a, I> {
59    /// The size of the windows.
60    pub size: NonZeroUsize,
61    current: usize,
62    dataset: &'a dyn Dataset<I>,
63}
64
65impl<'a, I> WindowsIterator<'a, I> {
66    /// Creates a new `WindowsIterator` instance. The windows overlap.
67    /// Is empty if the input `Dataset` is shorter than `size`.
68    ///
69    /// # Parameters
70    ///
71    /// - `dataset`: The dataset over which windows will be created.
72    /// - `size`: The size of the windows.
73    pub fn new(dataset: &'a dyn Dataset<I>, size: NonZeroUsize) -> Self {
74        WindowsIterator {
75            current: 0,
76            dataset,
77            size,
78        }
79    }
80}
81
82impl<I> Iterator for WindowsIterator<'_, I> {
83    type Item = Vec<I>;
84
85    fn next(&mut self) -> Option<Vec<I>> {
86        self.current += 1;
87        self.dataset.window(self.current - 1, self.size)
88    }
89}
90
91impl<I> Clone for WindowsIterator<'_, I> {
92    fn clone(&self) -> Self {
93        WindowsIterator {
94            size: self.size,
95            dataset: self.dataset,
96            current: self.current,
97        }
98    }
99}
100
101/// Dataset designed to work with overlapping windows of data.
102pub struct WindowsDataset<D, I> {
103    /// The size of the windows.
104    pub size: NonZeroUsize,
105    dataset: D,
106    input: PhantomData<I>,
107}
108
109impl<D, I> WindowsDataset<D, I>
110where
111    D: Dataset<I>,
112{
113    /// Creates a new `WindowsDataset` instance. The windows overlap.
114    /// Is empty if the input `Dataset` is shorter than `size`.
115    ///
116    /// # Parameters
117    ///
118    /// - `dataset`: The dataset over which windows will be created.
119    /// - `size`: The size of the windows.
120    pub fn new(dataset: D, size: usize) -> Self
121    where
122        D:,
123    {
124        let size = NonZeroUsize::new(size).expect("window size must be non-zero");
125        WindowsDataset::<D, I> {
126            size,
127            dataset,
128            input: PhantomData,
129        }
130    }
131}
132
133impl<D, I> Dataset<Vec<I>> for WindowsDataset<D, I>
134where
135    D: Dataset<I>,
136    I: Send + Sync,
137{
138    /// Retrieves a window of items from the dataset.
139    ///
140    /// # Parameters
141    ///
142    /// - `index`: The index of the window.
143    ///
144    /// # Returns
145    ///
146    /// A vector representing the window.
147    fn get(&self, index: usize) -> Option<Vec<I>> {
148        self.dataset.window(index, self.size)
149    }
150
151    fn get_many(&self, indices: &[usize]) -> Option<Vec<Vec<I>>> {
152        let mut windows = Vec::with_capacity(indices.len());
153        let mut read_indices = Vec::new();
154        for &index in indices {
155            read_indices.clear();
156            read_indices.extend(index..index + self.size.get());
157            let window = self.dataset.get_many(&read_indices)?;
158            if window.len() != read_indices.len() {
159                return None;
160            }
161            windows.push(window);
162        }
163        Some(windows)
164    }
165
166    /// Retrieves the number of windows in the dataset.
167    ///
168    /// # Returns
169    ///
170    /// A size representing the number of windows.
171    fn len(&self) -> usize {
172        let len = self.dataset.len() as isize - self.size.get() as isize + 1;
173        max(len, 0) as usize
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use rstest::rstest;
180
181    use crate::{
182        Dataset, InMemDataset,
183        transform::{Windows, WindowsDataset},
184    };
185
186    #[rstest]
187    pub fn windows_should_be_equal_to_vec_windows() {
188        let items = [1, 2, 3, 4, 5].to_vec();
189        let dataset = InMemDataset::new(items.clone());
190        let expected = items
191            .windows(3)
192            .map(|x| x.to_vec())
193            .collect::<Vec<Vec<i32>>>();
194
195        let result = dataset.windows(3).collect::<Vec<Vec<i32>>>();
196
197        assert_eq!(result, expected);
198    }
199
200    #[rstest]
201    pub fn windows_dataset_should_be_equal_to_vec_windows() {
202        let items = [1, 2, 3, 4, 5].to_vec();
203        let dataset = InMemDataset::new(items.clone());
204        let expected = items
205            .windows(3)
206            .map(|x| x.to_vec())
207            .collect::<Vec<Vec<i32>>>();
208
209        let result = WindowsDataset::new(dataset, 3)
210            .iter()
211            .collect::<Vec<Vec<i32>>>();
212
213        assert_eq!(result, expected);
214    }
215
216    #[rstest]
217    pub fn cloned_iterator_should_be_equal() {
218        let items = [1, 2, 3, 4, 5].to_vec();
219        let dataset = InMemDataset::new(items.clone());
220        let original = dataset.windows(4);
221
222        let cloned = original.clone();
223
224        assert!(std::ptr::eq(cloned.dataset, original.dataset));
225        assert_eq!(cloned.size, original.size);
226        assert_eq!(cloned.current, original.current);
227    }
228
229    #[rstest]
230    pub fn cloned_iterator_should_be_unaffected() {
231        let items = [1, 2, 3, 4, 5].to_vec();
232        let dataset = InMemDataset::new(items.clone());
233        let mut original = dataset.windows(4);
234
235        let cloned = original.clone();
236        original.current = 2;
237
238        assert_ne!(cloned.current, original.current);
239    }
240
241    #[rstest]
242    #[should_panic(expected = "window size must be non-zero")]
243    pub fn windows_should_panic() {
244        let items = [1, 2].to_vec();
245        let dataset = InMemDataset::new(items.clone());
246
247        dataset.windows(0);
248    }
249
250    #[rstest]
251    #[should_panic(expected = "window size must be non-zero")]
252    pub fn new_window_dataset_should_panic() {
253        let items = [1, 2].to_vec();
254        let dataset = InMemDataset::new(items.clone());
255
256        WindowsDataset::new(dataset, 0);
257    }
258
259    #[rstest]
260    pub fn window_dataset_len_should_be_equal() {
261        let dataset = InMemDataset::new([1, 2, 3, 4].to_vec());
262
263        let result = WindowsDataset::new(dataset, 2).len();
264
265        assert_eq!(result, 3);
266    }
267
268    #[rstest]
269    pub fn window_iterator_should_be_empty() {
270        let dataset = InMemDataset::new([1, 2].to_vec());
271        let mut peekable = dataset.windows(4).peekable();
272
273        let result = peekable.peek();
274
275        assert_eq!(result, None);
276    }
277
278    #[rstest]
279    pub fn window_dataset_len_should_be_zero() {
280        let dataset = InMemDataset::new([1, 2].to_vec());
281
282        let result = WindowsDataset::new(dataset, 4).len();
283
284        assert_eq!(result, 0);
285    }
286
287    #[rstest]
288    pub fn window_dataset_get_should_be_equal() {
289        let dataset = InMemDataset::new([1, 2, 3, 4].to_vec());
290        let expected = Some([1, 2, 3].to_vec());
291
292        let result = WindowsDataset::new(dataset, 3).get(0);
293
294        assert_eq!(result, expected);
295    }
296
297    #[rstest]
298    pub fn window_dataset_get_should_be_none() {
299        let dataset = InMemDataset::new([1, 2].to_vec());
300
301        let result = WindowsDataset::new(dataset, 4).get(0);
302
303        assert_eq!(result, None);
304    }
305}