use faer::Mat;
use crate::prelude::*;
pub struct Pile {
pub cell_indices: Vec<usize>,
pub raw: CompressedSparseData2<u32, f32>,
pub umis_per_cell: Vec<f32>,
pub n_genes: usize,
pub downsampled: Option<CompressedSparseData2<u32, f32>>,
pub selected_gene_indices: Option<Vec<usize>>,
pub selected_dense: Option<Mat<f32>>,
}
impl Pile {
pub fn from_reader<S: SingleCellReading>(
reader: &S,
cell_indices: &[usize],
) -> Result<Self, BixverseErrors> {
let chunks = reader.read_cells_parallel(cell_indices)?;
let n_genes = reader.get_header().total_genes;
let raw = from_cell_chunks::<u32>(&chunks, &DataLayerReturn::Raw, n_genes)?;
let umis_per_cell = sum_rows_csr(&raw);
Ok(Self {
cell_indices: cell_indices.to_vec(),
raw,
umis_per_cell,
n_genes,
downsampled: None,
selected_gene_indices: None,
selected_dense: None,
})
}
#[inline]
pub fn n_cells(&self) -> usize {
self.cell_indices.len()
}
}
fn sum_rows_csr(mat: &CompressedSparseData2<u32, f32>) -> Vec<f32> {
let n_rows = mat.shape.0;
let mut sums = vec![0.0f32; n_rows];
for i in 0..n_rows {
let s: u64 = (mat.indptr[i]..mat.indptr[i + 1])
.map(|idx| mat.data[idx as usize] as u64)
.sum();
sums[i] = s as f32;
}
sums
}
#[cfg(test)]
mod tests {
use super::*;
fn make_csr(
data: Vec<u32>,
indices: Vec<usize>,
indptr: Vec<usize>,
shape: (usize, usize),
) -> CompressedSparseData2<u32, f32> {
CompressedSparseData2 {
data,
indices: indices.index_cast(),
indptr: indptr.index_cast(),
cs_type: CompressedSparseFormat::Csr,
data_2: None,
shape,
}
}
#[test]
fn sum_rows_csr_basic() {
let mat = make_csr(vec![3, 5, 2], vec![0, 2, 1], vec![0, 2, 3], (2, 3));
let sums = sum_rows_csr(&mat);
assert_eq!(sums, vec![8.0, 2.0]);
}
#[test]
fn sum_rows_csr_empty_row() {
let mat = make_csr(vec![], vec![], vec![0, 0], (1, 5));
let sums = sum_rows_csr(&mat);
assert_eq!(sums, vec![0.0]);
}
}