Skip to content

Commit cca105b

Browse files
authored
Merge branch 'fortran-lang:master' into gmres
2 parents 9da3671 + d068e75 commit cca105b

24 files changed

Lines changed: 4120 additions & 5 deletions

.github/workflows/ci_flang.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CI_Flang
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
10+
cancel-in-progress: true
11+
12+
env:
13+
CMAKE_BUILD_PARALLEL_LEVEL: "2"
14+
CTEST_PARALLEL_LEVEL: "2"
15+
CTEST_TEST_TIMEOUT: "5"
16+
17+
jobs:
18+
Build:
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Python 3.x
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: 3.x
29+
30+
- name: Install fypp
31+
run: pip install --upgrade fypp
32+
33+
- name: Setup Flang
34+
uses: minhqdao/setup-fortran@v1
35+
id: setup-fortran
36+
with:
37+
compiler: flang
38+
version: latest
39+
40+
- name: Configure with CMake
41+
run: >-
42+
cmake -Wdev
43+
-DCMAKE_BUILD_TYPE=Release
44+
-DCMAKE_Fortran_COMPILER=${{ steps.setup-fortran.outputs.fc }}
45+
-DCMAKE_C_COMPILER=${{ steps.setup-fortran.outputs.cc }}
46+
-DCMAKE_MAXIMUM_RANK:STRING=4
47+
-DCMAKE_INSTALL_PREFIX=$PWD/_dist
48+
-DFIND_BLAS:BOOL=FALSE
49+
-DWITH_XDP=off
50+
-DWITH_QP=off
51+
-S . -B build
52+
53+
- name: Build
54+
run: cmake --build build --parallel
55+
56+
- name: Catch build fail
57+
if: failure()
58+
run: cmake --build build --verbose --parallel 1
59+
60+
- name: Test
61+
run: >-
62+
ctest
63+
--test-dir build
64+
--parallel
65+
--output-on-failure
66+
--no-tests=error
67+
68+
- name: Install project
69+
run: cmake --install build

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ GCC Fortran (MSYS) | 13 | Windows Server 2022 (10.0.20348 Build 1547) | x86_64
9494
GCC Fortran (MinGW) | 13 | Windows Server 2022 (10.0.20348 Build 1547) | x86_64
9595
Intel oneAPI LLVM | 2024.1 | Ubuntu 24.04.3 LTS | x86_64
9696
Intel oneAPI classic | 2021.10 | Ubuntu 22.04.5 LTS | x86_64
97+
[Flang LLVM](https://flang.llvm.org/docs/) | 22 | Ubuntu 24.04.3 LTS | x86_64
9798

9899
The following combinations are known to work, but they are not tested in the CI:
99100

doc/specs/stdlib_io.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,136 @@ Exceptions trigger an `error stop` unless the optional `err` argument is provide
321321
{!example/io/example_get_file.f90!}
322322
```
323323

324+
## Matrix Market Format I/O
325+
326+
### Status
327+
328+
Experimental
329+
330+
### Description
331+
332+
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.
333+
334+
### `load_mm` - load a matrix from Matrix Market file
335+
336+
Loads a 2D matrix from a Matrix Market format file. Symmetric matrices are expanded to full storage.
337+
338+
#### Syntax
339+
340+
- To load a matrix of `array` format:
341+
342+
`call ` [[stdlib_io_mm(module):load_mm(interface)]] `(filename, matrix [, iostat, iomsg])`
343+
344+
- To load a matrix of `coordinate` format:
345+
346+
`call ` [[stdlib_io_mm(module):load_mm(interface)]] `(filename, index, data [, iostat, iomsg])`
347+
348+
#### Arguments
349+
350+
**`Array` format**
351+
352+
`call ` [[stdlib_io_mm(module):load_mm(interface)]] `(filename, matrix [, iostat, iomsg])`
353+
354+
- `filename`: Shall be a character expression containing the Matrix Market file name to read from.
355+
356+
- `matrix`: Shall be an allocatable rank-2 array of type `real`, `complex`, or `integer` that will contain the loaded matrix.
357+
358+
- `iostat` (optional): Shall be a scalar of type `integer` that receives the error status. Zero indicates success.
359+
360+
- `iomsg` (optional): Shall be an allocatable character string that receives the error message if iostat is non-zero.
361+
362+
**`Coordinate` format**
363+
364+
`call ` [[stdlib_io_mm(module):load_mm(interface)]] `(filename, index, data [, iostat, iomsg])`
365+
366+
- `filename`: Shall be a character expression containing the Matrix Market file name to read from.
367+
368+
- `index`: Shall be an allocatable rank-2 array of type `integer` that will contain the indices of the loaded matrix.
369+
370+
- `data`: Shall be an allocatable rank-1 array of type `real`, `complex`, or `integer` that will contain the values of the loaded matrix.
371+
372+
- `iostat` (optional): Shall be a scalar of type `integer` that receives the error status. Zero indicates success.
373+
374+
- `iomsg` (optional): Shall be an allocatable character string that receives the error message if iostat is non-zero.
375+
376+
### `save_mm` - save a matrix to Matrix Market file
377+
378+
Saves a 2D matrix to Matrix Market format file.
379+
380+
#### Syntax
381+
382+
- To save a matrix of `array` format:
383+
384+
`call ` [[stdlib_io_mm(module):save_mm(interface)]] `(filename, matrix [, comment, format, symmetry, iostat, iomsg])`
385+
386+
- To save a matrix of `coordinate` format:
387+
388+
`call ` [[stdlib_io_mm(module):save_mm(interface)]] `(filename, index, data [, comment, format, symmetry, iostat, iomsg])`
389+
390+
#### Arguments
391+
392+
**`Array` format**
393+
394+
`call ` [[stdlib_io_mm(module):save_mm(interface)]] `(filename, matrix [, comment, format, symmetry, iostat, iomsg])`
395+
396+
- `filename`: Shall be a character expression containing the Matrix Market file name to write to.
397+
398+
- `matrix`: Shall be a rank-2 array of type `real`, `complex`, or `integer` to save.
399+
400+
- `comment` (optional): Shall be a character expression containing additional comments for the file header.
401+
402+
- `format` (optional): Shall be a character expression specifying how entries are written.
403+
404+
- `symmetry` (optional): Shall be a character expression defining the symmetry of the matrix. Allowed values: `auto`, `general`, `symmetric`, `skew-symmetric`, `hermitian`.
405+
- `auto`: Detects the symmetry automatically, falls back to `general` if no symmetry is found.
406+
- `general`: all entries are stored
407+
- `symmetric` / `hermitian`: only the lower triangle (including diagonal) is stored
408+
- `skew-symmetric`: only the strictly lower triangle (excluding diagonal) is stored
409+
410+
Default: `general`
411+
412+
- `iostat` (optional): Shall be a scalar of type `integer` that receives the error status. Zero indicates success.
413+
414+
- `iomsg` (optional): Shall be an allocatable character string that receives the error message if iostat is non-zero.
415+
416+
**`Coordinate` format**
417+
418+
`call ` [[stdlib_io_mm(module):save_mm(interface)]] `(filename, index, data [, comment, format, symmetry, iostat, iomsg])`
419+
420+
- `filename`: Shall be a character expression containing the Matrix Market file name to write to.
421+
422+
- `index`: Shall be a rank-2 `integer` array of shape `(2, n)` specifying the indices of the entries.
423+
- index(1,:) shall contain row indices
424+
- index(2,:) shall contain column indices
425+
426+
- `data`: Shall be a rank-1 array of type `real`, `complex`, or `integer` to save.
427+
- If `size(data) == n`, the values for each index are written.
428+
- If `size(data) == 1`, a `pattern` matrix is written (no explicit values)
429+
430+
- `comment` (optional): Shall be a character expression containing additional comments for the file header.
431+
432+
- `format` (optional): Shall be a character expression specifying how entries are written.
433+
434+
- `symmetry` (optional): Shall be a character expression defining the symmetry of the matrix. Allowed values: `general`, `symmetric`, `skew-symmetric`, `hermitian`.
435+
- `general`: all entries are stored
436+
- `symmetric` / `hermitian`: only the lower triangle (including diagonal) is stored
437+
- `skew-symmetric`: only the strictly lower triangle (excluding diagonal) is stored
438+
439+
- `iostat` (optional): Shall be a scalar of type `integer` that receives the error status. Zero indicates success.
440+
441+
- `iomsg` (optional): Shall be an allocatable character string that receives the error message if iostat is non-zero.
442+
443+
### Matrix Market Format Details
444+
445+
The Matrix Market format supports:
446+
447+
- **Object types**: Currently only `matrix` is supported
448+
- **Formats**: `coordinate` (sparse) and `array` (dense)
449+
- **Data types**: `real`, `complex`, `integer`, `pattern`
450+
- **Symmetry**: `general`, `symmetric`, `skew-symmetric`, `hermitian`, `auto` (Currently only supported for `array` format)
451+
452+
### Example
453+
454+
```fortran
455+
{!example/io/example_matrix_market.f90!}
456+
```

example/io/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ADD_EXAMPLE(fmt_constants)
33
ADD_EXAMPLE(get_file)
44
ADD_EXAMPLE(loadnpy)
55
ADD_EXAMPLE(loadtxt)
6+
ADD_EXAMPLE(matrix_market)
67
ADD_EXAMPLE(open)
78
ADD_EXAMPLE(savenpy)
89
ADD_EXAMPLE(savetxt)
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
program example_matrix_market
2+
use stdlib_io_mm, only : load_mm, save_mm
3+
use stdlib_kinds, only : dp
4+
use stdlib_error, only: error_stop
5+
implicit none
6+
7+
real(dp), allocatable :: matrix(:,:), matrix2(:,:)
8+
integer, allocatable :: index(:,:)
9+
complex(dp), allocatable :: data(:)
10+
character(len=*), parameter :: dense_filename = "example_dense.mtx"
11+
character(len=*), parameter :: sparse_filename = "example_sparse.mtx"
12+
integer :: iostat, i
13+
character(len=:), allocatable :: errmsg
14+
character(len=:), allocatable :: iomsg
15+
16+
! Create a test dense matrix
17+
allocate(matrix(3,3))
18+
matrix = reshape([1.0_dp, 2.0_dp, 3.0_dp, &
19+
4.0_dp, 5.0_dp, 6.0_dp, &
20+
7.0_dp, 8.0_dp, 9.0_dp], [3,3])
21+
22+
print *, "=== Dense Matrix Example ==="
23+
print *, "Original dense matrix:"
24+
call print_matrix(matrix)
25+
26+
! Save dense matrix to Matrix Market file
27+
call save_mm(dense_filename, matrix, format="ES24.15E2", symmetry="general", iostat=iostat, iomsg=iomsg)
28+
if (iostat /= 0) then
29+
errmsg = "Error saving dense matrix: " // trim(iomsg)
30+
call error_stop(errmsg)
31+
end if
32+
33+
print *, "Dense matrix saved to ", dense_filename
34+
35+
! Load dense matrix from Matrix Market file
36+
call load_mm(dense_filename, matrix2, iostat=iostat, iomsg=iomsg)
37+
if (iostat /= 0) then
38+
errmsg = "Error loading dense matrix: " // trim(iomsg)
39+
call error_stop(errmsg)
40+
end if
41+
42+
print *, "Loaded dense matrix:"
43+
call print_matrix(matrix2)
44+
45+
print *, "=== Sparse Matrix Example ==="
46+
! Create a test sparse matrix
47+
allocate(index(2,6))
48+
allocate(data(6))
49+
index(:,1) = [1,1]; data(1) = (10.0_dp, -1.5_dp)
50+
index(:,2) = [2,2]; data(2) = (20.0_dp, 2.0_dp)
51+
index(:,3) = [3,3]; data(3) = (30.0_dp, 3.0_dp)
52+
index(:,4) = [4,4]; data(4) = (40.0_dp, -4.0_dp)
53+
index(:,5) = [1,4]; data(5) = ( 5.0_dp, -7.5_dp)
54+
index(:,6) = [3,1]; data(6) = (15.0_dp, 25.0_dp)
55+
56+
! Save sparse matrix to Matrix Market file
57+
call save_mm(sparse_filename, index, data, format="ES24.15E2", symmetry="general", iostat=iostat, iomsg=iomsg)
58+
if (iostat /= 0) then
59+
errmsg = "Error saving sparse matrix: " // trim(iomsg)
60+
call error_stop(errmsg)
61+
end if
62+
63+
print *, "Sparse matrix saved to ", sparse_filename
64+
65+
! Load sparse matrix from Matrix Market file
66+
call load_mm(sparse_filename, index, data, iostat=iostat, iomsg=iomsg)
67+
if (iostat /= 0) then
68+
errmsg = "Error loading sparse matrix: " // trim(iomsg)
69+
call error_stop(errmsg)
70+
end if
71+
72+
print *, "Loaded sparse matrix (COO format):"
73+
print *, "Data (row, col, value):"
74+
do i = 1, size(data)
75+
print *, index(1,i), index(2,i), data(i)
76+
end do
77+
78+
contains
79+
80+
subroutine print_matrix(mat)
81+
real(dp), intent(in) :: mat(:,:)
82+
integer :: i
83+
84+
do i = 1, size(mat, 1)
85+
print *, mat(i, :)
86+
end do
87+
print *
88+
end subroutine print_matrix
89+
90+
end program example_matrix_market

src/datetime/stdlib_datetime.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ pure subroutine civil_from_days(z, y, m, d)
682682
end if
683683
era = int(era64)
684684
doe = int(zz - era64 * 146097_int64)
685-
yoe = (doe - doe/1461 + doe/36524 &
685+
yoe = (doe - doe/1460 + doe/36524 &
686686
- doe/146096) / 365
687687
y = yoe + era * 400
688688
doy = doe - (365*yoe + yoe/4 - yoe/100)

src/io/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ set(io_fppFiles
33
stdlib_io_npy.fypp
44
stdlib_io_npy_load.fypp
55
stdlib_io_npy_save.fypp
6+
stdlib_io_mm.fypp
7+
stdlib_io_mm_load.fypp
8+
stdlib_io_mm_save.fypp
69
)
710

811
set(io_cppFiles

0 commit comments

Comments
 (0)