lazymatrix 0.3.0

Lazy normalized design matrices: apply column centering/scaling without materializing (X - 1cᵀ)S⁻¹, preserving sparsity.
Documentation
use lazymatrix::{MatrixShape, Scalar, SparseRows};

struct Csr<'a, F> {
    ncols: usize,
    offsets: &'a [usize],
    columns: &'a [usize],
    values: &'a [F],
}

impl<F> MatrixShape for Csr<'_, F> {
    fn nrows(&self) -> usize {
        self.offsets.len() - 1
    }

    fn ncols(&self) -> usize {
        self.ncols
    }
}

impl<F: Scalar> SparseRows<F> for Csr<'_, F> {
    fn sparse_row(&self, i: usize) -> (&[usize], &[F]) {
        assert!(i < self.nrows());
        let range = self.offsets[i]..self.offsets[i + 1];
        (&self.columns[range.clone()], &self.values[range])
    }
}

#[test]
fn sparse_rows_supports_borrowed_trait_objects_without_backends() {
    let columns = [2, 0, 1];
    let values = [f32::NAN, f32::INFINITY, -0.0];
    let matrix = Csr {
        ncols: 3,
        offsets: &[0, 1, 3],
        columns: &columns,
        values: &values,
    };
    let erased: &dyn SparseRows<f32> = &matrix;
    let borrowed = &erased;
    let (indices, raw) = <&dyn SparseRows<f32> as SparseRows<f32>>::sparse_row(borrowed, 1);
    assert_eq!(borrowed.nrows(), 2);
    assert_eq!(borrowed.ncols(), 3);
    assert_eq!(indices, &[0, 1]);
    assert_eq!(indices.as_ptr(), columns[1..].as_ptr());
    assert_eq!(raw.as_ptr(), values[1..].as_ptr());
    assert_eq!(raw[0], f32::INFINITY);
    assert_eq!(raw[1].to_bits(), (-0.0_f32).to_bits());
    assert!(borrowed.sparse_row(0).1[0].is_nan());
}