use crate::arithmetic::Fx;
pub struct CsrMatrix {
pub n: usize,
pub row_ptr: Vec<usize>,
pub col_idx: Vec<usize>,
pub values: Vec<Fx>,
}
impl CsrMatrix {
pub fn nnz(&self) -> usize {
self.values.len()
}
pub fn spmv_add(&self, x: &[Fx], y: &mut [Fx]) {
for i in 0..self.n {
let mut acc = Fx::ZERO;
for k in self.row_ptr[i]..self.row_ptr[i + 1] {
acc = acc + self.values[k] * x[self.col_idx[k]];
}
y[i] = y[i] + acc;
}
}
pub fn spmv(&self, x: &[Fx], y: &mut [Fx]) {
y[..self.n].iter_mut().for_each(|v| *v = Fx::ZERO);
self.spmv_add(x, y);
}
}
pub struct CsrBuilder {
n: usize,
triplets: Vec<(usize, usize, Fx)>,
}
impl CsrBuilder {
pub fn new(n: usize) -> Self {
Self {
n,
triplets: Vec::new(),
}
}
pub fn add(&mut self, row: usize, col: usize, val: Fx) {
debug_assert!(row < self.n && col < self.n);
self.triplets.push((row, col, val));
}
pub fn build(mut self) -> CsrMatrix {
self.triplets.sort_unstable_by_key(|&(r, c, _)| (r, c));
let mut deduped: Vec<(usize, usize, Fx)> = Vec::with_capacity(self.triplets.len());
for (r, c, v) in self.triplets {
match deduped.last_mut() {
Some(last) if last.0 == r && last.1 == c => last.2 = last.2 + v,
_ => deduped.push((r, c, v)),
}
}
let nnz = deduped.len();
let mut row_ptr = vec![0usize; self.n + 1];
let mut col_idx = vec![0usize; nnz];
let mut values = vec![Fx::ZERO; nnz];
for (k, &(r, c, v)) in deduped.iter().enumerate() {
row_ptr[r + 1] += 1;
col_idx[k] = c;
values[k] = v;
}
for i in 0..self.n {
row_ptr[i + 1] += row_ptr[i];
}
CsrMatrix {
n: self.n,
row_ptr,
col_idx,
values,
}
}
}