use alloc::vec;
use alloc::vec::Vec;
use crate::scalar::Scalar;
use super::add::DimensionMismatch;
use super::{CscMatrix, CsrMatrix};
pub fn matmat_csr<T: Scalar>(
m: &CsrMatrix<T>,
x: &[T],
x_cols: usize,
) -> Result<Vec<T>, DimensionMismatch> {
let expected = m
.cols()
.checked_mul(x_cols)
.ok_or(DimensionMismatch::DimensionOverflow)?;
if x_cols == 0 || x.len() != expected {
return Err(DimensionMismatch::Shape);
}
let out_len = m
.rows()
.checked_mul(x_cols)
.ok_or(DimensionMismatch::DimensionOverflow)?;
let mut out = vec![T::zero(); out_len];
let row_ptr = m.row_ptr();
let col_idx = m.col_indices();
let vals = m.values();
for r in 0..m.rows() {
for k in row_ptr[r] as usize..row_ptr[r + 1] as usize {
let c = col_idx[k] as usize;
let v = vals[k];
for j in 0..x_cols {
let prev = out[r * x_cols + j];
out[r * x_cols + j] = prev.add(v.mul(x[c * x_cols + j]));
}
}
}
Ok(out)
}
pub fn matmat_csc<T: Scalar>(
m: &CscMatrix<T>,
x: &[T],
x_cols: usize,
) -> Result<Vec<T>, DimensionMismatch> {
let expected = m
.cols()
.checked_mul(x_cols)
.ok_or(DimensionMismatch::DimensionOverflow)?;
if x_cols == 0 || x.len() != expected {
return Err(DimensionMismatch::Shape);
}
let out_len = m
.rows()
.checked_mul(x_cols)
.ok_or(DimensionMismatch::DimensionOverflow)?;
let mut out = vec![T::zero(); out_len];
let col_ptr = m.col_ptr();
let row_idx = m.row_indices();
let vals = m.values();
for c in 0..m.cols() {
for k in col_ptr[c] as usize..col_ptr[c + 1] as usize {
let r = row_idx[k] as usize;
let v = vals[k];
for j in 0..x_cols {
let prev = out[r * x_cols + j];
out[r * x_cols + j] = prev.add(v.mul(x[c * x_cols + j]));
}
}
}
Ok(out)
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::{CscMatrix, CsrMatrix, matmat_csc, matmat_csr};
#[cfg(target_pointer_width = "32")]
#[test]
fn matmat_csr_rejects_overflowing_dimensions() {
let m = CsrMatrix::<f64>::new(1, 65536, vec![0, 0], vec![], vec![]).unwrap();
let x: Vec<f64> = vec![];
assert!(matmat_csr(&m, &x, 65536).is_err());
}
#[cfg(target_pointer_width = "32")]
#[test]
fn matmat_csc_rejects_overflowing_dimensions() {
let m = CscMatrix::<f64>::new(65536, 65536, vec![0u32; 65537], vec![], vec![]).unwrap();
let x: Vec<f64> = vec![];
assert!(matmat_csc(&m, &x, 65536).is_err());
}
}