-
Notifications
You must be signed in to change notification settings - Fork 224
feat(io): Add support for the matrix market exchange format #1108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9301ba1
e1fbad1
f7b4700
b6ba5cd
34e5a3c
0ea33f7
32b1df1
08f8c6b
912f9ef
6a21d2a
eac6f6b
2fb010f
621de46
44c1a74
7b78c6d
7189b92
694c0f3
3019722
a453ff3
4aa2fad
a8d988a
c0351f3
014b644
90a3ba5
8a9ffb9
0c33205
53d3ac3
a1ba8ac
7cf80fc
2d02766
28db893
be4c498
67a90c2
c736d41
8d505bb
63634be
0bf7170
e8e7387
5abdabd
3113f13
c03119d
91fbede
107ffda
213bc2a
c1a8c65
a4cb00e
4d220cc
4b27f8c
ad02254
749b798
4a65054
64456f5
3183c37
874bad2
e00ee73
476cdf6
13df893
9353e2e
bfd3bcc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -305,3 +305,70 @@ Exceptions trigger an `error stop` unless the optional `err` argument is provide | |
| {!example/io/example_get_file.f90!} | ||
| ``` | ||
|
|
||
| ## Matrix Market Format I/O | ||
|
|
||
| ### Status | ||
|
|
||
| Experimental | ||
|
|
||
| ### Description | ||
|
|
||
| The Matrix Market I/O module provides support for reading and writing matrices in the Matrix Market format, a simple ASCII format for sparse and dense matrices developed at NIST. The format supports real, complex, and integer matrices with various symmetry properties. | ||
|
|
||
| ### `load_mm` - load a matrix from Matrix Market file | ||
|
|
||
| #### Syntax | ||
|
|
||
| `call ` [[stdlib_io_mm(module):load_mm(interface)]] `(filename, matrix [, iostat] [, iomsg])` | ||
|
|
||
| #### Arguments | ||
|
|
||
| `filename`: Shall be a character expression containing the Matrix Market file name to read from. | ||
|
|
||
| `matrix`: Shall be an allocatable rank-2 array of type `real`, `complex`, or `integer` that will contain the loaded matrix. | ||
|
|
||
| `iostat` (optional): Shall be a scalar of type `integer` that receives the error status. Zero indicates success. | ||
|
|
||
| `iomsg` (optional): Shall be an allocatable character string that receives the error message if iostat is non-zero. | ||
|
|
||
| #### Description | ||
|
|
||
| Loads a 2D matrix from a Matrix Market format file. The routine automatically detects the data type, format (coordinate or array), and symmetry properties from the file header. For coordinate format files, symmetric matrices are expanded to full storage. | ||
|
|
||
| ### `save_mm` - save a matrix to Matrix Market file | ||
|
|
||
| #### Syntax | ||
|
|
||
| `call ` [[stdlib_io_mm(module):save_mm(interface)]] `(filename, matrix [, header_info] [, iostat] [, iomsg])` | ||
|
|
||
| #### Arguments | ||
|
|
||
| `filename`: Shall be a character expression containing the Matrix Market file name to write to. | ||
|
|
||
| `matrix`: Shall be a rank-2 array of type `real`, `complex`, or `integer` to save. | ||
|
|
||
| `header_info` (optional): Shall be a character expression containing additional comments for the file header. Can also specify format preference ('coordinate' or 'array'). | ||
|
|
||
| `iostat` (optional): Shall be a scalar of type `integer` that receives the error status. Zero indicates success. | ||
|
|
||
| `iomsg` (optional): Shall be an allocatable character string that receives the error message if iostat is non-zero. | ||
|
|
||
| #### Description | ||
|
|
||
| Saves a 2D matrix to Matrix Market format file. The routine automatically chooses coordinate format for sparse matrices (< 50% non-zero) and array format for dense matrices, unless overridden in `header_info`. | ||
|
Comment on lines
+342
to
+358
|
||
|
|
||
| ### Matrix Market Format Details | ||
|
|
||
| The Matrix Market format supports: | ||
|
|
||
| - **Object types**: Currently only `matrix` is supported | ||
| - **Formats**: `coordinate` (sparse) and `array` (dense) | ||
| - **Data types**: `real`, `complex`, `integer` (pattern not yet supported) | ||
| - **Symmetry**: `general`, `symmetric`, `skew-symmetric`, `hermitian` | ||
|
|
||
| ### Example | ||
|
|
||
| ```fortran | ||
| {!example/io/example_matrix_market.f90!} | ||
| ``` | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| program example_matrix_market | ||
| use stdlib_io_mm, only : load_mm, save_mm | ||
| use stdlib_kinds, only : dp | ||
| implicit none | ||
|
|
||
| real(dp), allocatable :: matrix(:,:), matrix2(:,:) | ||
| integer, allocatable :: index(:,:) | ||
| real(dp), allocatable :: data(:) | ||
| character(len=*), parameter :: dense_filename = "test_dense.mtx" | ||
| character(len=*), parameter :: sparse_filename = "test_sparse.mtx" | ||
| integer :: iostat, i | ||
| character(len=:), allocatable :: iomsg | ||
|
|
||
| iostat = 0 | ||
| iomsg = '' | ||
| ! Create a test dense matrix | ||
| allocate(matrix(3,3)) | ||
| matrix = reshape([1.0_dp, 2.0_dp, 3.0_dp, & | ||
| 4.0_dp, 5.0_dp, 6.0_dp, & | ||
| 7.0_dp, 8.0_dp, 9.0_dp], [3,3]) | ||
|
|
||
| print *, "=== Dense Matrix Example ===" | ||
| print *, "Original dense matrix:" | ||
| call print_matrix(matrix) | ||
|
|
||
| ! Save dense matrix to Matrix Market file | ||
| call save_mm(dense_filename, matrix, iostat=iostat, iomsg=iomsg) | ||
| if (iostat /= 0) then | ||
| print *, "Error saving dense matrix: ", iomsg | ||
| stop 1 | ||
| end if | ||
|
|
||
| print *, "Dense matrix saved to ", dense_filename | ||
|
|
||
| ! Load dense matrix from Matrix Market file | ||
| call load_mm(dense_filename, matrix2, iostat=iostat, iomsg=iomsg) | ||
| if (iostat /= 0) then | ||
| print *, "Error loading dense matrix: ", iomsg | ||
| stop 1 | ||
| end if | ||
|
|
||
| print *, "Loaded dense matrix:" | ||
| call print_matrix(matrix2) | ||
|
|
||
| ! Create a sparse test file manually for demonstration | ||
| call create_sparse_test_file(sparse_filename) | ||
|
|
||
| print *, "=== Sparse Matrix Example ===" | ||
| print *, "Loading sparse matrix from ", sparse_filename | ||
|
|
||
| ! Load sparse matrix from Matrix Market file | ||
| call load_mm(sparse_filename, index, data, iostat=iostat, iomsg=iomsg) | ||
| if (iostat /= 0) then | ||
| print *, "Error loading sparse matrix: ", iomsg | ||
| stop 1 | ||
| end if | ||
|
|
||
| print *, "Loaded sparse matrix (COO format):" | ||
| print *, "Data (row, col, value):" | ||
| do i = 1, size(data) | ||
| print *, index(1,i), index(2,i), data(i) | ||
| end do | ||
|
|
||
| contains | ||
|
|
||
| subroutine print_matrix(mat) | ||
| real(dp), intent(in) :: mat(:,:) | ||
| integer :: i | ||
|
|
||
| do i = 1, size(mat, 1) | ||
| print *, mat(i, :) | ||
| end do | ||
| print * | ||
| end subroutine print_matrix | ||
|
|
||
| subroutine create_sparse_test_file(filename) | ||
| character(len=*), intent(in) :: filename | ||
| integer :: u | ||
|
|
||
| open(newunit=u, file=filename, status='replace') | ||
| write(u, '(A)') '%%MatrixMarket matrix coordinate real general' | ||
| write(u, '(A)') '% This is a test sparse matrix' | ||
| write(u, '(A)') '4 4 6' | ||
| write(u, '(A)') '1 1 10.0' | ||
| write(u, '(A)') '2 2 20.0' | ||
| write(u, '(A)') '3 3 30.0' | ||
| write(u, '(A)') '4 4 40.0' | ||
| write(u, '(A)') '1 4 5.0' | ||
| write(u, '(A)') '3 1 15.0' | ||
| close(u) | ||
| end subroutine create_sparse_test_file | ||
|
|
||
| end program example_matrix_market |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| ! SPDX-Identifier: MIT | ||
|
|
||
| #:include "common.fypp" | ||
| #:set R_KINDS_TYPES = list(zip(REAL_KINDS, REAL_TYPES, REAL_SUFFIX)) | ||
| #:set C_KINDS_TYPES = list(zip(CMPLX_KINDS, CMPLX_TYPES, CMPLX_SUFFIX)) | ||
| #:set I_KINDS_TYPES = list(zip(INT_KINDS, INT_TYPES, INT_KINDS)) | ||
| #:set RCI_KINDS_TYPES = R_KINDS_TYPES + C_KINDS_TYPES + I_KINDS_TYPES | ||
|
|
||
| !> The Matrix Market (MM) format is a simple, human-readable, ASCII format for sparse | ||
| !> and dense matrices. The format was developed at NIST (National Institute of Standards | ||
| !> and Technology) for the Matrix Market, a repository of test matrices for use in | ||
| !> comparative studies of algorithms for numerical linear algebra. | ||
| !> | ||
| !> For more information, see: https://math.nist.gov/MatrixMarket/formats.html | ||
| module stdlib_io_mm | ||
| use stdlib_kinds, only : int8, int16, int32, int64, sp, dp, xdp, qp | ||
| implicit none | ||
| private | ||
|
|
||
| type, public :: mm_header_type | ||
| integer :: object | ||
| integer :: format | ||
| integer :: qualifier | ||
| integer :: symmetry | ||
| character(len=1024), allocatable :: comments(:) | ||
| end type mm_header_type | ||
|
|
||
| !> Version: experimental | ||
| !> | ||
| !> Load a matrix from a Matrix Market file | ||
| !> ([Specification](../page/specs/stdlib_io.html#load_mm)) | ||
| interface load_mm | ||
| #:for k, t, s in RCI_KINDS_TYPES | ||
| module subroutine load_mm_dense_${s}$(filename, matrix, iostat, iomsg) | ||
| !> Name of the Matrix Market file to load from | ||
| character(len=*), intent(in) :: filename | ||
| !> Matrix to be loaded from the Matrix Market file | ||
| ${t}$, allocatable, intent(out) :: matrix(:,:) | ||
| !> Error status of loading, zero on success | ||
| integer, intent(out), optional :: iostat | ||
| !> Associated error message in case of non-zero status code | ||
| character(len=:), allocatable, intent(out), optional :: iomsg | ||
| end subroutine | ||
| #:endfor | ||
| #:for k, t, s in RCI_KINDS_TYPES | ||
| module subroutine load_mm_coo_${s}$(filename, index, data, iostat, iomsg) | ||
| !> Name of the Matrix Market file to load from | ||
| character(len=*), intent(in) :: filename | ||
| !> Matrix indices to be read from the Matrix Market file | ||
| integer, allocatable, intent(out) :: index(:,:) | ||
| !> Matrix data to be read from the Matrix Market file | ||
| ${t}$, allocatable, intent(out) :: data(:) | ||
| !> Error status of loading, zero on success | ||
| integer, intent(out), optional :: iostat | ||
| !> Associated error message in case of non-zero status code | ||
| character(len=:), allocatable, intent(out), optional :: iomsg | ||
| end subroutine | ||
| #:endfor | ||
| end interface | ||
| public :: load_mm | ||
|
|
||
| !> Version: experimental | ||
| !> | ||
| !> Save a matrix to a Matrix Market file | ||
| !> ([Specification](../page/specs/stdlib_io.html#save_mm)) | ||
| interface save_mm | ||
| #:for k, t, s in RCI_KINDS_TYPES | ||
| module subroutine save_mm_dense_${s}$(filename, matrix, comment, format, symmetry, iostat, iomsg) | ||
| character(len=*), intent(in) :: filename | ||
| ${t}$, intent(in) :: matrix(:,:) | ||
| character(len=*), intent(in), optional :: comment | ||
| character(len=*), intent(in), optional :: format | ||
| character(len=*), intent(in), optional :: symmetry | ||
| integer, intent(out), optional :: iostat | ||
| character(len=:), allocatable, intent(out), optional :: iomsg | ||
| end subroutine | ||
| #:endfor | ||
|
|
||
| #:for k, t, s in RCI_KINDS_TYPES | ||
| module subroutine save_mm_coo_${s}$(filename, index, data, comment, format, symmetry, iostat, iomsg) | ||
| character(len=*), intent(in) :: filename | ||
| integer, intent(in) :: index(:,:) | ||
| ${t}$, intent(in) :: data(:) | ||
| character(len=*), intent(in), optional :: comment | ||
| character(len=*), intent(in), optional :: format | ||
| character(len=*), intent(in), optional :: symmetry | ||
| integer, intent(out), optional :: iostat | ||
| character(len=:), allocatable, intent(out), optional :: iomsg | ||
| end subroutine | ||
| #:endfor | ||
| end interface save_mm | ||
| public :: save_mm | ||
|
|
||
| end module stdlib_io_mm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation only describes the dense matrix interface for load_mm and save_mm, but doesn't document the sparse (COO) interface that accepts separate index and data parameters. The COO interface should be documented as an alternative syntax for loading and saving sparse matrices.