use std::{cmp::max, iter::FromIterator};
#[derive(Clone, Debug)]
pub struct CooMat<T> {
rows: usize,
cols: usize,
entries: Vec<(usize, usize, T)>,
}
impl<T> CooMat<T> {
pub fn new(rows: usize, cols: usize) -> Self {
let rows = max(rows, 1);
let cols = max(cols, 1);
let entries = Vec::new();
CooMat {
rows,
cols,
entries,
}
}
pub fn with_capacity(rows: usize, cols: usize, capacity: usize) -> Self {
let rows = max(rows, 1);
let cols = max(cols, 1);
let entries = Vec::with_capacity(capacity);
CooMat {
rows,
cols,
entries,
}
}
pub fn with_entries<I>(rows: usize, cols: usize, entries: I) -> Self
where
I: IntoIterator<Item = (usize, usize, T)>,
{
let rows = max(rows, 1);
let cols = max(cols, 1);
let entries: Vec<_> = entries.into_iter().collect();
for (row, col, _) in entries.iter() {
if *row >= rows {
panic!("invalid row index ({}) should be < rows ({})", row, rows);
}
if *col >= cols {
panic!("invalid column index ({}) should be < cols ({})", col, cols);
}
}
CooMat {
rows,
cols,
entries,
}
}
pub fn with_triplets<R, C, V>(rows: usize, cols: usize, rowind: R, colind: C, values: V) -> Self
where
R: IntoIterator<Item = usize>,
C: IntoIterator<Item = usize>,
V: IntoIterator<Item = T>,
{
let rows = max(rows, 1);
let cols = max(cols, 1);
let rowind: Vec<_> = rowind.into_iter().collect();
let colind: Vec<_> = colind.into_iter().collect();
let values: Vec<_> = values.into_iter().collect();
let len = values.len();
if rowind.len() != len || colind.len() != len {
panic!(
"invalid triplets: rowind ({}), colind ({}) and values ({}) lengths differ",
rowind.len(),
colind.len(),
values.len()
);
}
for (row, col) in rowind.iter().zip(colind.iter()) {
if *row >= rows {
panic!("invalid row index ({}) should be < rows ({})", row, rows);
}
if *col >= cols {
panic!("invalid column index ({}) should be < cols ({})", col, cols);
}
}
let mut entries = Vec::with_capacity(len);
for (idx, value) in values.into_iter().enumerate() {
entries.push((rowind[idx], colind[idx], value));
}
CooMat {
rows,
cols,
entries,
}
}
pub fn rows(&self) -> usize {
self.rows
}
pub fn cols(&self) -> usize {
self.cols
}
pub fn shape(&self) -> (usize, usize) {
(self.rows, self.cols)
}
pub fn capacity(&self) -> usize {
self.entries.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.entries.reserve(additional);
}
pub fn shrink(&mut self) {
self.entries.shrink_to_fit();
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn truncate(&mut self, len: usize) {
self.entries.truncate(len);
}
pub fn get(&self, index: usize) -> Option<(&usize, &usize, &T)> {
self.entries.get(index).map(|(r, c, v)| (r, c, v))
}
pub fn get_mut(&mut self, index: usize) -> Option<(&usize, &usize, &mut T)> {
self.entries.get_mut(index).map(|(r, c, v)| (&*r, &*c, v))
}
pub fn swap(&mut self, a: usize, b: usize) {
if a > self.len() {
panic!("invalid index: index = {} | length = {}", a, self.len());
}
if b > self.len() {
panic!("invalid index: index = {} | length = {}", b, self.len());
}
self.entries.swap(a, b);
}
pub fn insert(&mut self, index: usize, row: usize, col: usize, val: T) {
if index > self.len() {
panic!("invalid index: index = {} | length = {}", index, self.len());
}
if row >= self.rows {
panic!("invalid row index: row = {} | rows = {}", row, self.rows);
}
if col >= self.cols {
panic!("invalid column index: col = {} | cols = {}", col, self.cols);
}
self.entries.insert(index, (row, col, val));
}
pub fn remove(&mut self, index: usize) -> (usize, usize, T) {
if index > self.len() {
panic!("invalid index: index = {} | length = {}", index, self.len());
}
self.entries.remove(index)
}
pub fn swap_remove(&mut self, index: usize) -> (usize, usize, T) {
if index > self.len() {
panic!("invalid index: index = {} | length = {}", index, self.len());
}
self.entries.swap_remove(index)
}
pub fn push(&mut self, row: usize, col: usize, val: T) {
if row >= self.rows {
panic!("invalid row index: row = {} | rows = {}", row, self.rows);
}
if col >= self.cols {
panic!("invalid column index: col = {} | cols = {}", col, self.cols);
}
self.entries.push((row, col, val));
}
pub fn pop(&mut self) -> Option<(usize, usize, T)> {
self.entries.pop()
}
pub fn retain<F>(&mut self, pred: F)
where
F: FnMut(&(usize, usize, T)) -> bool,
{
self.entries.retain(pred);
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn sort_stable_row_major(&mut self) {
self.entries
.sort_by(|(r1, c1, _), (r2, c2, _)| r1.cmp(r2).then(c1.cmp(c2)));
}
pub fn sort_stable_col_major(&mut self) {
self.entries
.sort_by(|(r1, c1, _), (r2, c2, _)| c1.cmp(c2).then(r1.cmp(r2)));
}
pub fn sort_unstable_row_major(&mut self) {
self.entries
.sort_unstable_by(|(r1, c1, _), (r2, c2, _)| r1.cmp(r2).then(c1.cmp(c2)));
}
pub fn sort_unstable_col_major(&mut self) {
self.entries
.sort_unstable_by(|(r1, c1, _), (r2, c2, _)| c1.cmp(c2).then(r1.cmp(r2)));
}
pub fn reverse(&mut self) {
self.entries.reverse();
}
pub fn iter(&self) -> Iter<T> {
Iter {
inner: self.entries.iter(),
}
}
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut {
inner: self.entries.iter_mut(),
}
}
}
impl<T> Extend<(usize, usize, T)> for CooMat<T> {
fn extend<I: IntoIterator<Item = (usize, usize, T)>>(&mut self, iter: I) {
for (row, col, val) in iter {
self.push(row, col, val);
}
}
}
impl<T> FromIterator<(usize, usize, T)> for CooMat<T> {
fn from_iter<I: IntoIterator<Item = (usize, usize, T)>>(iter: I) -> Self {
let entries: Vec<_> = iter.into_iter().collect();
if entries.is_empty() {
CooMat::new(1, 1)
} else {
let rows = entries.iter().map(|&(r, _, _)| r).max().unwrap() + 1;
let cols = entries.iter().map(|&(_, c, _)| c).max().unwrap() + 1;
CooMat::with_entries(rows, cols, entries)
}
}
}
impl<T> IntoIterator for CooMat<T> {
type Item = (usize, usize, T);
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
inner: self.entries.into_iter(),
}
}
}
#[derive(Clone, Debug)]
pub struct Iter<'iter, T: 'iter> {
inner: std::slice::Iter<'iter, (usize, usize, T)>,
}
impl<'iter, T: 'iter> Iterator for Iter<'iter, T> {
type Item = (&'iter usize, &'iter usize, &'iter T);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(r, c, v)| (r, c, v))
}
}
impl<T> DoubleEndedIterator for Iter<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(|(r, c, v)| (r, c, v))
}
}
impl<T> ExactSizeIterator for Iter<'_, T> {}
#[derive(Debug)]
pub struct IterMut<'iter, T: 'iter> {
inner: std::slice::IterMut<'iter, (usize, usize, T)>,
}
impl<'iter, T: 'iter> Iterator for IterMut<'iter, T> {
type Item = (&'iter usize, &'iter usize, &'iter mut T);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(r, c, v)| (&*r, &*c, v))
}
}
impl<T> DoubleEndedIterator for IterMut<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(|(r, c, v)| (&*r, &*c, v))
}
}
impl<T> ExactSizeIterator for IterMut<'_, T> {}
#[derive(Debug)]
pub struct IntoIter<T> {
inner: std::vec::IntoIter<(usize, usize, T)>,
}
impl<T> Iterator for IntoIter<T> {
type Item = (usize, usize, T);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_annotation() {
let _: CooMat<f64> = CooMat::new(1, 2);
}
#[test]
fn new_fish() {
CooMat::<f64>::new(2, 1);
}
#[test]
fn new_shape() {
let matrix = CooMat::<f64>::new(1, 2);
assert_eq!(matrix.shape(), (1, 2));
}
#[test]
fn new_length() {
let matrix = CooMat::<f64>::new(1, 1);
assert_eq!(matrix.entries.len(), 0)
}
#[test]
fn new_capacity() {
let matrix = CooMat::<f64>::new(1, 1);
assert_eq!(matrix.entries.capacity(), 0);
}
#[test]
fn new_null_rows_cols() {
let matrix = CooMat::<f64>::new(0, 0);
assert_eq!(matrix.shape(), (1, 1));
}
#[test]
fn with_capacity_annotation() {
let _: CooMat<f64> = CooMat::with_capacity(1, 2, 3);
}
#[test]
fn with_capacity_fish() {
CooMat::<f64>::with_capacity(2, 1, 3);
}
#[test]
fn with_capacity_shape() {
let matrix = CooMat::<f64>::with_capacity(1, 2, 3);
assert_eq!(matrix.shape(), (1, 2));
}
#[test]
fn with_capacity_length() {
let matrix = CooMat::<f64>::with_capacity(1, 1, 1);
assert_eq!(matrix.entries.len(), 0)
}
#[test]
fn with_capacity_capacity() {
let matrix = CooMat::<f64>::with_capacity(1, 1, 1);
assert_eq!(matrix.entries.capacity(), 1);
}
#[test]
fn with_capacity_null_rows_cols() {
let matrix = CooMat::<f64>::with_capacity(0, 0, 1);
assert_eq!(matrix.shape(), (1, 1));
}
#[test]
fn with_entries() {
let entries = vec![(0, 0, 1.0)];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.get(0), Some((&0, &0, &1.0)));
assert_eq!(matrix.get(1), None);
}
#[test]
fn with_entries_order() {
let entries = vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)];
let matrix = CooMat::with_entries(2, 2, entries);
let mut iter = matrix.iter();
assert_eq!(iter.next(), Some((&0, &0, &1.0)));
assert_eq!(iter.next(), Some((&0, &1, &2.0)));
assert_eq!(iter.next(), Some((&1, &0, &3.0)));
assert_eq!(iter.next(), Some((&1, &1, &4.0)));
assert_eq!(iter.next(), None);
}
#[test]
fn with_entries_length() {
let entries = vec![(0, 0, 1.0)];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.entries.len(), 1)
}
#[test]
fn with_entries_capacity() {
let entries = vec![(0, 0, 1.0)];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.entries.capacity(), 1)
}
#[test]
fn with_entries_null_rows_cols() {
let matrix: CooMat<f64> = CooMat::with_entries(0, 0, vec![]);
assert_eq!(matrix.shape(), (1, 1));
}
#[test]
#[should_panic]
fn with_entries_invalid_row() {
let entries = vec![(1, 0, 1.0)];
CooMat::with_entries(1, 1, entries);
}
#[test]
#[should_panic]
fn with_entries_invalid_col() {
let entries = vec![(0, 1, 1.0)];
CooMat::with_entries(1, 1, entries);
}
#[test]
fn with_triplets() {
let rowind = vec![0];
let colind = vec![0];
let values = vec![1.0];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.get(0), Some((&0, &0, &1.0)));
assert_eq!(matrix.get(1), None);
}
#[test]
fn with_triplets_order() {
let rowind = vec![0, 0, 1, 1];
let colind = vec![0, 1, 0, 1];
let values = vec![1.0, 2.0, 3.0, 4.0];
let matrix = CooMat::with_triplets(2, 2, rowind, colind, values);
let mut iter = matrix.iter();
assert_eq!(iter.next(), Some((&0, &0, &1.0)));
assert_eq!(iter.next(), Some((&0, &1, &2.0)));
assert_eq!(iter.next(), Some((&1, &0, &3.0)));
assert_eq!(iter.next(), Some((&1, &1, &4.0)));
assert_eq!(iter.next(), None);
}
#[test]
fn with_triplets_length() {
let rowind = vec![0];
let colind = vec![0];
let values = vec![1.0];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.entries.len(), 1);
}
#[test]
fn with_triplets_capacity() {
let rowind = vec![0];
let colind = vec![0];
let values = vec![1.0];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.entries.capacity(), 1);
}
#[test]
#[should_panic]
fn with_triplets_invalid_row() {
let rowind = vec![1];
let colind = vec![0];
let values = vec![1.0];
CooMat::with_triplets(1, 1, rowind, colind, values);
}
#[test]
#[should_panic]
fn with_triplets_invalid_col() {
let rowind = vec![0];
let colind = vec![1];
let values = vec![1.0];
CooMat::with_triplets(1, 1, rowind, colind, values);
}
#[test]
#[should_panic]
fn with_triplets_invalid_length() {
let rowind = vec![0; 2];
let colind = vec![1; 1];
let values = vec![1.0; 3];
CooMat::with_triplets(1, 1, rowind, colind, values);
}
#[test]
fn rows() {
let matrix: CooMat<f64> = CooMat::new(0, 1);
assert_eq!(matrix.rows(), 1);
let matrix: CooMat<f64> = CooMat::new(1, 1);
assert_eq!(matrix.rows(), 1);
let matrix: CooMat<f64> = CooMat::new(123, 1);
assert_eq!(matrix.rows(), 123);
}
#[test]
fn cols() {
let matrix: CooMat<f64> = CooMat::new(1, 0);
assert_eq!(matrix.cols(), 1);
let matrix: CooMat<f64> = CooMat::new(1, 1);
assert_eq!(matrix.cols(), 1);
let matrix: CooMat<f64> = CooMat::new(1, 123);
assert_eq!(matrix.cols(), 123);
}
#[test]
fn shape() {
let matrix: CooMat<f64> = CooMat::new(0, 0);
assert_eq!(matrix.shape(), (1, 1));
let matrix: CooMat<f64> = CooMat::new(1, 1);
assert_eq!(matrix.shape(), (1, 1));
let matrix: CooMat<f64> = CooMat::new(123, 123);
assert_eq!(matrix.shape(), (123, 123));
}
#[test]
fn capacity_new() {
let matrix: CooMat<f64> = CooMat::new(1, 1);
assert_eq!(matrix.capacity(), 0);
}
#[test]
fn capacity_with_capacity() {
let matrix: CooMat<f64> = CooMat::with_capacity(1, 1, 0);
assert_eq!(matrix.capacity(), 0);
let matrix: CooMat<f64> = CooMat::with_capacity(1, 1, 1);
assert_eq!(matrix.capacity(), 1);
let matrix: CooMat<f64> = CooMat::with_capacity(1, 1, 123);
assert_eq!(matrix.capacity(), 123);
}
#[test]
fn capacity_with_entries() {
let entries = vec![];
let matrix: CooMat<f64> = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.capacity(), 0);
let entries = vec![(0, 0, 1.0)];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.capacity(), 1);
let entries = vec![(0, 0, 1.0); 123];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.capacity(), 123);
}
#[test]
fn capacity_with_triplets() {
let rowind = vec![];
let colind = vec![];
let values: Vec<f64> = vec![];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.capacity(), 0);
let rowind = vec![0];
let colind = vec![0];
let values = vec![1.0];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.capacity(), 1);
let rowind = vec![0; 123];
let colind = vec![0; 123];
let values = vec![1.0; 123];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.capacity(), 123);
}
#[test]
fn reserve() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: Vec::new(),
};
assert_eq!(matrix.capacity(), 0);
matrix.reserve(10);
assert!(matrix.entries.capacity() >= 10);
}
#[test]
fn shrink() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: Vec::with_capacity(10),
};
assert_eq!(matrix.capacity(), 10);
matrix.shrink();
assert_eq!(matrix.capacity(), 0);
}
#[test]
fn length_new() {
let matrix: CooMat<f64> = CooMat::new(1, 1);
assert_eq!(matrix.len(), 0);
}
#[test]
fn length_with_capacity() {
let matrix: CooMat<f64> = CooMat::with_capacity(1, 1, 1);
assert_eq!(matrix.len(), 0);
}
#[test]
fn length_with_entries() {
let entries = vec![];
let matrix: CooMat<f64> = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.len(), 0);
let entries = vec![(0, 0, 1.0)];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.len(), 1);
let entries = vec![(0, 0, 1.0); 123];
let matrix = CooMat::with_entries(1, 1, entries);
assert_eq!(matrix.len(), 123);
}
#[test]
fn length_with_triplets() {
let rowind = vec![];
let colind = vec![];
let values: Vec<f64> = vec![];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.len(), 0);
let rowind = vec![0];
let colind = vec![0];
let values = vec![1.0];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.len(), 1);
let rowind = vec![0; 123];
let colind = vec![0; 123];
let values = vec![1.0; 123];
let matrix = CooMat::with_triplets(1, 1, rowind, colind, values);
assert_eq!(matrix.len(), 123);
}
#[test]
fn is_empty() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: Vec::new(),
};
assert!(matrix.is_empty());
matrix.push(0, 0, 1.0);
assert!(!matrix.is_empty());
}
#[test]
fn truncate() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
assert_eq!(matrix.len(), 4);
matrix.truncate(2);
assert_eq!(matrix.len(), 2);
}
#[test]
fn truncate_clear() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
assert_eq!(matrix.len(), 4);
matrix.truncate(0);
assert!(matrix.is_empty());
}
#[test]
fn truncate_noop() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
assert_eq!(matrix.len(), 4);
matrix.truncate(4);
assert_eq!(matrix.len(), 4);
}
#[test]
fn truncate_outofbounds() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
assert_eq!(matrix.len(), 4);
matrix.truncate(5);
assert_eq!(matrix.len(), 4);
}
#[test]
fn get() {
let matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![(0, 0, 1.0)],
};
assert_eq!(matrix.get(0), Some((&0, &0, &1.0)));
assert_eq!(matrix.get(1), None);
}
#[test]
fn get_mut() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![(0, 0, 1.0)],
};
assert_eq!(matrix.get_mut(0), Some((&0, &0, &mut 1.0)));
assert_eq!(matrix.get_mut(1), None);
}
#[test]
fn swap() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0)],
};
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
matrix.swap(0, 1);
assert_eq!(matrix.entries.get(0), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 0, 1.0)));
}
#[test]
#[should_panic]
fn swap_outofbounds() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![],
};
matrix.swap(0, 1);
}
#[test]
fn insert() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (1, 1, 4.0)],
};
matrix.insert(1, 0, 1, 2.0);
matrix.insert(2, 1, 0, 3.0);
assert_eq!(matrix.entries.len(), 4);
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
#[should_panic]
fn insert_outofbounds() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![],
};
matrix.insert(1, 0, 0, 1.0);
}
#[test]
fn remove() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![(0, 0, 1.0)],
};
assert_eq!(matrix.entries.len(), 1);
assert_eq!(matrix.remove(0), (0, 0, 1.0));
assert!(matrix.entries.is_empty());
}
#[test]
#[should_panic]
fn remove_outofbounds() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![],
};
matrix.remove(0);
}
#[test]
fn swap_remove() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
assert_eq!(matrix.entries.len(), 4);
assert_eq!(matrix.swap_remove(1), (0, 1, 2.0));
assert_eq!(matrix.entries.len(), 3);
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(1, 1, 4.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
}
#[test]
#[should_panic]
fn swap_remove_outofbounds() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![],
};
matrix.swap_remove(0);
}
#[test]
fn push() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![],
};
matrix.push(0, 0, 1.0);
assert_eq!(matrix.entries.len(), 1);
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
}
#[test]
fn pop() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![(0, 0, 1.0)],
};
assert_eq!(matrix.pop(), Some((0, 0, 1.0)));
assert!(matrix.entries.is_empty())
}
#[test]
fn retain() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
matrix.retain(|(r, c, v)| *v <= 3.0 && r != c);
assert_eq!(matrix.entries.len(), 2);
}
#[test]
fn clear() {
let mut matrix: CooMat<f64> = CooMat {
rows: 1,
cols: 1,
entries: vec![(0, 0, 1.0)],
};
matrix.clear();
assert!(matrix.entries.is_empty())
}
#[test]
fn sort_stable_row_major() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (1, 1, 4.0), (1, 0, 3.0), (0, 1, 2.0)],
};
matrix.sort_stable_row_major();
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
fn sort_unstable_row_major() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (1, 1, 4.0), (1, 0, 3.0), (0, 1, 2.0)],
};
matrix.sort_unstable_row_major();
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
fn sort_stable_col_major() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (1, 1, 4.0), (1, 0, 2.0), (0, 1, 3.0)],
};
matrix.sort_stable_col_major();
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(1, 0, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(0, 1, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
fn sort_unstable_col_major() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (1, 1, 4.0), (1, 0, 2.0), (0, 1, 3.0)],
};
matrix.sort_unstable_col_major();
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(1, 0, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(0, 1, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
fn reverse() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
matrix.reverse();
assert_eq!(matrix.entries.get(0), Some(&(1, 1, 4.0)));
assert_eq!(matrix.entries.get(1), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(2), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(3), Some(&(0, 0, 1.0)));
}
#[test]
fn iter() {
let matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
let mut iter = matrix.iter();
assert_eq!(iter.next(), Some((&0, &0, &1.0)));
assert_eq!(iter.next(), Some((&0, &1, &2.0)));
assert_eq!(iter.next(), Some((&1, &0, &3.0)));
assert_eq!(iter.next(), Some((&1, &1, &4.0)));
assert!(iter.next().is_none());
}
#[test]
fn iter_mut() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
let mut iter = matrix.iter_mut();
assert_eq!(iter.next(), Some((&0, &0, &mut 1.0)));
assert_eq!(iter.next(), Some((&0, &1, &mut 2.0)));
assert_eq!(iter.next(), Some((&1, &0, &mut 3.0)));
assert_eq!(iter.next(), Some((&1, &1, &mut 4.0)));
assert!(iter.next().is_none());
}
#[test]
fn extend() {
let mut matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![],
};
assert!(matrix.entries.is_empty());
matrix.extend(vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)]);
assert_eq!(matrix.entries.len(), 4);
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
fn from_iter() {
let entries = vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)];
let matrix = CooMat::from_iter(entries);
assert_eq!(matrix.entries.len(), 4);
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
#[test]
fn into_iter() {
let matrix: CooMat<f64> = CooMat {
rows: 2,
cols: 2,
entries: vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)],
};
let mut iter = matrix.into_iter();
assert_eq!(iter.next(), Some((0, 0, 1.0)));
assert_eq!(iter.next(), Some((0, 1, 2.0)));
assert_eq!(iter.next(), Some((1, 0, 3.0)));
assert_eq!(iter.next(), Some((1, 1, 4.0)));
assert!(iter.next().is_none());
}
#[test]
fn collect() {
let matrix: CooMat<_> = vec![(0, 0, 1.0), (0, 1, 2.0), (1, 0, 3.0), (1, 1, 4.0)]
.into_iter()
.collect();
assert_eq!(matrix.entries.len(), 4);
assert_eq!(matrix.entries.get(0), Some(&(0, 0, 1.0)));
assert_eq!(matrix.entries.get(1), Some(&(0, 1, 2.0)));
assert_eq!(matrix.entries.get(2), Some(&(1, 0, 3.0)));
assert_eq!(matrix.entries.get(3), Some(&(1, 1, 4.0)));
}
}