flatk/chunked/sparse.rs
1//! This module defines functions specific to `Chunked<Sparse<_>>` types
2use super::*;
3use crate::select::{AsIndexSlice, AsIndexSliceMut};
4use crate::Sparse;
5
6impl<'a, S, T, I, O> Chunked<Sparse<S, T, I>, Offsets<O>>
7where
8 I: Dummy + AsIndexSliceMut,
9 T: Dummy + Set + View<'a>,
10 <T as View<'a>>::Type: Set + Clone + Dummy,
11 S: Dummy + Set + ViewMut<'a>,
12 <S as ViewMut<'a>>::Type: Set + SplitAt + Dummy + PermuteInPlace,
13 O: Clone + AsRef<[usize]>,
14{
15 /// Sort each sparse chunk by the source index.
16 ///
17 /// # Example
18 ///
19 /// ```
20 /// use flatk::*;
21 /// let sparse = Sparse::from_dim(vec![0,2,1,2,0], 4, vec![1,2,3,4,5]);
22 /// let mut chunked = Chunked::from_sizes(vec![3,2], sparse);
23 /// chunked.sort_chunks_by_index();
24 /// assert_eq!(chunked.storage(), &[1,3,2,5,4]);
25 /// assert_eq!(chunked.data().indices(), &[0,1,2,0,2]);
26 /// ```
27 pub fn sort_chunks_by_index(&'a mut self) {
28 let mut indices = vec![0; self.data.selection.indices.as_mut().len()];
29 let mut seen = vec![false; indices.len()];
30 let mut chunked_workspace = Chunked {
31 chunks: self.chunks.clone(),
32 data: (indices.as_mut_slice(), seen.as_mut_slice()),
33 };
34
35 for ((permutation, seen), mut chunk) in chunked_workspace.iter_mut().zip(self.iter_mut()) {
36 // Initialize permutation
37 (0..permutation.len())
38 .zip(permutation.iter_mut())
39 .for_each(|(i, out)| *out = i);
40
41 // Sort the permutation according to selection indices.
42 chunk.selection.indices.sort_indices(permutation);
43
44 // Apply the result of the sort (i.e. the permutation) to the whole chunk.
45 chunk.permute_in_place(permutation, seen);
46 }
47 }
48}
49
50impl<'a, S, T, I, O> Chunked<Sparse<S, T, I>, Offsets<O>>
51where
52 S: Storage + IntoOwned + Set + View<'a>,
53 S::Storage: Set,
54 <S as View<'a>>::Type: SplitAt + Dummy + Set,
55 T: View<'a> + Set + Clone,
56 <T as View<'a>>::Type: Set + Dummy + Clone,
57 I: AsIndexSlice,
58 O: Set + AsRef<[usize]>,
59{
60 /// Combine elements in each sorted chunk with the same index using the given function.
61 ///
62 /// Assuming that the chunks are sorted by index, this function will combine adjacent
63 /// elements with the same index into one element.
64 ///
65 /// # Example
66 ///
67 /// ```
68 /// use flatk::*;
69 /// let sparse = Sparse::from_dim(vec![0,2,1,1,2,0,2], 4, vec![1,2,3,4,5,6,7]);
70 /// let mut chunked = Chunked::from_sizes(vec![4,3], sparse);
71 /// chunked.sort_chunks_by_index();
72 /// let compressed = chunked.compressed(|a, b| *a += *b);
73 /// assert_eq!(compressed.view().offsets().into_inner(), &[0,3,5]);
74 /// assert_eq!(compressed.view().storage(), &[1,7,2,6,12]);
75 /// assert_eq!(compressed.view().data().indices(), &[0,1,2,0,2]);
76 /// ```
77 pub fn compressed<E>(
78 &'a self,
79 mut combine: impl FnMut(&mut E::Owned, E),
80 ) -> Chunked<Sparse<S::Owned, T>, Offsets>
81 where
82 <S as View<'a>>::Type: IntoIterator<Item = E>,
83 E: IntoOwned,
84 S::Owned: Set<Elem = E::Owned> + Default + Reserve + Push<E::Owned>,
85 {
86 self.pruned(&mut combine, |_, _, _| true, |_, _| {})
87 }
88}
89
90impl<'a, S, T, I, O> Chunked<Sparse<S, T, I>, Offsets<O>>
91where
92 S: Storage + IntoOwned + Set + View<'a>,
93 S::Storage: Set,
94 <S as View<'a>>::Type: SplitAt + Dummy + Set,
95 T: View<'a> + Set + Clone,
96 <T as View<'a>>::Type: Set + Dummy + Clone,
97 I: AsIndexSlice,
98 O: Set + AsRef<[usize]>,
99{
100 /// Prune elements according to a given predicate and combine them in each
101 /// sorted chunk with the same index.
102 ///
103 /// Assuming that the chunks are sorted by index, this function will combine adjacent
104 /// elements with the same index into one element.
105 ///
106 /// This is a more general version of `compressed` that allows you to prune unwanted elements.
107 /// In addition the `combine` and `keep` functions get an additional target
108 /// index where each element will be written to.
109 ///
110 /// # Examples
111 ///
112 /// A simple example.
113 ///
114 /// ```
115 /// use flatk::*;
116 /// let sparse = Sparse::from_dim(vec![0,2,1,1,2,0,2], 4, vec![1.0, 2.0, 0.1, 0.01, 5.0, 0.001, 7.0]);
117 /// let mut chunked = Chunked::from_sizes(vec![4,3], sparse);
118 /// chunked.sort_chunks_by_index();
119 /// let pruned = chunked.pruned(|a, b| *a += *b, |_, _, &val| val > 0.01, |_,_| {});
120 /// assert_eq!(pruned.view().offsets().into_inner(), &[0,3,4]);
121 /// assert_eq!(pruned.view().storage(), &[1.0, 0.11, 2.0, 12.0]); // 0.001 is pruned.
122 /// assert_eq!(pruned.view().data().indices(), &[0,1,2,2]);
123 /// ```
124 ///
125 /// The following example extends on the previous example but shows how one
126 /// may construct a mapping from original elements to the pruned output.
127 ///
128 /// ```
129 /// use flatk::*;
130 /// let indices = vec![0, 2, 1, 1, 2, 0, 2];
131 /// let num_indices = indices.len();
132 /// let sparse = Sparse::from_dim(indices, 4, vec![1.0, 2.0, 0.1, 0.01, 5.0, 0.001, 7.0]);
133 /// let mut chunked = Chunked::from_sizes(vec![4,3], sparse);
134 /// chunked.sort_chunks_by_index();
135 /// let mut mapping = vec![None; num_indices];
136 /// let pruned = chunked.pruned(|a, b| {
137 /// *a += *b
138 /// }, |_, _, &val| {
139 /// val > 0.01
140 /// }, |src, dst| mapping[src] = Some(dst));
141 ///
142 /// // As before, the resulting structure is pruned.
143 /// assert_eq!(pruned.view().offsets().into_inner(), &[0,3,4]);
144 /// assert_eq!(pruned.view().storage(), &[1.0, 0.11, 2.0, 12.0]); // 0.001 is pruned.
145 /// assert_eq!(pruned.view().data().indices(), &[0,1,2,2]);
146 /// assert_eq!(mapping, vec![Some(0), Some(1), Some(1), Some(2), None, Some(3), Some(3)]);
147 /// ```
148 pub fn pruned<E>(
149 &'a self,
150 mut combine: impl FnMut(&mut E::Owned, E),
151 mut keep: impl FnMut(usize, usize, &E::Owned) -> bool,
152 mut map: impl FnMut(usize, usize),
153 ) -> Chunked<Sparse<S::Owned, T>, Offsets>
154 where
155 <S as View<'a>>::Type: IntoIterator<Item = E>,
156 E: IntoOwned,
157 S::Owned: Set<Elem = E::Owned> + Default + Reserve + Push<E::Owned>,
158 {
159 // Initialize and allocate all output types.
160 let mut data: <S as IntoOwned>::Owned = Default::default();
161 data.reserve_with_storage(self.data.len(), self.storage().len());
162 let mut indices = Vec::new();
163 indices.reserve(self.data.selection.len());
164 let mut sparse = Sparse::new(
165 Select::new(indices, self.data.selection.target.clone()),
166 data,
167 );
168
169 let mut offsets = Vec::with_capacity(self.chunks.num_offsets());
170 offsets.push(0);
171
172 for (i, sparse_chunk) in self.iter().enumerate() {
173 sparse.extend_pruned(
174 sparse_chunk,
175 |_pos, a, b| combine(a, b),
176 |j, e| keep(i, j, e),
177 |src, dst| map(src + self.offset(i), dst),
178 );
179 offsets.push(sparse.len());
180 }
181
182 // Assemble the output type from constructed parts.
183 Chunked::from_offsets(offsets, sparse)
184 }
185}