Initial COO <-> Dense conversion routines
This commit is contained in:
parent
7260f05b07
commit
54329146c9
26
nalgebra-sparse/src/convert/impl_std_ops.rs
Normal file
26
nalgebra-sparse/src/convert/impl_std_ops.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use crate::coo::CooMatrix;
|
||||
use crate::convert::serial::{convert_dense_coo, convert_coo_dense};
|
||||
use nalgebra::{Matrix, Scalar, Dim, ClosedAdd, DMatrix};
|
||||
use nalgebra::storage::{Storage};
|
||||
use num_traits::Zero;
|
||||
|
||||
impl<'a, T, R, C, S> From<&'a Matrix<T, R, C, S>> for CooMatrix<T>
|
||||
where
|
||||
T: Scalar + Zero,
|
||||
R: Dim,
|
||||
C: Dim,
|
||||
S: Storage<T, R, C>
|
||||
{
|
||||
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
|
||||
convert_dense_coo(matrix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<&'a CooMatrix<T>> for DMatrix<T>
|
||||
where
|
||||
T: Scalar + Zero + ClosedAdd,
|
||||
{
|
||||
fn from(coo: &'a CooMatrix<T>) -> Self {
|
||||
convert_coo_dense(coo)
|
||||
}
|
||||
}
|
5
nalgebra-sparse/src/convert/mod.rs
Normal file
5
nalgebra-sparse/src/convert/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
//! TODO
|
||||
|
||||
pub mod serial;
|
||||
|
||||
mod impl_std_ops;
|
48
nalgebra-sparse/src/convert/serial.rs
Normal file
48
nalgebra-sparse/src/convert/serial.rs
Normal file
@ -0,0 +1,48 @@
|
||||
//! TODO
|
||||
use nalgebra::{DMatrix, Scalar, Matrix, Dim};
|
||||
use crate::coo::CooMatrix;
|
||||
use crate::csr::CsrMatrix;
|
||||
use num_traits::Zero;
|
||||
use std::ops::{Add, AddAssign};
|
||||
use nalgebra::storage::Storage;
|
||||
|
||||
/// TODO
|
||||
pub fn convert_dense_coo<T, R, C, S>(dense: &Matrix<T, R, C, S>) -> CooMatrix<T>
|
||||
where
|
||||
T: Scalar + Zero,
|
||||
R: Dim,
|
||||
C: Dim,
|
||||
S: Storage<T, R, C>
|
||||
{
|
||||
let mut coo = CooMatrix::new(dense.nrows(), dense.ncols());
|
||||
|
||||
for (index, v) in dense.iter().enumerate() {
|
||||
if v != &T::zero() {
|
||||
// We use the fact that matrix iteration is guaranteed to be column-major
|
||||
let i = index % dense.nrows();
|
||||
let j = index / dense.nrows();
|
||||
coo.push(i, j, v.inlined_clone());
|
||||
}
|
||||
}
|
||||
|
||||
coo
|
||||
}
|
||||
|
||||
/// TODO
|
||||
///
|
||||
/// TODO: What should the actual trait bounds be?
|
||||
pub fn convert_coo_dense<T>(coo: &CooMatrix<T>) -> DMatrix<T>
|
||||
where
|
||||
T: Scalar + Zero + Add + AddAssign,
|
||||
{
|
||||
let mut output = DMatrix::repeat(coo.nrows(), coo.ncols(), T::zero());
|
||||
for (i, j, v) in coo.triplet_iter() {
|
||||
output[(i, j)] += v.inlined_clone();
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn convert_coo_csr<T>(_coo: &CooMatrix<T>) -> CsrMatrix<T> {
|
||||
todo!()
|
||||
}
|
@ -186,6 +186,8 @@ where
|
||||
/// Construct the dense representation of the COO matrix.
|
||||
///
|
||||
/// Duplicate entries are summed together.
|
||||
///
|
||||
/// TODO: Remove?
|
||||
pub fn to_dense(&self) -> DMatrix<T>
|
||||
where
|
||||
T: ClosedAdd + Zero,
|
||||
|
@ -68,6 +68,11 @@
|
||||
//! - Cholesky factorization (port existing factorization from nalgebra's sparse module)
|
||||
//!
|
||||
//!
|
||||
//! TODO: Write docs on the following:
|
||||
//!
|
||||
//! - Overall design ("easy API" vs. "expert" API etc.)
|
||||
//! - Conversions (From, explicit "expert" API etc.)
|
||||
//! - Matrix ops design
|
||||
#![deny(non_camel_case_types)]
|
||||
#![deny(unused_parens)]
|
||||
#![deny(non_upper_case_globals)]
|
||||
@ -80,6 +85,7 @@ pub mod csc;
|
||||
pub mod csr;
|
||||
pub mod pattern;
|
||||
pub mod ops;
|
||||
pub mod convert;
|
||||
|
||||
#[cfg(feature = "proptest-support")]
|
||||
pub mod proptest;
|
||||
|
84
nalgebra-sparse/tests/unit_tests/convert_serial.rs
Normal file
84
nalgebra-sparse/tests/unit_tests/convert_serial.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use nalgebra_sparse::coo::CooMatrix;
|
||||
use nalgebra_sparse::convert::serial::{convert_coo_dense, convert_dense_coo};
|
||||
use nalgebra_sparse::proptest::coo_with_duplicates;
|
||||
use nalgebra::proptest::matrix;
|
||||
use proptest::prelude::*;
|
||||
use nalgebra::DMatrix;
|
||||
|
||||
#[test]
|
||||
fn test_convert_dense_coo() {
|
||||
// No duplicates
|
||||
{
|
||||
#[rustfmt::skip]
|
||||
let entries = &[1, 0, 3,
|
||||
0, 5, 0];
|
||||
// The COO representation of a dense matrix is not unique.
|
||||
// Here we implicitly test that the coo matrix is indeed constructed from column-major
|
||||
// iteration of the dense matrix.
|
||||
let dense = DMatrix::from_row_slice(2, 3, entries);
|
||||
let coo = CooMatrix::try_from_triplets(2, 3, vec![0, 1, 0], vec![0, 1, 2], vec![1, 5, 3])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(CooMatrix::from(&dense), coo);
|
||||
assert_eq!(DMatrix::from(&coo), dense);
|
||||
}
|
||||
|
||||
// Duplicates
|
||||
// No duplicates
|
||||
{
|
||||
#[rustfmt::skip]
|
||||
let entries = &[1, 0, 3,
|
||||
0, 5, 0];
|
||||
// The COO representation of a dense matrix is not unique.
|
||||
// Here we implicitly test that the coo matrix is indeed constructed from column-major
|
||||
// iteration of the dense matrix.
|
||||
let dense = DMatrix::from_row_slice(2, 3, entries);
|
||||
let coo_no_dup = CooMatrix::try_from_triplets(2, 3,
|
||||
vec![0, 1, 0],
|
||||
vec![0, 1, 2],
|
||||
vec![1, 5, 3])
|
||||
.unwrap();
|
||||
let coo_dup = CooMatrix::try_from_triplets(2, 3,
|
||||
vec![0, 1, 0, 1],
|
||||
vec![0, 1, 2, 1],
|
||||
vec![1, -2, 3, 7])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(CooMatrix::from(&dense), coo_no_dup);
|
||||
assert_eq!(DMatrix::from(&coo_dup), dense);
|
||||
}
|
||||
}
|
||||
|
||||
fn coo_strategy() -> impl Strategy<Value=CooMatrix<i32>> {
|
||||
coo_with_duplicates(-5 ..= 5, 0..=6usize, 0..=6usize, 40, 2)
|
||||
}
|
||||
|
||||
proptest! {
|
||||
|
||||
#[test]
|
||||
fn convert_dense_coo_roundtrip(dense in matrix(-5 ..= 5, 0 ..=6, 0..=6)) {
|
||||
let coo = convert_dense_coo(&dense);
|
||||
let dense2 = convert_coo_dense(&coo);
|
||||
prop_assert_eq!(&dense, &dense2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_coo_dense_coo_roundtrip(coo in coo_strategy()) {
|
||||
// We cannot compare the result of the roundtrip coo -> dense -> coo directly for
|
||||
// two reasons:
|
||||
// 1. the COO matrices will generally have different ordering of elements
|
||||
// 2. explicitly stored zero entries in the original matrix will be discarded
|
||||
// when converting back to COO
|
||||
// Therefore we instead compare the results of converting the COO matrix
|
||||
// at the end of the roundtrip with its dense representation
|
||||
let dense = convert_coo_dense(&coo);
|
||||
let coo2 = convert_dense_coo(&dense);
|
||||
let dense2 = convert_coo_dense(&coo2);
|
||||
prop_assert_eq!(dense, dense2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_dense_coo_roundtrip(dense in matrix(-5..=5, 0..=6, 0..=6)) {
|
||||
prop_assert_eq!(&dense, &DMatrix::from(&CooMatrix::from(&dense)));
|
||||
}
|
||||
}
|
@ -3,4 +3,5 @@ mod ops;
|
||||
mod pattern;
|
||||
mod csr;
|
||||
mod csc;
|
||||
mod convert_serial;
|
||||
mod proptest;
|
Loading…
Reference in New Issue
Block a user