#[cfg(feature = "serde-serialize")]
mod coo_serde;
use crate::SparseFormatError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CooMatrix<T> {
nrows: usize,
ncols: usize,
row_indices: Vec<usize>,
col_indices: Vec<usize>,
values: Vec<T>,
}
impl<T: na::Scalar> CooMatrix<T> {
#[inline]
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::RawStorage<T, R, C>>(
&mut self,
r: usize,
c: usize,
m: &na::Matrix<T, R, C, S>,
) {
let block_nrows = m.nrows();
let block_ncols = m.ncols();
let max_row_with_block = r + block_nrows - 1;
let max_col_with_block = c + block_ncols - 1;
assert!(max_row_with_block < self.nrows);
assert!(max_col_with_block < self.ncols);
self.reserve(block_ncols * block_nrows);
for (col_idx, col) in m.column_iter().enumerate() {
for (row_idx, v) in col.iter().enumerate() {
self.row_indices.push(r + row_idx);
self.col_indices.push(c + col_idx);
self.values.push(v.clone());
}
}
}
}
impl<T> CooMatrix<T> {
pub fn new(nrows: usize, ncols: usize) -> Self {
Self {
nrows,
ncols,
row_indices: Vec::new(),
col_indices: Vec::new(),
values: Vec::new(),
}
}
pub fn zeros(nrows: usize, ncols: usize) -> Self {
Self::new(nrows, ncols)
}
pub fn try_from_triplets(
nrows: usize,
ncols: usize,
row_indices: Vec<usize>,
col_indices: Vec<usize>,
values: Vec<T>,
) -> Result<Self, SparseFormatError> {
use crate::SparseFormatErrorKind::*;
if row_indices.len() != col_indices.len() {
return Err(SparseFormatError::from_kind_and_msg(
InvalidStructure,
"Number of row and col indices must be the same.",
));
} else if col_indices.len() != values.len() {
return Err(SparseFormatError::from_kind_and_msg(
InvalidStructure,
"Number of col indices and values must be the same.",
));
}
let row_indices_in_bounds = row_indices.iter().all(|i| *i < nrows);
let col_indices_in_bounds = col_indices.iter().all(|j| *j < ncols);
if !row_indices_in_bounds {
Err(SparseFormatError::from_kind_and_msg(
IndexOutOfBounds,
"Row index out of bounds.",
))
} else if !col_indices_in_bounds {
Err(SparseFormatError::from_kind_and_msg(
IndexOutOfBounds,
"Col index out of bounds.",
))
} else {
Ok(Self {
nrows,
ncols,
row_indices,
col_indices,
values,
})
}
}
pub fn try_from_triplets_iter(
nrows: usize,
ncols: usize,
triplets: impl IntoIterator<Item = (usize, usize, T)>,
) -> Result<Self, SparseFormatError> {
let (row_indices, (col_indices, values)) =
triplets.into_iter().map(|(r, c, v)| (r, (c, v))).unzip();
Self::try_from_triplets(nrows, ncols, row_indices, col_indices, values)
}
pub fn triplet_iter(&self) -> impl Iterator<Item = (usize, usize, &T)> {
self.row_indices
.iter()
.zip(&self.col_indices)
.zip(&self.values)
.map(|((i, j), v)| (*i, *j, v))
}
pub fn triplet_iter_mut(&mut self) -> impl Iterator<Item = (usize, usize, &mut T)> {
self.row_indices
.iter()
.zip(&self.col_indices)
.zip(self.values.iter_mut())
.map(|((i, j), v)| (*i, *j, v))
}
pub fn reserve(&mut self, additional: usize) {
self.row_indices.reserve(additional);
self.col_indices.reserve(additional);
self.values.reserve(additional);
}
#[inline]
pub fn push(&mut self, i: usize, j: usize, v: T) {
assert!(i < self.nrows);
assert!(j < self.ncols);
self.row_indices.push(i);
self.col_indices.push(j);
self.values.push(v);
}
pub fn clear_triplets(&mut self) {
self.col_indices.clear();
self.row_indices.clear();
self.values.clear();
}
#[inline]
#[must_use]
pub fn nrows(&self) -> usize {
self.nrows
}
#[inline]
#[must_use]
pub fn ncols(&self) -> usize {
self.ncols
}
#[inline]
#[must_use]
pub fn nnz(&self) -> usize {
self.values.len()
}
#[must_use]
pub fn row_indices(&self) -> &[usize] {
&self.row_indices
}
#[must_use]
pub fn col_indices(&self) -> &[usize] {
&self.col_indices
}
#[must_use]
pub fn values(&self) -> &[T] {
&self.values
}
pub fn disassemble(self) -> (Vec<usize>, Vec<usize>, Vec<T>) {
(self.row_indices, self.col_indices, self.values)
}
}