add support for matrix market export
This commit is contained in:
parent
6cc633474d
commit
d511e372de
|
@ -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" ]
|
||||
features = [ "proptest-support", "compare" , "io"]
|
|
@ -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<Self, MatrixMarketError>;
|
||||
/// When matrix is a Hermitian matrix, it will convert itself to its conjugate.
|
||||
fn conjugate(self) -> Result<Self, MatrixMarketError>;
|
||||
/// 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<Self, MatrixMarketError> {
|
||||
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<Self, MatrixMarketError> {
|
||||
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<Self, MatrixMarketError> {
|
||||
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::<i32>(&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::<i32>(&generated_matrixmarket_string).unwrap();
|
||||
/// assert_matrix_eq!(matrix,generated_matrixmarket);
|
||||
/// ```
|
||||
pub fn write_to_matrix_market_str<T: MatrixMarketScalar, S: SparseAccess<T>>(
|
||||
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::<i32>(&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<T: MatrixMarketScalar, S: SparseAccess<T>, P: AsRef<Path>>(
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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::<f32>(&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::<f32>(&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::<f32>(&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::<i128>(&generated_matrixmarket_str).unwrap();
|
||||
assert_matrix_eq!(expected, generated_matrix);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -152,6 +168,10 @@ fn test_matrixmarket_sparse_complex_hermitian() {
|
|||
Complex::<f64>{re:0.0,im:0.0}, Complex::<f64>{re:0.0,im:0.0}, Complex::<f64>{re:0.0,im:0.0}, Complex::<f64>{re:0.0,im:33.32},Complex::<f64>{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::<Complex<f64>>(&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::<f64>(&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::<f32>(&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::<f32>(&generated_matrixmarket_str).unwrap();
|
||||
assert_matrix_eq!(expected, generated_matrix);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -298,6 +341,10 @@ fn test_matrixmarket_dense_complex_hermitian() {
|
|||
Complex::<f64>{re:4.0,im:4.0}, Complex::<f64>{re:7.0,im:7.0} ,Complex::<f64>{re:9.0,im:9.0} ,Complex::<f64>{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::<Complex<f64>>(&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::<i32>(&generated_matrixmarket_str).unwrap();
|
||||
assert_matrix_eq!(expected, generated_matrix);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -342,4 +393,8 @@ fn test_matrixmarket_dense_complex_general() {
|
|||
Complex::<f32>{re:1.0,im:0.0},Complex::<f32>{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::<Complex<f32>>(&generated_matrixmarket_str).unwrap();
|
||||
assert_matrix_eq!(expected, generated_matrix);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue