data_beans/sparse_io_vector/
read.rs1#![allow(dead_code)]
2
3use super::*;
4
5impl SparseIoVec {
6 pub(super) fn read_column_offset(
18 &self,
19 glob: usize,
20 col_offset: &mut usize,
21 triplets: &mut Vec<(u64, u64, f32)>,
22 ) -> anyhow::Result<()> {
23 let off = *col_offset as u64;
24 let g2c = self.global_to_compact_row.as_slice();
25 for source in self.col_to_data[glob].iter() {
26 let didx = source.backend as usize;
27 let loc = source.local_col as usize;
28 let (_, _, loc_triplets) = self.data_vec[didx].read_triplets_by_single_column(loc)?;
29 let l2g = self.data_local_to_global_row[didx].as_slice();
30 for (i, _j, v) in loc_triplets {
31 if let Some(c) = g2c[l2g[i as usize]] {
32 triplets.push((c as u64, off, v));
33 }
34 }
35 }
36 *col_offset += 1;
37 Ok(())
38 }
39
40 pub fn for_each_triplet<I, F>(
53 &self,
54 cells: I,
55 chunk_cols: usize,
56 mut f: F,
57 ) -> anyhow::Result<(usize, usize)>
58 where
59 I: Iterator<Item = usize>,
60 F: FnMut(u64, u64, f32),
61 {
62 let nrow = self.num_rows();
63 let cells: Vec<usize> = cells.collect();
64 let ncol = cells.len();
65 let chunk = chunk_cols.max(1);
66 let g2c = self.global_to_compact_row.as_slice();
67
68 for slab_start in (0..ncol).step_by(chunk) {
69 let slab_end = (slab_start + chunk).min(ncol);
70
71 let mut backend_groups: HashMap<usize, Vec<(usize, usize)>> = HashMap::default();
78 for (k, &glob) in cells[slab_start..slab_end].iter().enumerate() {
79 let out_col = slab_start + k;
80 for source in self.col_to_data[glob].iter() {
81 backend_groups
82 .entry(source.backend as usize)
83 .or_default()
84 .push((source.local_col as usize, out_col));
85 }
86 }
87
88 for (&didx, group) in &backend_groups {
89 let local_cols: Vec<usize> = group.iter().map(|&(loc, _)| loc).collect();
90 let (_, _, group_triplets) =
91 self.data_vec[didx].read_triplets_by_columns(local_cols)?;
92
93 let l2g = self.data_local_to_global_row[didx].as_slice();
94 if self.data_has_intra_row_merges[didx] {
95 let mut acc: HashMap<(u64, u64), f32> = HashMap::default();
101 for (i, j, v) in group_triplets {
102 if let Some(c) = g2c[l2g[i as usize]] {
103 let out_col = group[j as usize].1 as u64;
104 *acc.entry((c as u64, out_col)).or_insert(0.0) += v;
105 }
106 }
107 for ((r, c), v) in acc {
108 f(r, c, v);
109 }
110 } else {
111 for (i, j, v) in group_triplets {
112 if let Some(c) = g2c[l2g[i as usize]] {
113 let out_col = group[j as usize].1 as u64;
114 f(c as u64, out_col, v);
115 }
116 }
117 }
118 }
119 }
120
121 Ok((nrow, ncol))
122 }
123
124 #[allow(clippy::type_complexity)]
130 pub fn columns_triplets<I>(
131 &self,
132 cells: I,
133 ) -> anyhow::Result<((usize, usize), Vec<(u64, u64, f32)>)>
134 where
135 I: Iterator<Item = usize>,
136 {
137 let cells: Vec<usize> = cells.collect();
138 let one_slab = cells.len().max(1);
139 let mut triplets = Vec::new();
140 let dims = self.for_each_triplet(cells.into_iter(), one_slab, |r, c, v| {
141 triplets.push((r, c, v));
142 })?;
143 Ok((dims, triplets))
144 }
145
146 pub fn read_columns_ndarray<I>(&self, cells: I) -> anyhow::Result<ndarray::Array2<f32>>
147 where
148 I: Iterator<Item = usize>,
149 {
150 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
151 ndarray::Array2::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
152 }
153
154 pub fn read_columns_dmatrix<I>(&self, cells: I) -> anyhow::Result<nalgebra::DMatrix<f32>>
155 where
156 I: Iterator<Item = usize>,
157 {
158 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
159 DMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
160 }
161
162 pub fn read_columns_csc<I>(&self, cells: I) -> anyhow::Result<CscMatrix<f32>>
173 where
174 I: Iterator<Item = usize>,
175 {
176 let cells: Vec<usize> = cells.collect();
177 let nrow = self.num_rows();
178 let ncol = cells.len();
179
180 let mut backend_groups: Vec<Vec<(usize, usize)>> =
187 (0..self.data_vec.len()).map(|_| Vec::new()).collect();
188 for (out_col, &glob) in cells.iter().enumerate() {
189 for source in self.col_to_data[glob].iter() {
190 backend_groups[source.backend as usize].push((source.local_col as usize, out_col));
191 }
192 }
193
194 let mut buckets: Vec<Vec<(u32, f32)>> = (0..ncol).map(|_| Vec::new()).collect();
196 let g2c = self.global_to_compact_row.as_slice();
197
198 for (didx, group) in backend_groups.iter().enumerate() {
199 if group.is_empty() {
200 continue;
201 }
202 let l2g = self.data_local_to_global_row[didx].as_slice();
203
204 if let Some((indptr, indices, values)) = self.data_vec[didx].csc_column_arrays() {
205 for &(loc, out_col) in group {
207 if loc + 1 >= indptr.len() {
208 continue;
209 }
210 let s = indptr[loc] as usize;
211 let e = indptr[loc + 1] as usize;
212 let bucket = &mut buckets[out_col];
213 bucket.reserve(e - s);
214 for k in s..e {
215 let local_row = indices[k] as usize;
216 if let Some(c) = g2c[l2g[local_row]] {
217 bucket.push((c as u32, values[k]));
218 }
219 }
220 }
221 } else {
222 let cols: Vec<usize> = group.iter().map(|&(loc, _)| loc).collect();
229 let (_, _, trip) = self.data_vec[didx].read_triplets_by_columns(cols)?;
230 for (i, jj, v) in trip {
231 let (_, out_col) = group[jj as usize];
232 if let Some(c) = g2c[l2g[i as usize]] {
233 buckets[out_col].push((c as u32, v));
234 }
235 }
236 }
237 }
238
239 let total_nnz: usize = buckets.iter().map(|b| b.len()).sum();
241 let mut col_offsets: Vec<usize> = Vec::with_capacity(ncol + 1);
242 let mut row_indices: Vec<usize> = Vec::with_capacity(total_nnz);
243 let mut values: Vec<f32> = Vec::with_capacity(total_nnz);
244 col_offsets.push(0);
245
246 for bucket in &mut buckets {
247 let strictly_sorted_unique = bucket.windows(2).all(|w| w[0].0 < w[1].0);
259 if !strictly_sorted_unique {
260 bucket.sort_by_key(|&(r, _)| r);
261 let mut write = 0usize;
263 let mut read = 0usize;
264 while read < bucket.len() {
265 let (r, mut v) = bucket[read];
266 read += 1;
267 while read < bucket.len() && bucket[read].0 == r {
268 v += bucket[read].1;
269 read += 1;
270 }
271 bucket[write] = (r, v);
272 write += 1;
273 }
274 bucket.truncate(write);
275 }
276 for &(r, v) in bucket.iter() {
277 row_indices.push(r as usize);
278 values.push(v);
279 }
280 col_offsets.push(row_indices.len());
281 }
282
283 CscMatrix::try_from_csc_data(nrow, ncol, col_offsets, row_indices, values)
284 .map_err(|e| anyhow::anyhow!("CSC construction failed: {:?}", e))
285 }
286
287 pub fn read_columns_csr<I>(&self, cells: I) -> anyhow::Result<CsrMatrix<f32>>
288 where
289 I: Iterator<Item = usize>,
290 {
291 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
292 nalgebra_sparse::CsrMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
293 }
294
295 pub fn read_columns_tensor<I>(&self, cells: I) -> anyhow::Result<Tensor>
296 where
297 I: Iterator<Item = usize>,
298 {
299 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
300 Tensor::from_nonzero_triplets(nrow, ncol, &triplets)
301 }
302
303 #[allow(clippy::type_complexity)]
308 pub fn rows_triplets<I>(
309 &self,
310 rows: I,
311 ) -> anyhow::Result<((usize, usize), Vec<(u64, u64, f32)>)>
312 where
313 I: Iterator<Item = usize>,
314 {
315 let rows_compact: Vec<usize> = rows.collect();
316 let nrow_out = rows_compact.len();
317 let ncol_out = self.num_columns();
318
319 let n_compact = self.cached_num_rows;
320 let compact_to_global = self.compact_to_global_row.as_slice();
321
322 let mut triplets: Vec<(u64, u64, f32)> = Vec::new();
323 let mut local_to_out: Vec<usize> = Vec::with_capacity(rows_compact.len());
324 for didx in 0..self.data_vec.len() {
325 let g2l = &self.data_global_to_local_row[didx];
326
327 local_to_out.clear();
328 let mut local_rows: Vec<usize> = Vec::with_capacity(rows_compact.len());
329 for (out_row, &c) in rows_compact.iter().enumerate() {
330 if c >= n_compact {
331 continue;
332 }
333 let g = compact_to_global[c];
334 if let Some(&l) = g2l.get(&g) {
335 local_rows.push(l);
336 local_to_out.push(out_row);
337 }
338 }
339 if local_rows.is_empty() {
340 continue;
341 }
342
343 let (_, _, group_triplets) = self.data_vec[didx].read_triplets_by_rows(local_rows)?;
344 let cols_map = self
345 .data_to_cols
346 .get(&didx)
347 .ok_or_else(|| anyhow::anyhow!("missing data_to_cols entry for didx {}", didx))?;
348 triplets.reserve(group_triplets.len());
349 for (i, j, v) in group_triplets {
350 let mapped = cols_map[j as usize];
352 if mapped == usize::MAX {
353 continue;
354 }
355 let out_row = local_to_out[i as usize] as u64;
356 let out_col = mapped as u64;
357 triplets.push((out_row, out_col, v));
358 }
359 }
360
361 Ok(((nrow_out, ncol_out), triplets))
362 }
363
364 pub fn read_rows_ndarray<I>(&self, rows: I) -> anyhow::Result<ndarray::Array2<f32>>
365 where
366 I: Iterator<Item = usize>,
367 {
368 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
369 ndarray::Array2::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
370 }
371
372 pub fn read_rows_dmatrix<I>(&self, rows: I) -> anyhow::Result<nalgebra::DMatrix<f32>>
373 where
374 I: Iterator<Item = usize>,
375 {
376 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
377 DMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
378 }
379
380 pub fn read_rows_csc<I>(&self, rows: I) -> anyhow::Result<CscMatrix<f32>>
381 where
382 I: Iterator<Item = usize>,
383 {
384 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
385 nalgebra_sparse::CscMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
386 }
387
388 pub fn read_rows_csr<I>(&self, rows: I) -> anyhow::Result<CsrMatrix<f32>>
389 where
390 I: Iterator<Item = usize>,
391 {
392 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
393 nalgebra_sparse::CsrMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
394 }
395
396 pub fn read_rows_tensor<I>(&self, rows: I) -> anyhow::Result<Tensor>
397 where
398 I: Iterator<Item = usize>,
399 {
400 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
401 Tensor::from_nonzero_triplets(nrow, ncol, &triplets)
402 }
403}