From d511e372de5a5555ea44f3f681f98f17dd498e09 Mon Sep 17 00:00:00 2001 From: Hantao Hui Date: Mon, 24 Jan 2022 23:17:30 +0100 Subject: [PATCH 01/11] add support for matrix market export --- nalgebra-sparse/Cargo.toml | 2 +- nalgebra-sparse/src/io/matrix_market.rs | 133 +++++++++++++++++- nalgebra-sparse/src/io/mod.rs | 6 +- .../tests/unit_tests/matrix_market.rs | 59 +++++++- 4 files changed, 190 insertions(+), 10 deletions(-) diff --git a/nalgebra-sparse/Cargo.toml b/nalgebra-sparse/Cargo.toml index 6f7a7b4a..0dfe743f 100644 --- a/nalgebra-sparse/Cargo.toml +++ b/nalgebra-sparse/Cargo.toml @@ -37,4 +37,4 @@ nalgebra = { version="0.30", path = "../", features = ["compare"] } [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs -features = [ "proptest-support", "compare" ] \ No newline at end of file +features = [ "proptest-support", "compare" , "io"] \ No newline at end of file diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index dea284ee..924efcf8 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1,9 +1,10 @@ //! Implementation of matrix market io code. //! //! See the [website](https://math.nist.gov/MatrixMarket/formats.html) or the [paper](https://www.researchgate.net/publication/2630533_The_Matrix_Market_Exchange_Formats_Initial_Design) for more details about matrix market. -use crate::coo::CooMatrix; +use crate::CooMatrix; use crate::SparseFormatError; use crate::SparseFormatErrorKind; +use matrixcompare_core::SparseAccess; use nalgebra::Complex; use pest::iterators::Pairs; use pest::Parser; @@ -12,7 +13,8 @@ use std::convert::Infallible; use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; -use std::fs; +use std::fs::{self, File}; +use std::io::Write; use std::num::ParseIntError; use std::num::TryFromIntError; use std::path::Path; @@ -267,7 +269,7 @@ impl fmt::Display for MatrixMarketError { write!(f, "InvalidHeader,")?; } MatrixMarketErrorKind::EntryMismatch => { - write!(f, "EntryNumUnmatched,")?; + write!(f, "EntryMismatch,")?; } MatrixMarketErrorKind::TypeMismatch => { write!(f, "TypeMismatch,")?; @@ -288,7 +290,7 @@ impl fmt::Display for MatrixMarketError { write!(f, "NotLowerTriangle,")?; } MatrixMarketErrorKind::NonSquare => { - write!(f, "NotSquareMatrix,")?; + write!(f, "NonSquare,")?; } } write!(f, " message: {}", self.message) @@ -506,6 +508,10 @@ mod internal { fn negative(self) -> Result; /// When matrix is a Hermitian matrix, it will convert itself to its conjugate. fn conjugate(self) -> Result; + /// Returns the name of SupportedMatrixMarketScalar, used when write the matrix + fn typename() -> &'static str; + /// Convert the data to string + fn to_matrixmarket_string(&self) -> String; } } @@ -557,6 +563,14 @@ macro_rules! mm_int_impl { fn negative(self) -> Result { Ok(-self) } + #[inline] + fn typename() -> &'static str { + "integer" + } + #[inline] + fn to_matrixmarket_string(&self) -> String { + self.to_string() + } } }; } @@ -602,6 +616,14 @@ macro_rules! mm_real_impl { fn negative(self) -> Result { Ok(-self) } + #[inline] + fn typename() -> &'static str { + "real" + } + #[inline] + fn to_matrixmarket_string(&self) -> String { + self.to_string() + } } }; } @@ -648,6 +670,14 @@ macro_rules! mm_complex_impl { fn negative(self) -> Result { Ok(-self) } + #[inline] + fn typename() -> &'static str { + "complex" + } + #[inline] + fn to_matrixmarket_string(&self) -> String { + self.re.to_string() + " " + &self.im.to_string() + } } }; } @@ -697,6 +727,15 @@ macro_rules! mm_pattern_impl { format!("Pattern type has no negative"), )) } + #[inline] + fn typename() -> &'static str { + "pattern" + } + #[inline] + fn to_matrixmarket_string(&self) -> String { + // pattern type will return an empty string + String::new() + } } }; } @@ -1329,3 +1368,89 @@ fn next_dense_coordinate( } } } + +/// Write a sparse matrix into Matrix Market format string. +/// +/// Our exporter only writes matrix into `coordiante` and `general` format. +/// +/// +/// Examples +/// -------- +/// ``` +/// # use matrixcompare::assert_matrix_eq; +/// use nalgebra_sparse::io::{write_to_matrix_market_str,load_coo_from_matrix_market_str}; +/// let str = r#" +/// %%matrixmarket matrix coordinate integer general +/// 5 4 2 +/// 1 1 10 +/// 2 3 5 +/// "#; +/// let matrix = load_coo_from_matrix_market_str::(&str).unwrap(); +/// let generated_matrixmarket_string = write_to_matrix_market_str(&matrix); +/// // 'generated_matrixmarket' should equal to the 'matrix' +/// let generated_matrixmarket = load_coo_from_matrix_market_str::(&generated_matrixmarket_string).unwrap(); +/// assert_matrix_eq!(matrix,generated_matrixmarket); +/// ``` +pub fn write_to_matrix_market_str>( + sparse_matrix: &S, +) -> String { + let mut matrixmarket_string = String::new(); + // write header + matrixmarket_string.push_str("%%matrixmarket matrix coordinate "); + matrixmarket_string.push_str(T::typename()); + matrixmarket_string.push_str(" general\n% matrixmarket file generated by nalgebra-sparse.\n"); + // write shape information + matrixmarket_string.push_str(&sparse_matrix.rows().to_string()); + matrixmarket_string.push(' '); + matrixmarket_string.push_str(&sparse_matrix.cols().to_string()); + matrixmarket_string.push(' '); + matrixmarket_string.push_str(&sparse_matrix.nnz().to_string()); + matrixmarket_string.push('\n'); + + for (r, c, d) in sparse_matrix.fetch_triplets() { + matrixmarket_string.push_str(&(r + 1).to_string()); + matrixmarket_string.push_str(" "); + matrixmarket_string.push_str(&(c + 1).to_string()); + matrixmarket_string.push_str(" "); + matrixmarket_string.push_str(&d.to_matrixmarket_string()); + matrixmarket_string.push_str("\n"); + } + + matrixmarket_string +} + +/// Write a sparse matrix into Matrix Market format file. +/// +/// Our exporter only writes matrix into `coordiante` and `general` format. +/// +/// +/// Errors +/// -------- +/// +/// See [MatrixMarketErrorKind] for a list of possible error conditions. +/// +/// Examples +/// -------- +/// ``` +/// use nalgebra_sparse::io::{write_to_matrix_market_file,load_coo_from_matrix_market_str}; +/// let str = r#" +/// %%matrixmarket matrix coordinate integer general +/// 5 4 2 +/// 1 1 10 +/// 2 3 5 +/// "#; +/// let matrix = load_coo_from_matrix_market_str::(&str).unwrap(); +/// let res = write_to_matrix_market_file(&matrix,"path/to/matrix.mtx"); +/// if res.is_err(){ +/// // do something +/// } +/// ``` +pub fn write_to_matrix_market_file, P: AsRef>( + matrix: &S, + path: P, +) -> Result<(), MatrixMarketError> { + let matrixmarket_string = write_to_matrix_market_str(matrix); + let mut file = File::create(path)?; + write!(file, "{}", matrixmarket_string)?; + Ok(()) +} diff --git a/nalgebra-sparse/src/io/mod.rs b/nalgebra-sparse/src/io/mod.rs index 89b21ffb..ff61fb6c 100644 --- a/nalgebra-sparse/src/io/mod.rs +++ b/nalgebra-sparse/src/io/mod.rs @@ -6,7 +6,7 @@ //! //! | Format | Import | Export | //! | ------------------------------------------------|------------|------------| -//! | [Matrix market](#matrix-market-format) | Yes | No | +//! | [Matrix market](#matrix-market-format) | Yes | Yes | //! //! [Matrix market]: https://math.nist.gov/MatrixMarket/formats.html //! @@ -32,7 +32,7 @@ //! > "*The Matrix Market Exchange Formats: Initial Design.*" (1996). pub use self::matrix_market::{ - load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, MatrixMarketError, - MatrixMarketErrorKind, MatrixMarketScalar, + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market_file, + write_to_matrix_market_str, MatrixMarketError, MatrixMarketErrorKind, MatrixMarketScalar, }; mod matrix_market; diff --git a/nalgebra-sparse/tests/unit_tests/matrix_market.rs b/nalgebra-sparse/tests/unit_tests/matrix_market.rs index 48ff1a78..5d109a9c 100644 --- a/nalgebra-sparse/tests/unit_tests/matrix_market.rs +++ b/nalgebra-sparse/tests/unit_tests/matrix_market.rs @@ -1,7 +1,7 @@ use matrixcompare::assert_matrix_eq; use nalgebra::dmatrix; use nalgebra::Complex; -use nalgebra_sparse::io::load_coo_from_matrix_market_str; +use nalgebra_sparse::io::{load_coo_from_matrix_market_str, write_to_matrix_market_str}; use nalgebra_sparse::CooMatrix; #[test] @@ -19,6 +19,10 @@ fn test_matrixmarket_sparse_real_general_empty() { assert_eq!(sparse_mat.nrows(), shape.0); assert_eq!(sparse_mat.ncols(), shape.1); assert_eq!(sparse_mat.nnz(), 0); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(sparse_mat, generated_matrix); } } @@ -37,6 +41,10 @@ fn test_matrixmarket_dense_real_general_empty() { assert_eq!(sparse_mat.nrows(), shape.0); assert_eq!(sparse_mat.ncols(), shape.1); assert_eq!(sparse_mat.nnz(), 0); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(sparse_mat, generated_matrix); } } @@ -97,6 +105,10 @@ fn test_matrixmarket_sparse_real_general() { 0.0, 0.0, 0.0, 0.0, 12.0; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -125,6 +137,10 @@ fn test_matrixmarket_sparse_int_symmetric() { -15, 0, 35, 0, 55; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -152,6 +168,10 @@ fn test_matrixmarket_sparse_complex_hermitian() { Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:33.32},Complex::{re:12.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::>(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -175,6 +195,10 @@ fn test_matrixmarket_sparse_real_skew() { -15.0, 0.0, -35.0, 0.0, 0.0; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -198,7 +222,7 @@ fn test_matrixmarket_sparse_pattern_general() { let pattern_matrix = load_coo_from_matrix_market_str::<()>(file_str).unwrap(); let nrows = pattern_matrix.nrows(); let ncols = pattern_matrix.ncols(); - let (row_idx, col_idx, val) = pattern_matrix.disassemble(); + let (row_idx, col_idx, val) = pattern_matrix.clone().disassemble(); let values = vec![1; val.len()]; let sparse_mat = CooMatrix::try_from_triplets(nrows, ncols, row_idx, col_idx, values).unwrap(); let expected = dmatrix![ @@ -209,6 +233,17 @@ fn test_matrixmarket_sparse_pattern_general() { 0, 1, 0, 1, 1; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&pattern_matrix); + let generated_matrix = load_coo_from_matrix_market_str::<()>(&generated_matrixmarket_str).unwrap(); + + let nrows = generated_matrix.nrows(); + let ncols = generated_matrix.ncols(); + let (row_idx, col_idx, val) = generated_matrix.clone().disassemble(); + let values = vec![1; val.len()]; + let generated_sparse_mat = CooMatrix::try_from_triplets(nrows, ncols, row_idx, col_idx, values).unwrap(); + + assert_matrix_eq!(expected, generated_sparse_mat); } #[test] @@ -240,6 +275,10 @@ fn test_matrixmarket_dense_real_general() { 4.0, 8.0, 12.0; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -269,6 +308,10 @@ fn test_matrixmarket_dense_real_symmetric() { 4.0, 7.0, 9.0, 10.0; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -298,6 +341,10 @@ fn test_matrixmarket_dense_complex_hermitian() { Complex::{re:4.0,im:4.0}, Complex::{re:7.0,im:7.0} ,Complex::{re:9.0,im:9.0} ,Complex::{re:10.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::>(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -322,6 +369,10 @@ fn test_matrixmarket_dense_int_skew() { 3, 5, 6, 0; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } #[test] @@ -342,4 +393,8 @@ fn test_matrixmarket_dense_complex_general() { Complex::{re:1.0,im:0.0},Complex::{re:1.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); + + let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); + let generated_matrix = load_coo_from_matrix_market_str::>(&generated_matrixmarket_str).unwrap(); + assert_matrix_eq!(expected, generated_matrix); } From 8904c01c7b9c5d49fcfb08f27ec6ee3dbc60509a Mon Sep 17 00:00:00 2001 From: Hantao Hui Date: Thu, 3 Feb 2022 11:49:15 +0100 Subject: [PATCH 02/11] export to file directly; add a new trait for export --- nalgebra-sparse/src/io/matrix_market.rs | 115 +++++++++++++++++++++--- nalgebra-sparse/src/io/mod.rs | 3 +- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index 924efcf8..d00a873d 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1,10 +1,9 @@ //! Implementation of matrix market io code. //! //! See the [website](https://math.nist.gov/MatrixMarket/formats.html) or the [paper](https://www.researchgate.net/publication/2630533_The_Matrix_Market_Exchange_Formats_Initial_Design) for more details about matrix market. -use crate::CooMatrix; use crate::SparseFormatError; use crate::SparseFormatErrorKind; -use matrixcompare_core::SparseAccess; +use crate::{CooMatrix, CscMatrix, CsrMatrix}; use nalgebra::Complex; use pest::iterators::Pairs; use pest::Parser; @@ -513,6 +512,17 @@ mod internal { /// Convert the data to string fn to_matrixmarket_string(&self) -> String; } + + pub trait SupportedMatrixMarketExport { + /// iterate over triplets + fn triplet_iter(&self) -> Box + '_>; + /// number of rows + fn nrows(&self) -> usize; + /// number of columns + fn ncols(&self) -> usize; + /// number of non-zeros + fn nnz(&self) -> usize; + } } /// A marker trait for supported matrix market scalars. @@ -754,6 +764,46 @@ mm_complex_impl!(f64); mm_pattern_impl!(()); +/// A marker trait for supported sparse matrix types. +/// +/// This is a sealed trait; it cannot be implemented by external crates. This is done in order to prevent leaking +/// some of the implementation details we currently rely on. We may relax this restriction in the future. +pub trait MatrixMarketExport: + internal::SupportedMatrixMarketExport +{ +} + +macro_rules! mm_matrix_impl { + ($T_MATRIX:ty) => { + impl MatrixMarketExport for $T_MATRIX {} + + impl internal::SupportedMatrixMarketExport + for $T_MATRIX + { + #[inline] + fn triplet_iter(&self) -> Box + '_> { + Box::new(self.triplet_iter()) + } + #[inline] + fn nrows(&self) -> usize { + self.nrows() + } + #[inline] + fn ncols(&self) -> usize { + self.ncols() + } + #[inline] + fn nnz(&self) -> usize { + self.nnz() + } + } + }; +} + +mm_matrix_impl!(CooMatrix); +mm_matrix_impl!(CsrMatrix); +mm_matrix_impl!(CscMatrix); + #[derive(Parser)] #[grammar = "io/matrix_market.pest"] struct MatrixMarketParser; @@ -1391,23 +1441,29 @@ fn next_dense_coordinate( /// let generated_matrixmarket = load_coo_from_matrix_market_str::(&generated_matrixmarket_string).unwrap(); /// assert_matrix_eq!(matrix,generated_matrixmarket); /// ``` -pub fn write_to_matrix_market_str>( +pub fn write_to_matrix_market_str>( sparse_matrix: &S, ) -> String { let mut matrixmarket_string = String::new(); + // write header matrixmarket_string.push_str("%%matrixmarket matrix coordinate "); matrixmarket_string.push_str(T::typename()); - matrixmarket_string.push_str(" general\n% matrixmarket file generated by nalgebra-sparse.\n"); + matrixmarket_string.push_str(" general\n"); + + //write comment + matrixmarket_string.push_str("% matrixmarket file generated by nalgebra-sparse.\n"); + // write shape information - matrixmarket_string.push_str(&sparse_matrix.rows().to_string()); + matrixmarket_string.push_str(&sparse_matrix.nrows().to_string()); matrixmarket_string.push(' '); - matrixmarket_string.push_str(&sparse_matrix.cols().to_string()); + matrixmarket_string.push_str(&sparse_matrix.ncols().to_string()); matrixmarket_string.push(' '); matrixmarket_string.push_str(&sparse_matrix.nnz().to_string()); matrixmarket_string.push('\n'); - for (r, c, d) in sparse_matrix.fetch_triplets() { + //write triplets + for (r, c, d) in sparse_matrix.triplet_iter() { matrixmarket_string.push_str(&(r + 1).to_string()); matrixmarket_string.push_str(" "); matrixmarket_string.push_str(&(c + 1).to_string()); @@ -1415,7 +1471,6 @@ pub fn write_to_matrix_market_str>( matrixmarket_string.push_str(&d.to_matrixmarket_string()); matrixmarket_string.push_str("\n"); } - matrixmarket_string } @@ -1442,15 +1497,49 @@ pub fn write_to_matrix_market_str>( /// let matrix = load_coo_from_matrix_market_str::(&str).unwrap(); /// let res = write_to_matrix_market_file(&matrix,"path/to/matrix.mtx"); /// if res.is_err(){ -/// // do something +/// // do something /// } /// ``` -pub fn write_to_matrix_market_file, P: AsRef>( - matrix: &S, +pub fn write_to_matrix_market_file< + T: MatrixMarketScalar, + S: MatrixMarketExport, + P: AsRef, +>( + sparse_matrix: &S, path: P, ) -> Result<(), MatrixMarketError> { - let matrixmarket_string = write_to_matrix_market_str(matrix); + // The code is basically the same as write_to_matrix_market_str, but write the matrix into file instead. let mut file = File::create(path)?; - write!(file, "{}", matrixmarket_string)?; + + // write header + write!( + file, + "%%matrixmarket matrix coordinate {} general\n", + T::typename() + )?; + + // write comments + write!(file, "% matrixmarket file generated by nalgebra-sparse.\n",)?; + + // write shape information + write!( + file, + "{} {} {}\n", + sparse_matrix.nrows(), + sparse_matrix.ncols(), + sparse_matrix.nnz() + )?; + + // write triplets + for (r, c, d) in sparse_matrix.triplet_iter() { + write!( + file, + "{} {} {}\n", + r + 1, + c + 1, + d.to_matrixmarket_string() + )?; + } + Ok(()) } diff --git a/nalgebra-sparse/src/io/mod.rs b/nalgebra-sparse/src/io/mod.rs index ff61fb6c..52fe4446 100644 --- a/nalgebra-sparse/src/io/mod.rs +++ b/nalgebra-sparse/src/io/mod.rs @@ -33,6 +33,7 @@ pub use self::matrix_market::{ load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market_file, - write_to_matrix_market_str, MatrixMarketError, MatrixMarketErrorKind, MatrixMarketScalar, + write_to_matrix_market_str, MatrixMarketError, MatrixMarketErrorKind, MatrixMarketExport, + MatrixMarketScalar, }; mod matrix_market; From 9e0dfd14de228241aea6633f3670d552c056c617 Mon Sep 17 00:00:00 2001 From: Hantao Hui Date: Sun, 13 Feb 2022 21:16:16 +0100 Subject: [PATCH 03/11] use std::io::Write trait when export to matrix market --- nalgebra-sparse/src/io/matrix_market.rs | 141 ++++++++++-------------- 1 file changed, 61 insertions(+), 80 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index d00a873d..8acedd77 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -508,9 +508,9 @@ mod internal { /// When matrix is a Hermitian matrix, it will convert itself to its conjugate. fn conjugate(self) -> Result; /// Returns the name of SupportedMatrixMarketScalar, used when write the matrix - fn typename() -> &'static str; - /// Convert the data to string - fn to_matrixmarket_string(&self) -> String; + fn typename() -> &'static [u8]; + /// Convert the data to bytes + fn to_matrixmarket_bytes(&self) -> Vec; } pub trait SupportedMatrixMarketExport { @@ -574,12 +574,12 @@ macro_rules! mm_int_impl { Ok(-self) } #[inline] - fn typename() -> &'static str { - "integer" + fn typename() -> &'static [u8] { + b"integer" } #[inline] - fn to_matrixmarket_string(&self) -> String { - self.to_string() + fn to_matrixmarket_bytes(&self) -> Vec { + self.to_string().into_bytes() } } }; @@ -627,12 +627,12 @@ macro_rules! mm_real_impl { Ok(-self) } #[inline] - fn typename() -> &'static str { - "real" + fn typename() -> &'static [u8] { + b"real" } #[inline] - fn to_matrixmarket_string(&self) -> String { - self.to_string() + fn to_matrixmarket_bytes(&self) -> Vec { + self.to_string().into_bytes() } } }; @@ -681,12 +681,12 @@ macro_rules! mm_complex_impl { Ok(-self) } #[inline] - fn typename() -> &'static str { - "complex" + fn typename() -> &'static [u8] { + b"complex" } #[inline] - fn to_matrixmarket_string(&self) -> String { - self.re.to_string() + " " + &self.im.to_string() + fn to_matrixmarket_bytes(&self) -> Vec { + (self.re.to_string() + " " + &self.im.to_string()).into_bytes() } } }; @@ -738,13 +738,12 @@ macro_rules! mm_pattern_impl { )) } #[inline] - fn typename() -> &'static str { - "pattern" + fn typename() -> &'static [u8] { + b"pattern" } #[inline] - fn to_matrixmarket_string(&self) -> String { - // pattern type will return an empty string - String::new() + fn to_matrixmarket_bytes(&self) -> Vec { + Vec::::new() } } }; @@ -1444,34 +1443,14 @@ fn next_dense_coordinate( pub fn write_to_matrix_market_str>( sparse_matrix: &S, ) -> String { - let mut matrixmarket_string = String::new(); - - // write header - matrixmarket_string.push_str("%%matrixmarket matrix coordinate "); - matrixmarket_string.push_str(T::typename()); - matrixmarket_string.push_str(" general\n"); - - //write comment - matrixmarket_string.push_str("% matrixmarket file generated by nalgebra-sparse.\n"); - - // write shape information - matrixmarket_string.push_str(&sparse_matrix.nrows().to_string()); - matrixmarket_string.push(' '); - matrixmarket_string.push_str(&sparse_matrix.ncols().to_string()); - matrixmarket_string.push(' '); - matrixmarket_string.push_str(&sparse_matrix.nnz().to_string()); - matrixmarket_string.push('\n'); - - //write triplets - for (r, c, d) in sparse_matrix.triplet_iter() { - matrixmarket_string.push_str(&(r + 1).to_string()); - matrixmarket_string.push_str(" "); - matrixmarket_string.push_str(&(c + 1).to_string()); - matrixmarket_string.push_str(" "); - matrixmarket_string.push_str(&d.to_matrixmarket_string()); - matrixmarket_string.push_str("\n"); - } - matrixmarket_string + let mut bytes = Vec::::new(); + // This will call impl Write for Vec + // The vector will grow as needed. + // So, unwrap here won't cause any issue. + write_to_matrix_market(&mut bytes, sparse_matrix).unwrap(); + // safety issue is because 'from_utf8_unchecked' does not check that the bytes passed to it are valid UTF-8. + // Since 'bytes' created here is valid UTF-8 data, so it will not cause any problem. + unsafe { String::from_utf8_unchecked(bytes) } } /// Write a sparse matrix into Matrix Market format file. @@ -1508,38 +1487,40 @@ pub fn write_to_matrix_market_file< sparse_matrix: &S, path: P, ) -> Result<(), MatrixMarketError> { - // The code is basically the same as write_to_matrix_market_str, but write the matrix into file instead. let mut file = File::create(path)?; - - // write header - write!( - file, - "%%matrixmarket matrix coordinate {} general\n", - T::typename() - )?; - - // write comments - write!(file, "% matrixmarket file generated by nalgebra-sparse.\n",)?; - - // write shape information - write!( - file, - "{} {} {}\n", - sparse_matrix.nrows(), - sparse_matrix.ncols(), - sparse_matrix.nnz() - )?; - - // write triplets - for (r, c, d) in sparse_matrix.triplet_iter() { - write!( - file, - "{} {} {}\n", - r + 1, - c + 1, - d.to_matrixmarket_string() - )?; - } - + write_to_matrix_market(&mut file, sparse_matrix)?; + Ok(()) +} + +/// low level implementation of writing sparse matrix into any [std::io::Write] object +fn write_to_matrix_market, W: Write>( + w: &mut W, + sparse_matrix: &S, +) -> Result<(), MatrixMarketError> { + // write header + w.write_all(b"%%matrixmarket matrix coordinate ")?; + w.write_all(T::typename())?; + w.write_all(b" general\n")?; + + //write comment + w.write_all(b"% matrixmarket file generated by nalgebra-sparse.\n")?; + + // write shape information + w.write_all(sparse_matrix.nrows().to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all(sparse_matrix.ncols().to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all(sparse_matrix.nnz().to_string().as_bytes())?; + w.write_all(b"\n")?; + + //write triplets + for (r, c, d) in sparse_matrix.triplet_iter() { + w.write_all((r + 1).to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all((c + 1).to_string().as_bytes())?; + w.write_all(b" ")?; + w.write_all(&d.to_matrixmarket_bytes())?; + w.write_all(b"\n")?; + } Ok(()) } From 0cae5842620052f72efb60d179629f3759f20411 Mon Sep 17 00:00:00 2001 From: Hantao Hui Date: Fri, 25 Feb 2022 17:59:50 +0100 Subject: [PATCH 04/11] use writeln! macro; replace unsafe with expect --- nalgebra-sparse/src/io/matrix_market.rs | 96 ++++++++++++++----------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index 8acedd77..c644c34f 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -508,9 +508,9 @@ mod internal { /// When matrix is a Hermitian matrix, it will convert itself to its conjugate. fn conjugate(self) -> Result; /// Returns the name of SupportedMatrixMarketScalar, used when write the matrix - fn typename() -> &'static [u8]; - /// Convert the data to bytes - fn to_matrixmarket_bytes(&self) -> Vec; + fn typename() -> &'static str; + /// Write the data self to w + fn write_matrix_market(&self, w: W) -> Result<(), std::fmt::Error>; } pub trait SupportedMatrixMarketExport { @@ -574,12 +574,15 @@ macro_rules! mm_int_impl { Ok(-self) } #[inline] - fn typename() -> &'static [u8] { - b"integer" + fn typename() -> &'static str { + "integer" } #[inline] - fn to_matrixmarket_bytes(&self) -> Vec { - self.to_string().into_bytes() + fn write_matrix_market( + &self, + mut w: W, + ) -> Result<(), std::fmt::Error> { + write!(w, "{}", self) } } }; @@ -627,12 +630,15 @@ macro_rules! mm_real_impl { Ok(-self) } #[inline] - fn typename() -> &'static [u8] { - b"real" + fn typename() -> &'static str { + "real" } #[inline] - fn to_matrixmarket_bytes(&self) -> Vec { - self.to_string().into_bytes() + fn write_matrix_market( + &self, + mut w: W, + ) -> Result<(), std::fmt::Error> { + write!(w, "{}", self) } } }; @@ -681,12 +687,15 @@ macro_rules! mm_complex_impl { Ok(-self) } #[inline] - fn typename() -> &'static [u8] { - b"complex" + fn typename() -> &'static str { + "complex" } #[inline] - fn to_matrixmarket_bytes(&self) -> Vec { - (self.re.to_string() + " " + &self.im.to_string()).into_bytes() + fn write_matrix_market( + &self, + mut w: W, + ) -> Result<(), std::fmt::Error> { + write!(w, "{} {}", self.re, self.im) } } }; @@ -738,12 +747,15 @@ macro_rules! mm_pattern_impl { )) } #[inline] - fn typename() -> &'static [u8] { - b"pattern" + fn typename() -> &'static str { + "pattern" } #[inline] - fn to_matrixmarket_bytes(&self) -> Vec { - Vec::::new() + fn write_matrix_market( + &self, + mut _w: W, + ) -> Result<(), std::fmt::Error> { + Ok(()) } } }; @@ -1448,9 +1460,9 @@ pub fn write_to_matrix_market_str( sparse_matrix: &S, path: P, -) -> Result<(), MatrixMarketError> { +) -> Result<(), std::io::Error> { let mut file = File::create(path)?; write_to_matrix_market(&mut file, sparse_matrix)?; Ok(()) @@ -1494,33 +1506,35 @@ pub fn write_to_matrix_market_file< /// low level implementation of writing sparse matrix into any [std::io::Write] object fn write_to_matrix_market, W: Write>( - w: &mut W, + mut w: W, sparse_matrix: &S, -) -> Result<(), MatrixMarketError> { +) -> Result<(), std::io::Error> { // write header - w.write_all(b"%%matrixmarket matrix coordinate ")?; - w.write_all(T::typename())?; - w.write_all(b" general\n")?; + writeln!( + w, + "%%matrixmarket matrix coordinate {} general", + T::typename() + )?; //write comment - w.write_all(b"% matrixmarket file generated by nalgebra-sparse.\n")?; + writeln!(w, "% matrixmarket file generated by nalgebra-sparse.")?; // write shape information - w.write_all(sparse_matrix.nrows().to_string().as_bytes())?; - w.write_all(b" ")?; - w.write_all(sparse_matrix.ncols().to_string().as_bytes())?; - w.write_all(b" ")?; - w.write_all(sparse_matrix.nnz().to_string().as_bytes())?; - w.write_all(b"\n")?; + writeln!( + w, + "{} {} {}", + sparse_matrix.nrows(), + sparse_matrix.ncols(), + sparse_matrix.nnz() + )?; //write triplets + let mut buffer = String::new(); for (r, c, d) in sparse_matrix.triplet_iter() { - w.write_all((r + 1).to_string().as_bytes())?; - w.write_all(b" ")?; - w.write_all((c + 1).to_string().as_bytes())?; - w.write_all(b" ")?; - w.write_all(&d.to_matrixmarket_bytes())?; - w.write_all(b"\n")?; + buffer.clear(); + d.write_matrix_market(&mut buffer) + .expect("Unexpected format error was generated when write to String"); + writeln!(w, "{} {} {} ", r + 1, c + 1, buffer)?; } Ok(()) } From 8e48d26767f86c745f06a27f4d955108a5d2d5f5 Mon Sep 17 00:00:00 2001 From: Hantao Hui Date: Mon, 21 Mar 2022 12:11:49 +0100 Subject: [PATCH 05/11] add more tests; use bufwritter; fix typo; use temp_dir to test with files --- nalgebra-sparse/src/io/matrix_market.rs | 46 ++-- nalgebra-sparse/src/io/mod.rs | 6 +- .../tests/unit_tests/matrix_market.rs | 250 +++++++++++------- 3 files changed, 187 insertions(+), 115 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index c644c34f..5143447c 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -13,7 +13,7 @@ use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; use std::fs::{self, File}; -use std::io::Write; +use std::io::{BufWriter, Write}; use std::num::ParseIntError; use std::num::TryFromIntError; use std::path::Path; @@ -1432,25 +1432,26 @@ fn next_dense_coordinate( /// Write a sparse matrix into Matrix Market format string. /// -/// Our exporter only writes matrix into `coordiante` and `general` format. +/// The exporter only writes matrix into `coordinate` and `general` format. /// /// /// Examples /// -------- /// ``` -/// # use matrixcompare::assert_matrix_eq; -/// use nalgebra_sparse::io::{write_to_matrix_market_str,load_coo_from_matrix_market_str}; -/// let str = r#" -/// %%matrixmarket matrix coordinate integer general +/// # use nalgebra_sparse::CooMatrix; +/// use nalgebra_sparse::io::{write_to_matrix_market_str}; +/// let expected_str = r#"%%matrixmarket matrix coordinate integer general +/// % matrixmarket file generated by nalgebra-sparse. /// 5 4 2 /// 1 1 10 /// 2 3 5 /// "#; -/// let matrix = load_coo_from_matrix_market_str::(&str).unwrap(); -/// let generated_matrixmarket_string = write_to_matrix_market_str(&matrix); -/// // 'generated_matrixmarket' should equal to the 'matrix' -/// let generated_matrixmarket = load_coo_from_matrix_market_str::(&generated_matrixmarket_string).unwrap(); -/// assert_matrix_eq!(matrix,generated_matrixmarket); +/// let row_indices = vec![0,1]; +/// let col_indices = vec![0,2]; +/// let values = vec![10,5]; +/// let matrix = CooMatrix::try_from_triplets(5,4,row_indices,col_indices,values).unwrap(); +/// let generated_matrixmarket_str = write_to_matrix_market_str(&matrix); +/// assert_eq!(expected_str,generated_matrixmarket_str); /// ``` pub fn write_to_matrix_market_str>( sparse_matrix: &S, @@ -1467,7 +1468,7 @@ pub fn write_to_matrix_market_str(&str).unwrap(); -/// let res = write_to_matrix_market_file(&matrix,"path/to/matrix.mtx"); -/// if res.is_err(){ -/// // do something -/// } +/// // create a temporary file 'temp.mtx' +/// let mut tempdir = std::env::temp_dir(); +/// tempdir.push("temp.mtx"); +/// write_to_matrix_market_file(&matrix,tempdir).unwrap(); /// ``` pub fn write_to_matrix_market_file< T: MatrixMarketScalar, @@ -1499,13 +1500,18 @@ pub fn write_to_matrix_market_file< sparse_matrix: &S, path: P, ) -> Result<(), std::io::Error> { - let mut file = File::create(path)?; + let file = File::create(path)?; + let mut file = BufWriter::new(file); write_to_matrix_market(&mut file, sparse_matrix)?; + // Quote from BufWriter doc. + // > It is critical to call flush before BufWriter is dropped. Though dropping will attempt to flush the contents of the buffer, any errors that happen in the process of dropping will be ignored. Calling flush ensures that the buffer is empty and thus dropping will not even attempt file operations. + file.flush() + .expect("Unexpected error when flushing the buffer data to File"); Ok(()) } /// low level implementation of writing sparse matrix into any [std::io::Write] object -fn write_to_matrix_market, W: Write>( +pub fn write_to_matrix_market, W: Write>( mut w: W, sparse_matrix: &S, ) -> Result<(), std::io::Error> { @@ -1534,7 +1540,7 @@ fn write_to_matrix_market, W: Wr buffer.clear(); d.write_matrix_market(&mut buffer) .expect("Unexpected format error was generated when write to String"); - writeln!(w, "{} {} {} ", r + 1, c + 1, buffer)?; + writeln!(w, "{} {} {}", r + 1, c + 1, buffer)?; } Ok(()) } diff --git a/nalgebra-sparse/src/io/mod.rs b/nalgebra-sparse/src/io/mod.rs index 52fe4446..f257d7e2 100644 --- a/nalgebra-sparse/src/io/mod.rs +++ b/nalgebra-sparse/src/io/mod.rs @@ -32,8 +32,8 @@ //! > "*The Matrix Market Exchange Formats: Initial Design.*" (1996). pub use self::matrix_market::{ - load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market_file, - write_to_matrix_market_str, MatrixMarketError, MatrixMarketErrorKind, MatrixMarketExport, - MatrixMarketScalar, + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market, + write_to_matrix_market_file, write_to_matrix_market_str, MatrixMarketError, + MatrixMarketErrorKind, MatrixMarketExport, MatrixMarketScalar, }; mod matrix_market; diff --git a/nalgebra-sparse/tests/unit_tests/matrix_market.rs b/nalgebra-sparse/tests/unit_tests/matrix_market.rs index 5d109a9c..7bf6891c 100644 --- a/nalgebra-sparse/tests/unit_tests/matrix_market.rs +++ b/nalgebra-sparse/tests/unit_tests/matrix_market.rs @@ -1,12 +1,20 @@ use matrixcompare::assert_matrix_eq; -use nalgebra::dmatrix; +use nalgebra::matrix; use nalgebra::Complex; -use nalgebra_sparse::io::{load_coo_from_matrix_market_str, write_to_matrix_market_str}; +use nalgebra_sparse::io::{ + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market_file, + write_to_matrix_market_str, +}; +use nalgebra_sparse::proptest::coo_no_duplicates; use nalgebra_sparse::CooMatrix; +use proptest::prelude::*; + +type C64 = Complex; +type C32 = Complex; #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_real_general_empty() { +fn test_matrixmarket_load_sparse_real_general_empty() { // Test several valid zero-shapes of a sparse matrix let shapes = vec![ (0, 0), (1, 0), (0, 1) ]; let strings: Vec = shapes @@ -19,16 +27,12 @@ fn test_matrixmarket_sparse_real_general_empty() { assert_eq!(sparse_mat.nrows(), shape.0); assert_eq!(sparse_mat.ncols(), shape.1); assert_eq!(sparse_mat.nnz(), 0); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(sparse_mat, generated_matrix); } } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_real_general_empty() { +fn test_matrixmarket_load_dense_real_general_empty() { // Test several valid zero-shapes of a dense matrix let shapes = vec![ (0, 0), (1, 0), (0, 1) ]; let strings: Vec = shapes @@ -41,16 +45,12 @@ fn test_matrixmarket_dense_real_general_empty() { assert_eq!(sparse_mat.nrows(), shape.0); assert_eq!(sparse_mat.ncols(), shape.1); assert_eq!(sparse_mat.nnz(), 0); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(sparse_mat, generated_matrix); } } #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_real_general() { +fn test_matrixmarket_load_sparse_real_general() { let file_str = r#" %%MatrixMarket matrix CoOrdinate real general % This is also an example of free-format features. @@ -97,7 +97,7 @@ fn test_matrixmarket_sparse_real_general() { 5 5 1.200e+01 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1.0, 0.0, 0.0, 6.0, 0.0; 0.0, 10.5, 0.0, 0.0, 0.0; 0.0, 0.0, 0.015, 0.0, 0.0; @@ -105,15 +105,11 @@ fn test_matrixmarket_sparse_real_general() { 0.0, 0.0, 0.0, 0.0, 12.0; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_int_symmetric() { +fn test_matrixmarket_load_sparse_int_symmetric() { let file_str = r#" %%MatrixMarket matrix coordinate integer symmetric % @@ -129,7 +125,7 @@ fn test_matrixmarket_sparse_int_symmetric() { 5 5 55 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 11, 0, 0, 0, -15; 0, 22, 23, 24, 0; 0, 23, 33, 0, 35; @@ -137,15 +133,11 @@ fn test_matrixmarket_sparse_int_symmetric() { -15, 0, 35, 0, 55; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_complex_hermitian() { +fn test_matrixmarket_load_sparse_complex_hermitian() { let file_str = r#" %%MatrixMarket matrix coordinate complex hermitian % @@ -160,23 +152,19 @@ fn test_matrixmarket_sparse_complex_hermitian() { "#; let sparse_mat = load_coo_from_matrix_market_str::>(file_str).unwrap(); - let expected = dmatrix![ - Complex::{re:1.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0},Complex::{re:0.0,im:0.0}; - Complex::{re:0.0,im:0.0}, Complex::{re:10.5,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:250.5,im:-22.22},Complex::{re:0.0,im:0.0}; - Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.015,im:0.0}, Complex::{re:0.0,im:0.0},Complex::{re:0.0,im:0.0}; - Complex::{re:0.0,im:0.0}, Complex::{re:250.5,im:22.22}, Complex::{re:0.0,im:0.0}, Complex::{re:-280.0,im:0.0},Complex::{re:0.0,im:-33.32}; - Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:33.32},Complex::{re:12.0,im:0.0}; + let expected = matrix![ + C64{re:1.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0},C64{re:0.0,im:0.0}; + C64{re:0.0,im:0.0}, C64{re:10.5,im:0.0}, C64{re:0.0,im:0.0}, C64{re:250.5,im:-22.22},C64{re:0.0,im:0.0}; + C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.015,im:0.0}, C64{re:0.0,im:0.0},C64{re:0.0,im:0.0}; + C64{re:0.0,im:0.0}, C64{re:250.5,im:22.22}, C64{re:0.0,im:0.0}, C64{re:-280.0,im:0.0},C64{re:0.0,im:-33.32}; + C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:33.32},C64{re:12.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::>(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_real_skew() { +fn test_matrixmarket_load_sparse_real_skew() { let file_str = r#" %%MatrixMarket matrix coordinate real skew-symmetric % @@ -187,7 +175,7 @@ fn test_matrixmarket_sparse_real_skew() { 5 3 -35.0 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 0.0, 0.0, 0.0, 0.0, 15.0; 0.0, 0.0, 23.0, 24.0, 0.0; 0.0, -23.0, 0.0, 0.0, 35.0; @@ -195,15 +183,11 @@ fn test_matrixmarket_sparse_real_skew() { -15.0, 0.0, -35.0, 0.0, 0.0; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_pattern_general() { +fn test_matrixmarket_load_sparse_pattern_general() { let file_str = r#" %%MatrixMarket matrix coordinate pattern general % @@ -225,7 +209,7 @@ fn test_matrixmarket_sparse_pattern_general() { let (row_idx, col_idx, val) = pattern_matrix.clone().disassemble(); let values = vec![1; val.len()]; let sparse_mat = CooMatrix::try_from_triplets(nrows, ncols, row_idx, col_idx, values).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1, 0, 0, 0, 1; 0, 0, 1, 1, 0; 0, 1, 0, 0, 1; @@ -233,22 +217,11 @@ fn test_matrixmarket_sparse_pattern_general() { 0, 1, 0, 1, 1; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&pattern_matrix); - let generated_matrix = load_coo_from_matrix_market_str::<()>(&generated_matrixmarket_str).unwrap(); - - let nrows = generated_matrix.nrows(); - let ncols = generated_matrix.ncols(); - let (row_idx, col_idx, val) = generated_matrix.clone().disassemble(); - let values = vec![1; val.len()]; - let generated_sparse_mat = CooMatrix::try_from_triplets(nrows, ncols, row_idx, col_idx, values).unwrap(); - - assert_matrix_eq!(expected, generated_sparse_mat); } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_real_general() { +fn test_matrixmarket_load_dense_real_general() { let file_str = r#" %%MatrixMarket matrix array real general % @@ -268,22 +241,18 @@ fn test_matrixmarket_dense_real_general() { "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1.0, 5.0, 9.0; 2.0, 6.0, 10.0; 3.0, 7.0, 11.0; 4.0, 8.0, 12.0; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_real_symmetric() { +fn test_matrixmarket_load_dense_real_symmetric() { let file_str = r#" %%MatrixMarket matrix array real symmetric % @@ -301,22 +270,18 @@ fn test_matrixmarket_dense_real_symmetric() { "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1.0, 2.0, 3.0, 4.0; 2.0, 5.0, 6.0, 7.0; 3.0, 6.0, 8.0, 9.0; 4.0, 7.0, 9.0, 10.0; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_complex_hermitian() { +fn test_matrixmarket_load_dense_complex_hermitian() { let file_str = r#" %%MatrixMarket matrix array complex hermitian % @@ -333,23 +298,19 @@ fn test_matrixmarket_dense_complex_hermitian() { 10.0 0.0 "#; - let sparse_mat = load_coo_from_matrix_market_str::>(file_str).unwrap(); - let expected = dmatrix![ - Complex::{re:1.0,im:0.0}, Complex::{re:2.0,im:-2.0} ,Complex::{re:3.0,im:-3.0} ,Complex::{re:4.0,im:-4.0}; - Complex::{re:2.0,im:2.0}, Complex::{re:5.0,im:0.0} ,Complex::{re:6.0,im:-6.0} ,Complex::{re:7.0,im:-7.0}; - Complex::{re:3.0,im:3.0}, Complex::{re:6.0,im:6.0} ,Complex::{re:8.0,im:0.0} ,Complex::{re:9.0,im:-9.0}; - Complex::{re:4.0,im:4.0}, Complex::{re:7.0,im:7.0} ,Complex::{re:9.0,im:9.0} ,Complex::{re:10.0,im:0.0}; + let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); + let expected = matrix![ + C64{re:1.0,im:0.0}, C64{re:2.0,im:-2.0} ,C64{re:3.0,im:-3.0} ,C64{re:4.0,im:-4.0}; + C64{re:2.0,im:2.0}, C64{re:5.0,im:0.0} ,C64{re:6.0,im:-6.0} ,C64{re:7.0,im:-7.0}; + C64{re:3.0,im:3.0}, C64{re:6.0,im:6.0} ,C64{re:8.0,im:0.0} ,C64{re:9.0,im:-9.0}; + C64{re:4.0,im:4.0}, C64{re:7.0,im:7.0} ,C64{re:9.0,im:9.0} ,C64{re:10.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::>(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_int_skew() { +fn test_matrixmarket_load_dense_int_skew() { let file_str = r#" %%MatrixMarket matrix array integer skew-symmetric % @@ -362,22 +323,18 @@ fn test_matrixmarket_dense_int_skew() { 6 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 0,-1,-2,-3; 1, 0,-4,-5; 2, 4, 0,-6; 3, 5, 6, 0; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_complex_general() { +fn test_matrixmarket_load_dense_complex_general() { let file_str = r#" %%MatrixMarket matrix array complex general % @@ -387,14 +344,123 @@ fn test_matrixmarket_dense_complex_general() { 1 0 1 0 "#; - let sparse_mat = load_coo_from_matrix_market_str::>(file_str).unwrap(); - let expected = dmatrix![ - Complex::{re:1.0,im:0.0},Complex::{re:1.0,im:0.0}; - Complex::{re:1.0,im:0.0},Complex::{re:1.0,im:0.0}; + let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); + let expected = matrix![ + C32{re:1.0,im:0.0},C32{re:1.0,im:0.0}; + C32{re:1.0,im:0.0},C32{re:1.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); - - let generated_matrixmarket_str = write_to_matrix_market_str(&sparse_mat); - let generated_matrix = load_coo_from_matrix_market_str::>(&generated_matrixmarket_str).unwrap(); - assert_matrix_eq!(expected, generated_matrix); +} + +#[test] +#[rustfmt::skip] +fn test_matrixmarket_write_real(){ + let dense_matrix = matrix![ + 1.0, 2.0, 3.0; + 2.0, 0.0, 3.0; + ]; + let row_indices = vec![0,1,0,0,1]; + let col_indices = vec![0,0,1,2,2]; + let values = vec![1.0,2.0,2.0,3.0,3.0]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + assert_matrix_eq!(dense_matrix,coo_matrix); + let expected = r#"%%matrixmarket matrix coordinate real general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 1 +2 1 2 +1 2 2 +1 3 3 +2 3 3 +"#; + let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str,expected); +} + +#[test] +fn test_matrixmarket_write_int() { + let dense_matrix = matrix![ + 1,2,3; + 2,0,3; + ]; + let row_indices = vec![0, 1, 0, 0, 1]; + let col_indices = vec![0, 0, 1, 2, 2]; + let values = vec![1, 2, 2, 3, 3]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + assert_matrix_eq!(dense_matrix, coo_matrix); + let expected = r#"%%matrixmarket matrix coordinate integer general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 1 +2 1 2 +1 2 2 +1 3 3 +2 3 3 +"#; + let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str, expected); +} + +#[test] +fn test_matrixmarket_write_pattern() { + let row_indices = vec![0, 1, 0, 0, 1]; + let col_indices = vec![0, 0, 1, 2, 2]; + let values = vec![(), (), (), (), ()]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + let expected = r#"%%matrixmarket matrix coordinate pattern general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 +2 1 +1 2 +1 3 +2 3 +"#; + let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str, expected); +} + +#[test] +fn test_matrixmarket_write_complex() { + let row_indices = vec![0, 1, 0, 0, 1]; + let col_indices = vec![0, 0, 1, 2, 2]; + let values = vec![ + C64 { re: 1.0, im: 2.0 }, + C64 { re: 2.0, im: 3.0 }, + C64 { re: 3.0, im: 4.0 }, + C64 { re: 4.0, im: 5.0 }, + C64 { re: 5.0, im: 6.0 }, + ]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + let expected = r#"%%matrixmarket matrix coordinate complex general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 1 2 +2 1 2 3 +1 2 3 4 +1 3 4 5 +2 3 5 6 +"#; + let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str, expected); +} + +proptest! { + #[test] + fn coo_matrix_market_roundtrip_str(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { + let generated_matrixmarket_string = write_to_matrix_market_str(&coo); + let generated_matrix = load_coo_from_matrix_market_str(&generated_matrixmarket_string).unwrap(); + assert_matrix_eq!(generated_matrix, coo); + } +} + +proptest! { + #[test] + fn coo_matrix_market_roundtrip_file(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { + let mut tempdir = std::env::temp_dir(); + tempdir.push("temp.mtx"); + write_to_matrix_market_file(&coo,&tempdir).unwrap(); + let generated_matrix = load_coo_from_matrix_market_file(tempdir).unwrap(); + assert_matrix_eq!(generated_matrix, coo); + } } From 31fc49818228976e49fb471a4c5896db938fa6e2 Mon Sep 17 00:00:00 2001 From: Hantao Hui Date: Sat, 7 May 2022 13:40:25 +0200 Subject: [PATCH 06/11] use tempdir to write matrix when running test --- nalgebra-sparse/Cargo.toml | 1 + nalgebra-sparse/src/io/matrix_market.rs | 5 +---- nalgebra-sparse/tests/unit_tests/matrix_market.rs | 10 ++++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nalgebra-sparse/Cargo.toml b/nalgebra-sparse/Cargo.toml index 0dfe743f..4e414322 100644 --- a/nalgebra-sparse/Cargo.toml +++ b/nalgebra-sparse/Cargo.toml @@ -34,6 +34,7 @@ pest_derive = { version = "2", optional = true } itertools = "0.10" matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] } nalgebra = { version="0.30", path = "../", features = ["compare"] } +tempfile = "3" [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index 5143447c..200aeff2 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1487,10 +1487,7 @@ pub fn write_to_matrix_market_str(&str).unwrap(); -/// // create a temporary file 'temp.mtx' -/// let mut tempdir = std::env::temp_dir(); -/// tempdir.push("temp.mtx"); -/// write_to_matrix_market_file(&matrix,tempdir).unwrap(); +/// write_to_matrix_market_file(&matrix,"path/to/matrix.mtx").unwrap(); /// ``` pub fn write_to_matrix_market_file< T: MatrixMarketScalar, diff --git a/nalgebra-sparse/tests/unit_tests/matrix_market.rs b/nalgebra-sparse/tests/unit_tests/matrix_market.rs index 7bf6891c..245fa3f5 100644 --- a/nalgebra-sparse/tests/unit_tests/matrix_market.rs +++ b/nalgebra-sparse/tests/unit_tests/matrix_market.rs @@ -8,6 +8,7 @@ use nalgebra_sparse::io::{ use nalgebra_sparse::proptest::coo_no_duplicates; use nalgebra_sparse::CooMatrix; use proptest::prelude::*; +use tempfile::tempdir; type C64 = Complex; type C32 = Complex; @@ -457,10 +458,11 @@ proptest! { proptest! { #[test] fn coo_matrix_market_roundtrip_file(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { - let mut tempdir = std::env::temp_dir(); - tempdir.push("temp.mtx"); - write_to_matrix_market_file(&coo,&tempdir).unwrap(); - let generated_matrix = load_coo_from_matrix_market_file(tempdir).unwrap(); + let temp_dir = tempdir().expect("Unable to create temporary directory"); + let file_path = temp_dir.path().join("temp.mtx"); + write_to_matrix_market_file(&coo,&file_path).unwrap(); + let generated_matrix = load_coo_from_matrix_market_file(file_path).unwrap(); assert_matrix_eq!(generated_matrix, coo); + temp_dir.close().expect("Unable to delete temporary directory"); } } From ef9a3dd7678f79f37db07a93231f781ab6dbb44f Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 9 May 2022 09:23:42 +0200 Subject: [PATCH 07/11] Update module-level docs --- nalgebra-sparse/src/io/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nalgebra-sparse/src/io/mod.rs b/nalgebra-sparse/src/io/mod.rs index f257d7e2..e5412562 100644 --- a/nalgebra-sparse/src/io/mod.rs +++ b/nalgebra-sparse/src/io/mod.rs @@ -19,10 +19,12 @@ //! which also uses the Matrix Market file format. //! //! We currently offer functionality for importing a Matrix market file to an instance of a -//! [CooMatrix](crate::CooMatrix) through the function [load_coo_from_matrix_market_file]. It is also possible to load -//! a matrix stored in the matrix market format with the function [load_coo_from_matrix_market_str]. -//! -//! Export is currently not implemented, but [planned](https://github.com/dimforge/nalgebra/issues/1037). +//! [CooMatrix](crate::CooMatrix) through the function [load_coo_from_matrix_market_file], +//! as well as functionality for writing various sparse matrices to the matrix market format +//! through [write_to_matrix_market_file]. It is also possible to load +//! a matrix stored as a string in the matrix market format with the function +//! [load_coo_from_matrix_market_str], or similarly write to a string with +//! [write_to_matrix_market_str]. //! //! Our implementation is based on the [format description](https://math.nist.gov/MatrixMarket/formats.html) //! on the Matrix Market website and the From 9b321955583108149fa97a56fd73314849c5b08b Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 9 May 2022 09:51:55 +0200 Subject: [PATCH 08/11] Change write -> save in order to be consistent with load terminology --- nalgebra-sparse/src/io/matrix_market.rs | 25 +++++++++---------- nalgebra-sparse/src/io/mod.rs | 8 +++--- .../tests/unit_tests/matrix_market.rs | 16 ++++++------ 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index 200aeff2..fc9b59b2 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -775,7 +775,7 @@ mm_complex_impl!(f64); mm_pattern_impl!(()); -/// A marker trait for supported sparse matrix types. +/// A marker trait for sparse matrix types that can be exported to the matrix market format. /// /// This is a sealed trait; it cannot be implemented by external crates. This is done in order to prevent leaking /// some of the implementation details we currently rely on. We may relax this restriction in the future. @@ -1439,7 +1439,7 @@ fn next_dense_coordinate( /// -------- /// ``` /// # use nalgebra_sparse::CooMatrix; -/// use nalgebra_sparse::io::{write_to_matrix_market_str}; +/// use nalgebra_sparse::io::{save_to_matrix_market_str}; /// let expected_str = r#"%%matrixmarket matrix coordinate integer general /// % matrixmarket file generated by nalgebra-sparse. /// 5 4 2 @@ -1450,26 +1450,25 @@ fn next_dense_coordinate( /// let col_indices = vec![0,2]; /// let values = vec![10,5]; /// let matrix = CooMatrix::try_from_triplets(5,4,row_indices,col_indices,values).unwrap(); -/// let generated_matrixmarket_str = write_to_matrix_market_str(&matrix); +/// let generated_matrixmarket_str = save_to_matrix_market_str(&matrix); /// assert_eq!(expected_str,generated_matrixmarket_str); /// ``` -pub fn write_to_matrix_market_str>( +pub fn save_to_matrix_market_str>( sparse_matrix: &S, ) -> String { let mut bytes = Vec::::new(); // This will call impl Write for Vec // The vector will grow as needed. // So, unwrap here won't cause any issue. - write_to_matrix_market(&mut bytes, sparse_matrix).unwrap(); + save_to_matrix_market(&mut bytes, sparse_matrix).unwrap(); String::from_utf8(bytes) .expect("Unexpected non UTF-8 data was generated when export to matrix market string") } -/// Write a sparse matrix into Matrix Market format file. -/// -/// The exporter only writes matrix into `coordinate` and `general` format. +/// Save a sparse matrix to a Matrix Market format file. /// +/// The exporter only saves the matrix with the `coordinate` and `general` matrix market formats. /// /// Errors /// -------- @@ -1479,7 +1478,7 @@ pub fn write_to_matrix_market_str(&str).unwrap(); -/// write_to_matrix_market_file(&matrix,"path/to/matrix.mtx").unwrap(); +/// save_to_matrix_market_file(&matrix,"path/to/matrix.mtx").unwrap(); /// ``` -pub fn write_to_matrix_market_file< +pub fn save_to_matrix_market_file< T: MatrixMarketScalar, S: MatrixMarketExport, P: AsRef, @@ -1499,7 +1498,7 @@ pub fn write_to_matrix_market_file< ) -> Result<(), std::io::Error> { let file = File::create(path)?; let mut file = BufWriter::new(file); - write_to_matrix_market(&mut file, sparse_matrix)?; + save_to_matrix_market(&mut file, sparse_matrix)?; // Quote from BufWriter doc. // > It is critical to call flush before BufWriter is dropped. Though dropping will attempt to flush the contents of the buffer, any errors that happen in the process of dropping will be ignored. Calling flush ensures that the buffer is empty and thus dropping will not even attempt file operations. file.flush() @@ -1508,7 +1507,7 @@ pub fn write_to_matrix_market_file< } /// low level implementation of writing sparse matrix into any [std::io::Write] object -pub fn write_to_matrix_market, W: Write>( +pub fn save_to_matrix_market, W: Write>( mut w: W, sparse_matrix: &S, ) -> Result<(), std::io::Error> { diff --git a/nalgebra-sparse/src/io/mod.rs b/nalgebra-sparse/src/io/mod.rs index e5412562..1f4cb081 100644 --- a/nalgebra-sparse/src/io/mod.rs +++ b/nalgebra-sparse/src/io/mod.rs @@ -21,10 +21,10 @@ //! We currently offer functionality for importing a Matrix market file to an instance of a //! [CooMatrix](crate::CooMatrix) through the function [load_coo_from_matrix_market_file], //! as well as functionality for writing various sparse matrices to the matrix market format -//! through [write_to_matrix_market_file]. It is also possible to load +//! through [save_to_matrix_market_file]. It is also possible to load //! a matrix stored as a string in the matrix market format with the function //! [load_coo_from_matrix_market_str], or similarly write to a string with -//! [write_to_matrix_market_str]. +//! [save_to_matrix_market_str]. //! //! Our implementation is based on the [format description](https://math.nist.gov/MatrixMarket/formats.html) //! on the Matrix Market website and the @@ -34,8 +34,8 @@ //! > "*The Matrix Market Exchange Formats: Initial Design.*" (1996). pub use self::matrix_market::{ - load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market, - write_to_matrix_market_file, write_to_matrix_market_str, MatrixMarketError, + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, save_to_matrix_market, + save_to_matrix_market_file, save_to_matrix_market_str, MatrixMarketError, MatrixMarketErrorKind, MatrixMarketExport, MatrixMarketScalar, }; mod matrix_market; diff --git a/nalgebra-sparse/tests/unit_tests/matrix_market.rs b/nalgebra-sparse/tests/unit_tests/matrix_market.rs index 245fa3f5..44e27644 100644 --- a/nalgebra-sparse/tests/unit_tests/matrix_market.rs +++ b/nalgebra-sparse/tests/unit_tests/matrix_market.rs @@ -2,8 +2,8 @@ use matrixcompare::assert_matrix_eq; use nalgebra::matrix; use nalgebra::Complex; use nalgebra_sparse::io::{ - load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, write_to_matrix_market_file, - write_to_matrix_market_str, + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, save_to_matrix_market_file, + save_to_matrix_market_str, }; use nalgebra_sparse::proptest::coo_no_duplicates; use nalgebra_sparse::CooMatrix; @@ -374,7 +374,7 @@ fn test_matrixmarket_write_real(){ 1 3 3 2 3 3 "#; - let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); assert_eq!(matrixmarket_str,expected); } @@ -398,7 +398,7 @@ fn test_matrixmarket_write_int() { 1 3 3 2 3 3 "#; - let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); assert_eq!(matrixmarket_str, expected); } @@ -417,7 +417,7 @@ fn test_matrixmarket_write_pattern() { 1 3 2 3 "#; - let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); assert_eq!(matrixmarket_str, expected); } @@ -442,14 +442,14 @@ fn test_matrixmarket_write_complex() { 1 3 4 5 2 3 5 6 "#; - let matrixmarket_str = write_to_matrix_market_str(&coo_matrix); + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); assert_eq!(matrixmarket_str, expected); } proptest! { #[test] fn coo_matrix_market_roundtrip_str(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { - let generated_matrixmarket_string = write_to_matrix_market_str(&coo); + let generated_matrixmarket_string = save_to_matrix_market_str(&coo); let generated_matrix = load_coo_from_matrix_market_str(&generated_matrixmarket_string).unwrap(); assert_matrix_eq!(generated_matrix, coo); } @@ -460,7 +460,7 @@ proptest! { fn coo_matrix_market_roundtrip_file(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { let temp_dir = tempdir().expect("Unable to create temporary directory"); let file_path = temp_dir.path().join("temp.mtx"); - write_to_matrix_market_file(&coo,&file_path).unwrap(); + save_to_matrix_market_file(&coo,&file_path).unwrap(); let generated_matrix = load_coo_from_matrix_market_file(file_path).unwrap(); assert_matrix_eq!(generated_matrix, coo); temp_dir.close().expect("Unable to delete temporary directory"); From 59421896cea745843e743006feee1b61c778932f Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 9 May 2022 09:59:09 +0200 Subject: [PATCH 09/11] Polish docs for save_* matrix market methods --- nalgebra-sparse/src/io/matrix_market.rs | 37 +++++++++++++++++-------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index fc9b59b2..489449a3 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1430,9 +1430,9 @@ fn next_dense_coordinate( } } -/// Write a sparse matrix into Matrix Market format string. +/// Save a sparse matrix as a Matrix Market format string. /// -/// The exporter only writes matrix into `coordinate` and `general` format. +/// The exporter only writes the matrix into `coordinate` and `general` format. /// /// /// Examples @@ -1453,9 +1453,13 @@ fn next_dense_coordinate( /// let generated_matrixmarket_str = save_to_matrix_market_str(&matrix); /// assert_eq!(expected_str,generated_matrixmarket_str); /// ``` -pub fn save_to_matrix_market_str>( +pub fn save_to_matrix_market_str( sparse_matrix: &S, -) -> String { +) -> String +where + T: MatrixMarketScalar, + S: MatrixMarketExport +{ let mut bytes = Vec::::new(); // This will call impl Write for Vec // The vector will grow as needed. @@ -1488,14 +1492,15 @@ pub fn save_to_matrix_market_str /// let matrix = load_coo_from_matrix_market_str::(&str).unwrap(); /// save_to_matrix_market_file(&matrix,"path/to/matrix.mtx").unwrap(); /// ``` -pub fn save_to_matrix_market_file< +pub fn save_to_matrix_market_file( + sparse_matrix: &S, + path: P, +) -> Result<(), std::io::Error> +where T: MatrixMarketScalar, S: MatrixMarketExport, P: AsRef, ->( - sparse_matrix: &S, - path: P, -) -> Result<(), std::io::Error> { +{ let file = File::create(path)?; let mut file = BufWriter::new(file); save_to_matrix_market(&mut file, sparse_matrix)?; @@ -1506,11 +1511,19 @@ pub fn save_to_matrix_market_file< Ok(()) } -/// low level implementation of writing sparse matrix into any [std::io::Write] object -pub fn save_to_matrix_market, W: Write>( +/// Save a sparse matrix to an [std::io::Write] instance. +/// +/// This is the most general save functionality. See [save_to_matrix_market_file] and +/// [save_to_matrix_market_str] for higher-level functionality. +pub fn save_to_matrix_market( mut w: W, sparse_matrix: &S, -) -> Result<(), std::io::Error> { +) -> Result<(), std::io::Error> +where + T: MatrixMarketScalar, + S: MatrixMarketExport, + W: Write +{ // write header writeln!( w, From 037226bb1f1a010d5bc3d1c63073e435e1ee80fe Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 9 May 2022 10:02:26 +0200 Subject: [PATCH 10/11] Use ? instead of unwrap() in examples --- nalgebra-sparse/src/io/matrix_market.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index 489449a3..36ca5ca4 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1439,6 +1439,7 @@ fn next_dense_coordinate( /// -------- /// ``` /// # use nalgebra_sparse::CooMatrix; +/// # fn main() -> Result<(), Box> { /// use nalgebra_sparse::io::{save_to_matrix_market_str}; /// let expected_str = r#"%%matrixmarket matrix coordinate integer general /// % matrixmarket file generated by nalgebra-sparse. @@ -1449,9 +1450,10 @@ fn next_dense_coordinate( /// let row_indices = vec![0,1]; /// let col_indices = vec![0,2]; /// let values = vec![10,5]; -/// let matrix = CooMatrix::try_from_triplets(5,4,row_indices,col_indices,values).unwrap(); +/// let matrix = CooMatrix::try_from_triplets(5,4,row_indices,col_indices,values)?; /// let generated_matrixmarket_str = save_to_matrix_market_str(&matrix); /// assert_eq!(expected_str,generated_matrixmarket_str); +/// # Ok(()) } /// ``` pub fn save_to_matrix_market_str( sparse_matrix: &S, @@ -1482,6 +1484,7 @@ where /// Examples /// -------- /// ```no_run +/// # fn main() -> Result<(), Box> { /// use nalgebra_sparse::io::{save_to_matrix_market_file,load_coo_from_matrix_market_str}; /// let str = r#" /// %%matrixmarket matrix coordinate integer general @@ -1489,8 +1492,9 @@ where /// 1 1 10 /// 2 3 5 /// "#; -/// let matrix = load_coo_from_matrix_market_str::(&str).unwrap(); -/// save_to_matrix_market_file(&matrix,"path/to/matrix.mtx").unwrap(); +/// let matrix = load_coo_from_matrix_market_str::(&str)?; +/// save_to_matrix_market_file(&matrix,"path/to/matrix.mtx")?; +/// # Ok(()) } /// ``` pub fn save_to_matrix_market_file( sparse_matrix: &S, From 80e77d2f9f0ed0e3d787e972ce598779d5fc599c Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 13 Jun 2022 09:55:16 +0200 Subject: [PATCH 11/11] Fix formatting --- nalgebra-sparse/src/io/matrix_market.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index 36ca5ca4..975c586e 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1455,12 +1455,10 @@ fn next_dense_coordinate( /// assert_eq!(expected_str,generated_matrixmarket_str); /// # Ok(()) } /// ``` -pub fn save_to_matrix_market_str( - sparse_matrix: &S, -) -> String +pub fn save_to_matrix_market_str(sparse_matrix: &S) -> String where T: MatrixMarketScalar, - S: MatrixMarketExport + S: MatrixMarketExport, { let mut bytes = Vec::::new(); // This will call impl Write for Vec @@ -1496,10 +1494,7 @@ where /// save_to_matrix_market_file(&matrix,"path/to/matrix.mtx")?; /// # Ok(()) } /// ``` -pub fn save_to_matrix_market_file( - sparse_matrix: &S, - path: P, -) -> Result<(), std::io::Error> +pub fn save_to_matrix_market_file(sparse_matrix: &S, path: P) -> Result<(), std::io::Error> where T: MatrixMarketScalar, S: MatrixMarketExport, @@ -1519,14 +1514,11 @@ where /// /// This is the most general save functionality. See [save_to_matrix_market_file] and /// [save_to_matrix_market_str] for higher-level functionality. -pub fn save_to_matrix_market( - mut w: W, - sparse_matrix: &S, -) -> Result<(), std::io::Error> +pub fn save_to_matrix_market(mut w: W, sparse_matrix: &S) -> Result<(), std::io::Error> where T: MatrixMarketScalar, S: MatrixMarketExport, - W: Write + W: Write, { // write header writeln!(