use alloc::vec;
use alloc::vec::Vec;
use crate::scalar::Scalar;
use super::{CscMatrix, CsrMatrix};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DimensionMismatch;
pub fn add_csr<T: Scalar>(
a: &CsrMatrix<T>,
b: &CsrMatrix<T>,
) -> Result<CsrMatrix<T>, DimensionMismatch> {
if a.rows() != b.rows() || a.cols() != b.cols() {
return Err(DimensionMismatch);
}
let rows = a.rows();
let cols = a.cols();
let mut out_row_ptr = vec![0usize; rows + 1];
let mut out_col: Vec<usize> = Vec::new();
let mut out_val: Vec<T> = Vec::new();
let mut pairs: Vec<(usize, T)> = Vec::new();
for r in 0..rows {
pairs.clear();
let a_range = a.row_ptr()[r]..a.row_ptr()[r + 1];
for k in a_range {
pairs.push((a.col_indices()[k], a.values()[k]));
}
let b_range = b.row_ptr()[r]..b.row_ptr()[r + 1];
for k in b_range {
pairs.push((b.col_indices()[k], b.values()[k]));
}
pairs.sort_by_key(|&(c, _)| c);
let mut k = 0;
while k < pairs.len() {
let (col, mut sum) = pairs[k];
let mut j = k + 1;
while j < pairs.len() && pairs[j].0 == col {
sum = sum.add(pairs[j].1);
j += 1;
}
if sum != T::zero() {
out_col.push(col);
out_val.push(sum);
}
k = j;
}
out_row_ptr[r + 1] = out_col.len();
}
Ok(CsrMatrix::new_raw(
rows,
cols,
out_row_ptr,
out_col,
out_val,
))
}
pub fn add_csc<T: Scalar>(
a: &CscMatrix<T>,
b: &CscMatrix<T>,
) -> Result<CscMatrix<T>, DimensionMismatch> {
if a.rows() != b.rows() || a.cols() != b.cols() {
return Err(DimensionMismatch);
}
let rows = a.rows();
let cols = a.cols();
let mut out_col_ptr = vec![0usize; cols + 1];
let mut out_row: Vec<usize> = Vec::new();
let mut out_val: Vec<T> = Vec::new();
let mut pairs: Vec<(usize, T)> = Vec::new();
for c in 0..cols {
pairs.clear();
let a_range = a.col_ptr()[c]..a.col_ptr()[c + 1];
for k in a_range {
pairs.push((a.row_indices()[k], a.values()[k]));
}
let b_range = b.col_ptr()[c]..b.col_ptr()[c + 1];
for k in b_range {
pairs.push((b.row_indices()[k], b.values()[k]));
}
pairs.sort_by_key(|&(r, _)| r);
let mut k = 0;
while k < pairs.len() {
let (row, mut sum) = pairs[k];
let mut j = k + 1;
while j < pairs.len() && pairs[j].0 == row {
sum = sum.add(pairs[j].1);
j += 1;
}
if sum != T::zero() {
out_row.push(row);
out_val.push(sum);
}
k = j;
}
out_col_ptr[c + 1] = out_row.len();
}
Ok(CscMatrix::new_raw(
rows,
cols,
out_col_ptr,
out_row,
out_val,
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn s1_add_csr_cancellation_zeros() {
let a = CsrMatrix::new(1, 2, vec![0, 1], vec![0], vec![3.0_f64]).unwrap();
let b = CsrMatrix::new(1, 2, vec![0, 1], vec![0], vec![-3.0_f64]).unwrap();
let c = add_csr(&a, &b).unwrap();
assert_eq!(c.nnz(), 0);
}
#[test]
fn s1_add_csc_cancellation_zeros() {
let a = CscMatrix::new(2, 1, vec![0, 1], vec![0], vec![5.0_f64]).unwrap();
let b = CscMatrix::new(2, 1, vec![0, 1], vec![0], vec![-5.0_f64]).unwrap();
let c = add_csc(&a, &b).unwrap();
assert_eq!(c.nnz(), 0);
}
}