use alloc::vec;
use alloc::vec::Vec;
use crate::scalar::Scalar;
use super::CsrMatrix;
use super::add::DimensionMismatch;
use super::sorted_csr::SortedCsrMatrix;
pub fn spmm_csr<T: Scalar>(
a: &CsrMatrix<T>,
b: &CsrMatrix<T>,
) -> Result<SortedCsrMatrix<T>, DimensionMismatch> {
if a.cols() != b.rows() {
return Err(DimensionMismatch);
}
let m = a.rows();
let n = b.cols();
let mut out_row_ptr = vec![0usize; m + 1];
let mut out_col: Vec<usize> = Vec::new();
let mut out_val: Vec<T> = Vec::new();
let mut dense = vec![T::zero(); n];
let mut touched: Vec<usize> = Vec::new();
let mut in_touched = vec![false; n];
let a_row_ptr = a.row_ptr();
let a_col = a.col_indices();
let a_val = a.values();
let b_row_ptr = b.row_ptr();
let b_col = b.col_indices();
let b_val = b.values();
for r in 0..m {
for ka in a_row_ptr[r]..a_row_ptr[r + 1] {
let k = a_col[ka];
let av = a_val[ka];
for kb in b_row_ptr[k]..b_row_ptr[k + 1] {
let j = b_col[kb];
let bv = b_val[kb];
let prev = dense[j];
dense[j] = prev.add(av.mul(bv));
if !in_touched[j] {
touched.push(j);
in_touched[j] = true;
}
}
}
touched.sort_unstable();
for &col in &touched {
out_col.push(col);
out_val.push(dense[col]);
dense[col] = T::zero();
in_touched[col] = false;
}
touched.clear();
out_row_ptr[r + 1] = out_col.len();
}
Ok(SortedCsrMatrix::from_sorted_unchecked(CsrMatrix::new_raw(
m,
n,
out_row_ptr,
out_col,
out_val,
)))
}