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 #[cfg(feature = "ndarray")]
147 pub fn read_columns_ndarray<I>(&self, cells: I) -> anyhow::Result<ndarray::Array2<f32>>
148 where
149 I: Iterator<Item = usize>,
150 {
151 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
152 ndarray::Array2::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
153 }
154
155 pub fn read_columns_dmatrix<I>(&self, cells: I) -> anyhow::Result<nalgebra::DMatrix<f32>>
156 where
157 I: Iterator<Item = usize>,
158 {
159 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
160 DMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
161 }
162
163 pub fn read_columns_csc<I>(&self, cells: I) -> anyhow::Result<CscMatrix<f32>>
174 where
175 I: Iterator<Item = usize>,
176 {
177 let cells: Vec<usize> = cells.collect();
178 let nrow = self.num_rows();
179 let ncol = cells.len();
180
181 let mut backend_groups: Vec<Vec<(usize, usize)>> =
188 (0..self.data_vec.len()).map(|_| Vec::new()).collect();
189 for (out_col, &glob) in cells.iter().enumerate() {
190 for source in self.col_to_data[glob].iter() {
191 backend_groups[source.backend as usize].push((source.local_col as usize, out_col));
192 }
193 }
194
195 let mut buckets: Vec<Vec<(u32, f32)>> = (0..ncol).map(|_| Vec::new()).collect();
197 let g2c = self.global_to_compact_row.as_slice();
198
199 for (didx, group) in backend_groups.iter().enumerate() {
200 if group.is_empty() {
201 continue;
202 }
203 let l2g = self.data_local_to_global_row[didx].as_slice();
204
205 if let Some((indptr, indices, values)) = self.data_vec[didx].csc_column_arrays() {
206 for &(loc, out_col) in group {
208 if loc + 1 >= indptr.len() {
209 continue;
210 }
211 let s = indptr[loc] as usize;
212 let e = indptr[loc + 1] as usize;
213 let bucket = &mut buckets[out_col];
214 bucket.reserve(e - s);
215 for k in s..e {
216 let local_row = indices[k] as usize;
217 if let Some(c) = g2c[l2g[local_row]] {
218 bucket.push((c as u32, values[k]));
219 }
220 }
221 }
222 } else {
223 let cols: Vec<usize> = group.iter().map(|&(loc, _)| loc).collect();
230 let (_, _, trip) = self.data_vec[didx].read_triplets_by_columns(cols)?;
231 for (i, jj, v) in trip {
232 let (_, out_col) = group[jj as usize];
233 if let Some(c) = g2c[l2g[i as usize]] {
234 buckets[out_col].push((c as u32, v));
235 }
236 }
237 }
238 }
239
240 let total_nnz: usize = buckets.iter().map(|b| b.len()).sum();
242 let mut col_offsets: Vec<usize> = Vec::with_capacity(ncol + 1);
243 let mut row_indices: Vec<usize> = Vec::with_capacity(total_nnz);
244 let mut values: Vec<f32> = Vec::with_capacity(total_nnz);
245 col_offsets.push(0);
246
247 for bucket in &mut buckets {
248 let strictly_sorted_unique = bucket.windows(2).all(|w| w[0].0 < w[1].0);
260 if !strictly_sorted_unique {
261 bucket.sort_by_key(|&(r, _)| r);
262 let mut write = 0usize;
264 let mut read = 0usize;
265 while read < bucket.len() {
266 let (r, mut v) = bucket[read];
267 read += 1;
268 while read < bucket.len() && bucket[read].0 == r {
269 v += bucket[read].1;
270 read += 1;
271 }
272 bucket[write] = (r, v);
273 write += 1;
274 }
275 bucket.truncate(write);
276 }
277 for &(r, v) in bucket.iter() {
278 row_indices.push(r as usize);
279 values.push(v);
280 }
281 col_offsets.push(row_indices.len());
282 }
283
284 CscMatrix::try_from_csc_data(nrow, ncol, col_offsets, row_indices, values)
285 .map_err(|e| anyhow::anyhow!("CSC construction failed: {:?}", e))
286 }
287
288 pub fn read_columns_csr<I>(&self, cells: I) -> anyhow::Result<CsrMatrix<f32>>
289 where
290 I: Iterator<Item = usize>,
291 {
292 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
293 nalgebra_sparse::CsrMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
294 }
295
296 #[cfg(feature = "tensor")]
297 pub fn read_columns_tensor<I>(&self, cells: I) -> anyhow::Result<Tensor>
298 where
299 I: Iterator<Item = usize>,
300 {
301 let ((nrow, ncol), triplets) = self.columns_triplets(cells)?;
302 Tensor::from_nonzero_triplets(nrow, ncol, &triplets)
303 }
304
305 #[allow(clippy::type_complexity)]
310 pub fn rows_triplets<I>(
311 &self,
312 rows: I,
313 ) -> anyhow::Result<((usize, usize), Vec<(u64, u64, f32)>)>
314 where
315 I: Iterator<Item = usize>,
316 {
317 let rows_compact: Vec<usize> = rows.collect();
318 let nrow_out = rows_compact.len();
319 let ncol_out = self.num_columns();
320
321 let n_compact = self.cached_num_rows;
322 let compact_to_global = self.compact_to_global_row.as_slice();
323
324 let mut triplets: Vec<(u64, u64, f32)> = Vec::new();
325 let mut local_to_out: Vec<usize> = Vec::with_capacity(rows_compact.len());
326 for didx in 0..self.data_vec.len() {
327 let g2l = &self.data_global_to_local_row[didx];
328
329 local_to_out.clear();
330 let mut local_rows: Vec<usize> = Vec::with_capacity(rows_compact.len());
331 for (out_row, &c) in rows_compact.iter().enumerate() {
332 if c >= n_compact {
333 continue;
334 }
335 let g = compact_to_global[c];
336 if let Some(&l) = g2l.get(&g) {
337 local_rows.push(l);
338 local_to_out.push(out_row);
339 }
340 }
341 if local_rows.is_empty() {
342 continue;
343 }
344
345 let (_, _, group_triplets) = self.data_vec[didx].read_triplets_by_rows(local_rows)?;
346 let cols_map = self
347 .data_to_cols
348 .get(&didx)
349 .ok_or_else(|| anyhow::anyhow!("missing data_to_cols entry for didx {}", didx))?;
350 triplets.reserve(group_triplets.len());
351 for (i, j, v) in group_triplets {
352 let mapped = cols_map[j as usize];
354 if mapped == usize::MAX {
355 continue;
356 }
357 let out_row = local_to_out[i as usize] as u64;
358 let out_col = mapped as u64;
359 triplets.push((out_row, out_col, v));
360 }
361 }
362
363 Ok(((nrow_out, ncol_out), triplets))
364 }
365
366 #[cfg(feature = "ndarray")]
367 pub fn read_rows_ndarray<I>(&self, rows: I) -> anyhow::Result<ndarray::Array2<f32>>
368 where
369 I: Iterator<Item = usize>,
370 {
371 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
372 ndarray::Array2::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
373 }
374
375 pub fn read_rows_dmatrix<I>(&self, rows: I) -> anyhow::Result<nalgebra::DMatrix<f32>>
376 where
377 I: Iterator<Item = usize>,
378 {
379 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
380 DMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
381 }
382
383 pub fn read_rows_csc<I>(&self, rows: I) -> anyhow::Result<CscMatrix<f32>>
384 where
385 I: Iterator<Item = usize>,
386 {
387 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
388 nalgebra_sparse::CscMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
389 }
390
391 pub fn read_rows_csr<I>(&self, rows: I) -> anyhow::Result<CsrMatrix<f32>>
392 where
393 I: Iterator<Item = usize>,
394 {
395 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
396 nalgebra_sparse::CsrMatrix::<f32>::from_nonzero_triplets(nrow, ncol, &triplets)
397 }
398
399 #[cfg(feature = "tensor")]
400 pub fn read_rows_tensor<I>(&self, rows: I) -> anyhow::Result<Tensor>
401 where
402 I: Iterator<Item = usize>,
403 {
404 let ((nrow, ncol), triplets) = self.rows_triplets(rows)?;
405 Tensor::from_nonzero_triplets(nrow, ncol, &triplets)
406 }
407}