Test SparsityPattern and CSR try_* constructors
This commit is contained in:
parent
d98f2d2ad7
commit
df1ef991f3
|
@ -62,7 +62,7 @@ impl<T> CsrMatrix<T> {
|
|||
|
||||
/// The column indices defining part of the CSR format.
|
||||
#[inline]
|
||||
pub fn column_indices(&self) -> &[usize] {
|
||||
pub fn col_indices(&self) -> &[usize] {
|
||||
self.sparsity_pattern.minor_indices()
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ where
|
|||
type Item = CsrRowMut<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let lane = self.pattern.lane(self.current_row_idx);
|
||||
let lane = self.pattern.get_lane(self.current_row_idx);
|
||||
let ncols = self.pattern.minor_dim();
|
||||
|
||||
if let Some(col_indices) = lane {
|
||||
|
|
|
@ -103,7 +103,7 @@ impl SparseFormatError {
|
|||
}
|
||||
|
||||
/// The type of format error described by a [SparseFormatError](struct.SparseFormatError.html).
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SparseFormatErrorKind {
|
||||
/// Indicates that the index data associated with the format contains at least one index
|
||||
/// out of bounds.
|
||||
|
|
|
@ -66,8 +66,19 @@ impl SparsityPattern {
|
|||
}
|
||||
|
||||
/// Get the lane at the given index.
|
||||
///
|
||||
/// Panics
|
||||
/// ------
|
||||
///
|
||||
/// Panics if `major_index` is out of bounds.
|
||||
#[inline]
|
||||
pub fn lane(&self, major_index: usize) -> Option<&[usize]> {
|
||||
pub fn lane(&self, major_index: usize) -> &[usize] {
|
||||
self.get_lane(major_index).unwrap()
|
||||
}
|
||||
|
||||
/// Get the lane at the given index, or `None` if out of bounds.
|
||||
#[inline]
|
||||
pub fn get_lane(&self, major_index: usize) -> Option<&[usize]> {
|
||||
let offset_begin = *self.major_offsets().get(major_index)?;
|
||||
let offset_end = *self.major_offsets().get(major_index + 1)?;
|
||||
Some(&self.minor_indices()[offset_begin..offset_end])
|
||||
|
@ -124,7 +135,7 @@ impl SparsityPattern {
|
|||
let mut prev = None;
|
||||
|
||||
while let Some(next) = iter.next().copied() {
|
||||
if next > minor_dim {
|
||||
if next >= minor_dim {
|
||||
return Err(MinorIndexOutOfBounds);
|
||||
}
|
||||
|
||||
|
@ -197,7 +208,7 @@ impl SparsityPattern {
|
|||
|
||||
/// Error type for `SparsityPattern` format errors.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum SparsityPatternFormatError {
|
||||
/// Indicates an invalid number of offsets.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
use nalgebra_sparse::csr::CsrMatrix;
|
||||
use nalgebra_sparse::SparseFormatErrorKind;
|
||||
|
||||
#[test]
|
||||
fn csr_matrix_valid_data() {
|
||||
// Construct matrix from valid data and check that selected methods return results
|
||||
// that agree with expectations.
|
||||
|
||||
{
|
||||
// A CSR matrix with zero explicitly stored entries
|
||||
let offsets = vec![0, 0, 0, 0];
|
||||
let indices = vec![];
|
||||
let values = Vec::<i32>::new();
|
||||
let mut matrix = CsrMatrix::try_from_csr_data(3, 2, offsets, indices, values).unwrap();
|
||||
|
||||
assert_eq!(matrix, CsrMatrix::new(3, 2));
|
||||
|
||||
assert_eq!(matrix.nrows(), 3);
|
||||
assert_eq!(matrix.ncols(), 2);
|
||||
assert_eq!(matrix.nnz(), 0);
|
||||
assert_eq!(matrix.row_offsets(), &[0, 0, 0, 0]);
|
||||
assert_eq!(matrix.col_indices(), &[]);
|
||||
assert_eq!(matrix.values(), &[]);
|
||||
|
||||
assert!(matrix.triplet_iter().next().is_none());
|
||||
assert!(matrix.triplet_iter_mut().next().is_none());
|
||||
|
||||
assert_eq!(matrix.row(0).ncols(), 2);
|
||||
assert_eq!(matrix.row(0).nnz(), 0);
|
||||
assert_eq!(matrix.row(0).col_indices(), &[]);
|
||||
assert_eq!(matrix.row(0).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(0).ncols(), 2);
|
||||
assert_eq!(matrix.row_mut(0).nnz(), 0);
|
||||
assert_eq!(matrix.row_mut(0).col_indices(), &[]);
|
||||
assert_eq!(matrix.row_mut(0).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(0).values_mut(), &[]);
|
||||
assert_eq!(matrix.row_mut(0).cols_and_values_mut(), ([].as_ref(), [].as_mut()));
|
||||
|
||||
assert_eq!(matrix.row(1).ncols(), 2);
|
||||
assert_eq!(matrix.row(1).nnz(), 0);
|
||||
assert_eq!(matrix.row(1).col_indices(), &[]);
|
||||
assert_eq!(matrix.row(1).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).ncols(), 2);
|
||||
assert_eq!(matrix.row_mut(1).nnz(), 0);
|
||||
assert_eq!(matrix.row_mut(1).col_indices(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).values_mut(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).cols_and_values_mut(), ([].as_ref(), [].as_mut()));
|
||||
|
||||
assert_eq!(matrix.row(2).ncols(), 2);
|
||||
assert_eq!(matrix.row(2).nnz(), 0);
|
||||
assert_eq!(matrix.row(2).col_indices(), &[]);
|
||||
assert_eq!(matrix.row(2).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(2).ncols(), 2);
|
||||
assert_eq!(matrix.row_mut(2).nnz(), 0);
|
||||
assert_eq!(matrix.row_mut(2).col_indices(), &[]);
|
||||
assert_eq!(matrix.row_mut(2).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(2).values_mut(), &[]);
|
||||
assert_eq!(matrix.row_mut(2).cols_and_values_mut(), ([].as_ref(), [].as_mut()));
|
||||
|
||||
assert!(matrix.get_row(3).is_none());
|
||||
assert!(matrix.get_row_mut(3).is_none());
|
||||
|
||||
let (offsets, indices, values) = matrix.disassemble();
|
||||
|
||||
assert_eq!(offsets, vec![0, 0, 0, 0]);
|
||||
assert_eq!(indices, vec![]);
|
||||
assert_eq!(values, vec![]);
|
||||
}
|
||||
|
||||
{
|
||||
// An arbitrary CSR matrix
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let mut matrix = CsrMatrix::try_from_csr_data(3,
|
||||
6,
|
||||
offsets.clone(),
|
||||
indices.clone(),
|
||||
values.clone()).unwrap();
|
||||
|
||||
assert_eq!(matrix.nrows(), 3);
|
||||
assert_eq!(matrix.ncols(), 6);
|
||||
assert_eq!(matrix.nnz(), 5);
|
||||
assert_eq!(matrix.row_offsets(), &[0, 2, 2, 5]);
|
||||
assert_eq!(matrix.col_indices(), &[0, 5, 1, 2, 3]);
|
||||
assert_eq!(matrix.values(), &[0, 1, 2, 3, 4]);
|
||||
|
||||
let expected_triplets = vec![(0, 0, 0), (0, 5, 1), (2, 1, 2), (2, 2, 3), (2, 3, 4)];
|
||||
assert_eq!(matrix.triplet_iter().map(|(i, j, v)| (i, j, *v)).collect::<Vec<_>>(),
|
||||
expected_triplets);
|
||||
assert_eq!(matrix.triplet_iter_mut().map(|(i, j, v)| (i, j, *v)).collect::<Vec<_>>(),
|
||||
expected_triplets);
|
||||
|
||||
assert_eq!(matrix.row(0).ncols(), 6);
|
||||
assert_eq!(matrix.row(0).nnz(), 2);
|
||||
assert_eq!(matrix.row(0).col_indices(), &[0, 5]);
|
||||
assert_eq!(matrix.row(0).values(), &[0, 1]);
|
||||
assert_eq!(matrix.row_mut(0).ncols(), 6);
|
||||
assert_eq!(matrix.row_mut(0).nnz(), 2);
|
||||
assert_eq!(matrix.row_mut(0).col_indices(), &[0, 5]);
|
||||
assert_eq!(matrix.row_mut(0).values(), &[0, 1]);
|
||||
assert_eq!(matrix.row_mut(0).values_mut(), &[0, 1]);
|
||||
assert_eq!(matrix.row_mut(0).cols_and_values_mut(), ([0, 5].as_ref(), [0, 1].as_mut()));
|
||||
|
||||
assert_eq!(matrix.row(1).ncols(), 6);
|
||||
assert_eq!(matrix.row(1).nnz(), 0);
|
||||
assert_eq!(matrix.row(1).col_indices(), &[]);
|
||||
assert_eq!(matrix.row(1).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).ncols(), 6);
|
||||
assert_eq!(matrix.row_mut(1).nnz(), 0);
|
||||
assert_eq!(matrix.row_mut(1).col_indices(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).values(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).values_mut(), &[]);
|
||||
assert_eq!(matrix.row_mut(1).cols_and_values_mut(), ([].as_ref(), [].as_mut()));
|
||||
|
||||
assert_eq!(matrix.row(2).ncols(), 6);
|
||||
assert_eq!(matrix.row(2).nnz(), 3);
|
||||
assert_eq!(matrix.row(2).col_indices(), &[1, 2, 3]);
|
||||
assert_eq!(matrix.row(2).values(), &[2, 3, 4]);
|
||||
assert_eq!(matrix.row_mut(2).ncols(), 6);
|
||||
assert_eq!(matrix.row_mut(2).nnz(), 3);
|
||||
assert_eq!(matrix.row_mut(2).col_indices(), &[1, 2, 3]);
|
||||
assert_eq!(matrix.row_mut(2).values(), &[2, 3, 4]);
|
||||
assert_eq!(matrix.row_mut(2).values_mut(), &[2, 3, 4]);
|
||||
assert_eq!(matrix.row_mut(2).cols_and_values_mut(), ([1, 2, 3].as_ref(), [2, 3, 4].as_mut()));
|
||||
|
||||
assert!(matrix.get_row(3).is_none());
|
||||
assert!(matrix.get_row_mut(3).is_none());
|
||||
|
||||
let (offsets2, indices2, values2) = matrix.disassemble();
|
||||
|
||||
assert_eq!(offsets2, offsets);
|
||||
assert_eq!(indices2, indices);
|
||||
assert_eq!(values2, values);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csr_matrix_try_from_invalid_csr_data() {
|
||||
|
||||
{
|
||||
// Empty offset array (invalid length)
|
||||
let matrix = CsrMatrix::try_from_csr_data(0, 0, Vec::new(), Vec::new(), Vec::<u32>::new());
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Offset array invalid length for arbitrary data
|
||||
let offsets = vec![0, 3, 5];
|
||||
let indices = vec![0, 1, 2, 3, 5];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid first entry in offsets array
|
||||
let offsets = vec![1, 2, 2, 5];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid last entry in offsets array
|
||||
let offsets = vec![0, 2, 2, 4];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid length of offsets array
|
||||
let offsets = vec![0, 2, 2];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Nonmonotonic offsets
|
||||
let offsets = vec![0, 3, 2, 5];
|
||||
let indices = vec![0, 1, 2, 3, 4];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Nonmonotonic minor indices
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 2, 3, 1, 4];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::InvalidStructure);
|
||||
}
|
||||
|
||||
{
|
||||
// Minor index out of bounds
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 6, 1, 2, 3];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::IndexOutOfBounds);
|
||||
}
|
||||
|
||||
{
|
||||
// Duplicate entry
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 5, 2, 2, 3];
|
||||
let values = vec![0, 1, 2, 3, 4];
|
||||
let matrix = CsrMatrix::try_from_csr_data(3, 6, offsets, indices, values);
|
||||
assert_eq!(matrix.unwrap_err().kind(), &SparseFormatErrorKind::DuplicateEntry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csr_matrix_get_index() {
|
||||
// TODO: Implement tests for ::get() and index()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csr_matrix_row_iter() {
|
||||
|
||||
}
|
|
@ -1,2 +1,4 @@
|
|||
mod coo;
|
||||
mod ops;
|
||||
mod ops;
|
||||
mod pattern;
|
||||
mod csr;
|
|
@ -0,0 +1,130 @@
|
|||
use nalgebra_sparse::pattern::{SparsityPattern, SparsityPatternFormatError};
|
||||
|
||||
#[test]
|
||||
fn sparsity_pattern_valid_data() {
|
||||
// Construct pattern from valid data and check that selected methods return results
|
||||
// that agree with expectations.
|
||||
|
||||
{
|
||||
// A pattern with zero explicitly stored entries
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3,
|
||||
2,
|
||||
vec![0, 0, 0, 0],
|
||||
Vec::new())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(pattern.major_dim(), 3);
|
||||
assert_eq!(pattern.minor_dim(), 2);
|
||||
assert_eq!(pattern.nnz(), 0);
|
||||
assert_eq!(pattern.major_offsets(), &[0, 0, 0, 0]);
|
||||
assert_eq!(pattern.minor_indices(), &[]);
|
||||
assert_eq!(pattern.lane(0), &[]);
|
||||
assert_eq!(pattern.lane(1), &[]);
|
||||
assert_eq!(pattern.lane(2), &[]);
|
||||
assert!(pattern.entries().next().is_none());
|
||||
|
||||
assert_eq!(pattern, SparsityPattern::new(3, 2));
|
||||
|
||||
let (offsets, indices) = pattern.disassemble();
|
||||
assert_eq!(offsets, vec![0, 0, 0, 0]);
|
||||
assert_eq!(indices, vec![]);
|
||||
}
|
||||
|
||||
{
|
||||
// Arbitrary pattern
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let pattern =
|
||||
SparsityPattern::try_from_offsets_and_indices(3, 6, offsets.clone(), indices.clone())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(pattern.major_dim(), 3);
|
||||
assert_eq!(pattern.minor_dim(), 6);
|
||||
assert_eq!(pattern.major_offsets(), offsets.as_slice());
|
||||
assert_eq!(pattern.minor_indices(), indices.as_slice());
|
||||
assert_eq!(pattern.nnz(), 5);
|
||||
assert_eq!(pattern.lane(0), &[0, 5]);
|
||||
assert_eq!(pattern.lane(1), &[]);
|
||||
assert_eq!(pattern.lane(2), &[1, 2, 3]);
|
||||
assert_eq!(pattern.entries().collect::<Vec<_>>(),
|
||||
vec![(0, 0), (0, 5), (2, 1), (2, 2), (2, 3)]);
|
||||
|
||||
let (offsets2, indices2) = pattern.disassemble();
|
||||
assert_eq!(offsets2, offsets);
|
||||
assert_eq!(indices2, indices);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sparsity_pattern_try_from_invalid_data() {
|
||||
{
|
||||
// Empty offset array (invalid length)
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(0, 0, Vec::new(), Vec::new());
|
||||
assert_eq!(pattern, Err(SparsityPatternFormatError::InvalidOffsetArrayLength));
|
||||
}
|
||||
|
||||
{
|
||||
// Offset array invalid length for arbitrary data
|
||||
let offsets = vec![0, 3, 5];
|
||||
let indices = vec![0, 1, 2, 3, 5];
|
||||
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert!(matches!(pattern, Err(SparsityPatternFormatError::InvalidOffsetArrayLength)));
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid first entry in offsets array
|
||||
let offsets = vec![1, 2, 2, 5];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert!(matches!(pattern, Err(SparsityPatternFormatError::InvalidOffsetFirstLast)));
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid last entry in offsets array
|
||||
let offsets = vec![0, 2, 2, 4];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert!(matches!(pattern, Err(SparsityPatternFormatError::InvalidOffsetFirstLast)));
|
||||
}
|
||||
|
||||
{
|
||||
// Invalid length of offsets array
|
||||
let offsets = vec![0, 2, 2];
|
||||
let indices = vec![0, 5, 1, 2, 3];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert!(matches!(pattern, Err(SparsityPatternFormatError::InvalidOffsetArrayLength)));
|
||||
}
|
||||
|
||||
{
|
||||
// Nonmonotonic offsets
|
||||
let offsets = vec![0, 3, 2, 5];
|
||||
let indices = vec![0, 1, 2, 3, 4];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert_eq!(pattern, Err(SparsityPatternFormatError::NonmonotonicOffsets));
|
||||
}
|
||||
|
||||
{
|
||||
// Nonmonotonic minor indices
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 2, 3, 1, 4];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert_eq!(pattern, Err(SparsityPatternFormatError::NonmonotonicMinorIndices));
|
||||
}
|
||||
|
||||
{
|
||||
// Minor index out of bounds
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 6, 1, 2, 3];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert_eq!(pattern, Err(SparsityPatternFormatError::MinorIndexOutOfBounds));
|
||||
}
|
||||
|
||||
{
|
||||
// Duplicate entry
|
||||
let offsets = vec![0, 2, 2, 5];
|
||||
let indices = vec![0, 5, 2, 2, 3];
|
||||
let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices);
|
||||
assert_eq!(pattern, Err(SparsityPatternFormatError::DuplicateEntry));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue