Initial COO <-> Dense conversion routines
This commit is contained in:
parent
7260f05b07
commit
54329146c9
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
//! TODO
|
||||||
|
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
|
mod impl_std_ops;
|
|
@ -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.
|
/// Construct the dense representation of the COO matrix.
|
||||||
///
|
///
|
||||||
/// Duplicate entries are summed together.
|
/// Duplicate entries are summed together.
|
||||||
|
///
|
||||||
|
/// TODO: Remove?
|
||||||
pub fn to_dense(&self) -> DMatrix<T>
|
pub fn to_dense(&self) -> DMatrix<T>
|
||||||
where
|
where
|
||||||
T: ClosedAdd + Zero,
|
T: ClosedAdd + Zero,
|
||||||
|
|
|
@ -68,6 +68,11 @@
|
||||||
//! - Cholesky factorization (port existing factorization from nalgebra's sparse module)
|
//! - 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(non_camel_case_types)]
|
||||||
#![deny(unused_parens)]
|
#![deny(unused_parens)]
|
||||||
#![deny(non_upper_case_globals)]
|
#![deny(non_upper_case_globals)]
|
||||||
|
@ -80,6 +85,7 @@ pub mod csc;
|
||||||
pub mod csr;
|
pub mod csr;
|
||||||
pub mod pattern;
|
pub mod pattern;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
|
pub mod convert;
|
||||||
|
|
||||||
#[cfg(feature = "proptest-support")]
|
#[cfg(feature = "proptest-support")]
|
||||||
pub mod proptest;
|
pub mod proptest;
|
||||||
|
|
|
@ -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 pattern;
|
||||||
mod csr;
|
mod csr;
|
||||||
mod csc;
|
mod csc;
|
||||||
|
mod convert_serial;
|
||||||
mod proptest;
|
mod proptest;
|
Loading…
Reference in New Issue