use alloc::vec;
use alloc::vec::Vec;
use crate::scalar::Scalar;
use super::add::DimensionMismatch;
use super::{CscMatrix, CsrMatrix};
pub trait SparseLinearOp<T: Scalar> {
fn rows(&self) -> usize;
fn cols(&self) -> usize;
fn apply(&self, x: &[T]) -> Result<Vec<T>, DimensionMismatch>;
}
impl<T: Scalar> SparseLinearOp<T> for CsrMatrix<T> {
fn rows(&self) -> usize {
CsrMatrix::rows(self)
}
fn cols(&self) -> usize {
CsrMatrix::cols(self)
}
fn apply(&self, x: &[T]) -> Result<Vec<T>, DimensionMismatch> {
if x.len() != CsrMatrix::cols(self) {
return Err(DimensionMismatch);
}
let mut out = vec![T::zero(); CsrMatrix::rows(self)];
let row_ptr = self.row_ptr();
let col_idx = self.col_indices();
let vals = self.values();
for r in 0..CsrMatrix::rows(self) {
for k in row_ptr[r]..row_ptr[r + 1] {
let prev = out[r];
out[r] = prev.add(vals[k].mul(x[col_idx[k]]));
}
}
Ok(out)
}
}
impl<T: Scalar> SparseLinearOp<T> for CscMatrix<T> {
fn rows(&self) -> usize {
CscMatrix::rows(self)
}
fn cols(&self) -> usize {
CscMatrix::cols(self)
}
fn apply(&self, x: &[T]) -> Result<Vec<T>, DimensionMismatch> {
if x.len() != CscMatrix::cols(self) {
return Err(DimensionMismatch);
}
let mut out = vec![T::zero(); CscMatrix::rows(self)];
let col_ptr = self.col_ptr();
let row_idx = self.row_indices();
let vals = self.values();
for c in 0..CscMatrix::cols(self) {
for k in col_ptr[c]..col_ptr[c + 1] {
let r = row_idx[k];
let prev = out[r];
out[r] = prev.add(vals[k].mul(x[c]));
}
}
Ok(out)
}
}