use data_beans::sparse_io::*;
use legume_numeric::matrix::traits::SampleOps;
fn fixture() -> (Box<dyn SparseIo<IndexIter = Vec<usize>>>, Vec<u64>) {
let mut arr = ndarray::Array2::<f32>::zeros((5, 7));
arr[(0, 1)] = 1.0;
arr[(3, 1)] = 2.0;
arr[(2, 3)] = 3.0;
arr[(0, 4)] = 4.0;
arr[(1, 4)] = 5.0;
arr[(4, 4)] = 6.0;
arr[(2, 5)] = 7.0;
let per_column = vec![0u64, 2, 0, 1, 3, 1, 0];
let data = create_sparse_from_ndarray(&arr, None, None).expect("fixture backend");
(data, per_column)
}
#[test]
fn per_column_nnz_matches_a_triplet_count() -> anyhow::Result<()> {
let (data, expected) = fixture();
for (col, &want) in expected.iter().enumerate() {
assert_eq!(
data.column_nnz(col),
Some(want),
"column {col}: indptr-derived nnz must equal the triplet count"
);
}
assert_eq!(data.column_nnz(99), None, "out of range is None, not 0");
Ok(())
}
#[test]
fn per_column_sums_agree_with_the_total() -> anyhow::Result<()> {
let (data, expected) = fixture();
let picked = [5usize, 1, 4];
let want: u64 = picked.iter().map(|&c| expected[c]).sum();
let got: u64 = picked
.iter()
.map(|&c| data.column_nnz(c).expect("in range"))
.sum();
assert_eq!(got, want);
let all: u64 = (0..7).map(|c| data.column_nnz(c).expect("in range")).sum();
assert_eq!(all as usize, data.num_non_zeros().expect("nnz"));
Ok(())
}
#[test]
fn random_matrix_totals_agree() -> anyhow::Result<()> {
let arr = ndarray::Array2::<f32>::runif(4, 9);
let data = create_sparse_from_ndarray(&arr, None, None)?;
let all: u64 = (0..9).map(|c| data.column_nnz(c).expect("in range")).sum();
assert_eq!(all, 36);
assert_eq!(data.column_nnz(8), Some(4));
Ok(())
}
#[test]
fn a_preload_over_budget_is_skipped_not_obeyed() -> anyhow::Result<()> {
let arr = ndarray::Array2::<f32>::from_elem((50, 40), 1.0);
let mut data = create_sparse_from_ndarray(&arr, None, None)?;
std::env::set_var("LEGUME_PRELOAD_BUDGET_BYTES", "1024");
let result = data.preload_columns();
std::env::remove_var("LEGUME_PRELOAD_BUDGET_BYTES");
result?;
assert!(
data.csc_column_arrays().is_none(),
"over budget: the arrays must not be resident"
);
let (_, _, t) = data.read_triplets_by_columns((0..40).collect())?;
assert_eq!(t.len(), 2000);
data.preload_columns()?;
assert!(data.csc_column_arrays().is_some(), "under budget: loaded");
Ok(())
}