Skip to content

Commit 0a17598

Browse files
github-actions[bot]jvdp1perazz
committed
Tridagonal matrices and associated spmv kernel (fortran-lang#957)
* Added the Tridiagonal type and associated spmv kernel. * Rename dense to dense_mat because of a naming conflict. * Added test for Tridiagonal spmv. * Changed comparison to account for floating point errors. * Move implementations to a dedicated module. Moving all the implementations to a dedicated module (and submodule) will prevent cluter of the `sparse` module as well as make things clearer from an implementation and documentation point of view. * Implementation of basic operations for Tridiagonal matrices is done. * In-code documentation. * Added examples. * Specifications page. * Fix typos in module header. * Fix errors in examples. * Enabled `xdp` and `qp` for `spmv` kernels. * Update test/linalg/test_linalg_sparse.fypp Remove trailing white space. Co-authored-by: Jeremie Vandenplas <[email protected]> * Update example/specialmatrices/example_specialmatrices_dp_spmv.f90 Import only required elements from the module. Co-authored-by: Jeremie Vandenplas <[email protected]> * Consistent lower-casing and imports. * Fixed allocation from source for complex types. * Make use of stdlib_constants to define the various zeros and ones. * Prevent temporary arrays + lower casing every names. * Import everything from stdlib_kinds * Fix imports. * Fix missing argument in check. * Update doc/specs/stdlib_specialmatrices.md Co-authored-by: Federico Perini <[email protected]> * Update doc/specs/stdlib_specialmatrices.md Co-authored-by: Federico Perini <[email protected]> * Update doc/specs/stdlib_specialmatrices.md Co-authored-by: Federico Perini <[email protected]> * Update src/stdlib_specialmatrices.fypp Co-authored-by: Federico Perini <[email protected]> * Update src/stdlib_specialmatrices_tridiagonal.fypp Co-authored-by: Federico Perini <[email protected]> * Improved error handling. * Added test for tridiagonal error handling. --------- Co-authored-by: Jeremie Vandenplas <[email protected]> Co-authored-by: Federico Perini <[email protected]>
2 parents f7c65aa + 3385843 commit 0a17598

13 files changed

+969
-48
lines changed

doc/specs/stdlib_specialmatrices.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
title: specialmatrices
3+
---
4+
5+
# The `stdlib_specialmatrices` module
6+
7+
[TOC]
8+
9+
## Introduction
10+
11+
The `stdlib_specialmatrices` module provides derived types and specialized drivers for highly structured matrices often encountered in scientific computing as well as control and signal processing applications.
12+
These include:
13+
14+
- Tridiagonal matrices
15+
- Symmetric Tridiagonal matrices (not yet supported)
16+
- Circulant matrices (not yet supported)
17+
- Toeplitz matrices (not yet supported)
18+
- Hankel matrices (not yet supported)
19+
20+
In addition, it also provides a `Poisson2D` matrix type (not yet supported) corresponding to the sparse block tridiagonal matrix obtained from discretizing the Laplace operator on a 2D grid with the standard second-order accurate central finite-difference scheme.
21+
22+
## List of derived types for special matrices
23+
24+
Below is a list of the currently supported derived types corresponding to different special matrices.
25+
Note that this module is under active development and this list will eventually grow.
26+
27+
### Tridiagonal matrices {#Tridiagonal}
28+
29+
#### Status
30+
31+
Experimental
32+
33+
#### Description
34+
35+
Tridiagonal matrices are ubiquituous in scientific computing and often appear when discretizing 1D differential operators.
36+
A generic tridiagonal matrix has the following structure:
37+
$$
38+
A
39+
=
40+
\begin{bmatrix}
41+
a_1 & b_1 \\
42+
c_1 & a_2 & b_2 \\
43+
& \ddots & \ddots & \ddots \\
44+
& & c_{n-2} & a_{n-1} & b_{n-1} \\
45+
& & & c_{n-1} & a_n
46+
\end{bmatrix}.
47+
$$
48+
Hence, only one vector of size `n` and two of size `n-1` need to be stored to fully represent the matrix.
49+
This particular structure also lends itself to specialized implementations for many linear algebra tasks.
50+
Interfaces to the most common ones will soon be provided by `stdlib_specialmatrices`.
51+
Tridiagonal matrices are available with all supported data types as `tridiagonal_<kind>_type`, for example:
52+
53+
- `tridiagonal_sp_type` : Tridiagonal matrix of size `n` with `real`/`single precision` data.
54+
- `tridiagonal_dp_type` : Tridiagonal matrix of size `n` with `real`/`double precision` data.
55+
- `tridiagonal_xdp_type` : Tridiagonal matrix of size `n` with `real`/`extended precision` data.
56+
- `tridiagonal_qp_type` : Tridiagonal matrix of size `n` with `real`/`quadruple precision` data.
57+
- `tridiagonal_csp_type` : Tridiagonal matrix of size `n` with `complex`/`single precision` data.
58+
- `tridiagonal_cdp_type` : Tridiagonal matrix of size `n` with `complex`/`double precision` data.
59+
- `tridiagonal_cxdp_type` : Tridiagonal matrix of size `n` with `complex`/`extended precision` data.
60+
- `tridiagonal_cqp_type` : Tridiagonal matrix of size `n` with `complex`/`quadruple precision` data.
61+
62+
63+
#### Syntax
64+
65+
- To construct a tridiagonal matrix from already allocated arrays `dl` (lower diagonal, size `n-1`), `dv` (main diagonal, size `n`) and `du` (upper diagonal, size `n-1`):
66+
67+
`A = ` [[stdlib_specialmatrices(module):tridiagonal(interface)]] `(dl, dv, du)`
68+
69+
- To construct a tridiagonal matrix of size `n x n` with constant diagonal elements `dl`, `dv`, and `du`:
70+
71+
`A = ` [[stdlib_specialmatrices(module):tridiagonal(interface)]] `(dl, dv, du, n)`
72+
73+
#### Example
74+
75+
```fortran
76+
{!example/specialmatrices/example_tridiagonal_dp_type.f90!}
77+
```
78+
79+
## Specialized drivers for linear algebra tasks
80+
81+
Below is a list of all the specialized drivers for linear algebra tasks currently provided by the `stdlib_specialmatrices` module.
82+
83+
### Matrix-vector products with `spmv` {#spmv}
84+
85+
#### Status
86+
87+
Experimental
88+
89+
#### Description
90+
91+
With the exception of `extended precision` and `quadruple precision`, all the types provided by `stdlib_specialmatrices` benefit from specialized kernels for matrix-vector products accessible via the common `spmv` interface.
92+
93+
- For `tridiagonal` matrices, the LAPACK `lagtm` backend is being used.
94+
95+
#### Syntax
96+
97+
`call ` [[stdlib_specialmatrices(module):spmv(interface)]] `(A, x, y [, alpha, beta, op])`
98+
99+
#### Arguments
100+
101+
- `A` : Shall be a matrix of one of the types provided by `stdlib_specialmatrices`. It is an `intent(in)` argument.
102+
103+
- `x` : Shall be a rank-1 or rank-2 array with the same kind as `A`. It is an `intent(in)` argument.
104+
105+
- `y` : Shall be a rank-1 or rank-2 array with the same kind as `A`. It is an `intent(inout)` argument.
106+
107+
- `alpha` (optional) : Scalar value of the same type as `x`. It is an `intent(in)` argument. By default, `alpha = 1`.
108+
109+
- `beta` (optional) : Scalar value of the same type as `y`. It is an `intent(in)` argument. By default `beta = 0`.
110+
111+
- `op` (optional) : In-place operator identifier. Shall be a character(1) argument. It can have any of the following values: `N`: no transpose, `T`: transpose, `H`: hermitian or complex transpose.
112+
113+
@warning
114+
Due to limitations of the underlying `lapack` driver, currently `alpha` and `beta` can only take one of the values `[-1, 0, 1]` for `tridiagonal` and `symtridiagonal` matrices. See `lagtm` for more details.
115+
@endwarning
116+
117+
#### Examples
118+
119+
```fortran
120+
{!example/specialmatrices/example_specialmatrices_dp_spmv.f90!}
121+
```
122+
123+
## Utility functions
124+
125+
### `dense` : converting a special matrix to a standard Fortran array {#dense}
126+
127+
#### Status
128+
129+
Experimental
130+
131+
#### Description
132+
133+
Utility function to convert all the matrix types provided by `stdlib_specialmatrices` to a standard rank-2 array of the appropriate kind.
134+
135+
#### Syntax
136+
137+
`B = ` [[stdlib_specialmatrices(module):dense(interface)]] `(A)`
138+
139+
#### Arguments
140+
141+
- `A` : Shall be a matrix of one of the types provided by `stdlib_specialmatrices`. It is an `intent(in)` argument.
142+
143+
- `B` : Shall be a rank-2 allocatable array of the appropriate `real` or `complex` kind.
144+
145+
### `transpose` : Transposition of a special matrix {#transpose}
146+
147+
#### Status
148+
149+
Experimental
150+
151+
#### Description
152+
153+
Utility function returning the transpose of a special matrix. The returned matrix is of the same type and kind as the input one.
154+
155+
#### Syntax
156+
157+
`B = ` [[stdlib_specialmatrices(module):transpose(interface)]] `(A)`
158+
159+
#### Arguments
160+
161+
- `A` : Shall be a matrix of one of the types provided by `stdlib_specialmatrices`. It is an `intent(in)` argument.
162+
163+
- `B` : Shall be a matrix of one of the same type and kind as `A`.
164+
165+
### `hermitian` : Complex-conjugate transpose of a special matrix {#hermitian}
166+
167+
#### Status
168+
169+
Experimental
170+
171+
#### Description
172+
173+
Utility function returning the complex-conjugate transpose of a special matrix. The returned matrix is of the same type and kind as the input one. For real-valued matrices, `hermitian` is equivalent to `transpose`.
174+
175+
#### Syntax
176+
177+
`B = ` [[stdlib_specialmatrices(module):hermitian(interface)]] `(A)`
178+
179+
#### Arguments
180+
181+
- `A` : Shall be a matrix of one of the types provided by `stdlib_specialmatrices`. It is an `intent(in)` argument.
182+
183+
- `B` : Shall be a matrix of one of the same type and kind as `A`.
184+
185+
### Operator overloading (`+`, `-`, `*`) {#operators}
186+
187+
#### Status
188+
189+
Experimental
190+
191+
#### Description
192+
193+
The definition of all standard artihmetic operators have been overloaded to be applicable for the matrix types defined by `stdlib_specialmatrices`:
194+
195+
- Overloading the `+` operator for adding two matrices of the same type and kind.
196+
- Overloading the `-` operator for subtracting two matrices of the same type and kind.
197+
- Overloading the `*` for scalar-matrix multiplication.
198+
199+
#### Syntax
200+
201+
- Adding two matrices of the same type:
202+
203+
`C = A` [[stdlib_specialmatrices(module):operator(+)(interface)]] `B`
204+
205+
- Subtracting two matrices of the same type:
206+
207+
`C = A` [[stdlib_specialmatrices(module):operator(-)(interface)]] `B`
208+
209+
- Scalar multiplication
210+
211+
`B = alpha` [[stdlib_specialmatrices(module):operator(*)(interface)]] `A`
212+
213+
@note
214+
For addition (`+`) and subtraction (`-`), matrices `A`, `B` and `C` all need to be of the same type and kind. For scalar multiplication (`*`), `A` and `B` need to be of the same type and kind, while `alpha` is either `real` or `complex` (with the same kind again) depending on the type being used.
215+
@endnote

example/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_subdirectory(random)
2525
add_subdirectory(selection)
2626
add_subdirectory(sorting)
2727
add_subdirectory(specialfunctions_gamma)
28+
add_subdirectory(specialmatrices)
2829
add_subdirectory(stats)
2930
add_subdirectory(stats_distribution_exponential)
3031
add_subdirectory(stats_distribution_normal)
Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,49 @@
11
program example_sparse_data_accessors
2-
use stdlib_linalg_constants, only: dp
3-
use stdlib_sparse
4-
implicit none
2+
use stdlib_linalg_constants, only: dp
3+
use stdlib_sparse
4+
implicit none
55

6-
real(dp) :: mat(2,2)
7-
real(dp), allocatable :: dense(:,:)
8-
type(CSR_dp_type) :: CSR
9-
type(COO_dp_type) :: COO
10-
integer :: i, j, locdof(2)
6+
real(dp) :: mat(2, 2)
7+
real(dp), allocatable :: dense_matrix(:, :)
8+
type(CSR_dp_type) :: CSR
9+
type(COO_dp_type) :: COO
10+
integer :: i, j, locdof(2)
1111

12-
! Initial data
13-
mat(:,1) = [1._dp,2._dp]
14-
mat(:,2) = [2._dp,1._dp]
15-
allocate(dense(5,5) , source = 0._dp)
16-
do i = 0, 3
17-
dense(1+i:2+i,1+i:2+i) = dense(1+i:2+i,1+i:2+i) + mat
18-
end do
12+
! Initial data
13+
mat(:, 1) = [1._dp, 2._dp]
14+
mat(:, 2) = [2._dp, 1._dp]
15+
allocate (dense_matrix(5, 5), source=0._dp)
16+
do i = 0, 3
17+
dense_matrix(1 + i:2 + i, 1 + i:2 + i) = dense_matrix(1 + i:2 + i, 1 + i:2 + i) + mat
18+
end do
1919

20-
print *, 'Original Matrix'
21-
do j = 1 , 5
22-
print '(5f8.1)',dense(j,:)
23-
end do
20+
print *, 'Original Matrix'
21+
do j = 1, 5
22+
print '(5f8.1)', dense_matrix(j, :)
23+
end do
2424

25-
! Initialize CSR data and reset dense reference matrix
26-
call dense2coo(dense,COO)
27-
call coo2csr(COO,CSR)
28-
CSR%data = 0._dp
29-
dense = 0._dp
25+
! Initialize CSR data and reset dense reference matrix
26+
call dense2coo(dense_matrix, COO)
27+
call coo2csr(COO, CSR)
28+
CSR%data = 0._dp
29+
dense_matrix = 0._dp
3030

31-
! Iteratively add blocks of data
32-
do i = 0, 3
33-
locdof(1:2) = [1+i,2+i]
34-
call CSR%add(locdof,locdof,mat)
35-
! lets print a dense view of every step
36-
call csr2dense(CSR,dense)
37-
print '(A,I2)', 'Add block :', i+1
38-
do j = 1 , 5
39-
print '(5f8.1)',dense(j,:)
40-
end do
41-
end do
31+
! Iteratively add blocks of data
32+
do i = 0, 3
33+
locdof(1:2) = [1 + i, 2 + i]
34+
call CSR%add(locdof, locdof, mat)
35+
! lets print a dense view of every step
36+
call csr2dense(CSR, dense_matrix)
37+
print '(A,I2)', 'Add block :', i + 1
38+
do j = 1, 5
39+
print '(5f8.1)', dense_matrix(j, :)
40+
end do
41+
end do
4242

43-
! Request values from the matrix
44-
print *, ''
45-
print *, 'within sparse pattern :',CSR%at(2,1)
46-
print *, 'outside sparse pattern :',CSR%at(5,2)
47-
print *, 'outside matrix pattern :',CSR%at(7,7)
48-
49-
end program example_sparse_data_accessors
43+
! Request values from the matrix
44+
print *, ''
45+
print *, 'within sparse pattern :', CSR%at(2, 1)
46+
print *, 'outside sparse pattern :', CSR%at(5, 2)
47+
print *, 'outside matrix pattern :', CSR%at(7, 7)
48+
49+
end program example_sparse_data_accessors
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ADD_EXAMPLE(specialmatrices_dp_spmv)
2+
ADD_EXAMPLE(tridiagonal_dp_type)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
program example_tridiagonal_matrix
2+
use stdlib_linalg_constants, only: dp
3+
use stdlib_specialmatrices, only: tridiagonal_dp_type, tridiagonal, dense, spmv
4+
implicit none
5+
6+
integer, parameter :: n = 5
7+
type(tridiagonal_dp_type) :: A
8+
real(dp) :: dl(n - 1), dv(n), du(n - 1)
9+
real(dp) :: x(n), y(n), y_dense(n)
10+
integer :: i
11+
12+
! Create an arbitrary tridiagonal matrix.
13+
dl = [(i, i=1, n - 1)]; dv = [(2*i, i=1, n)]; du = [(3*i, i=1, n - 1)]
14+
A = tridiagonal(dl, dv, du)
15+
16+
! Initialize vectors.
17+
x = 1.0_dp; y = 0.0_dp; y_dense = 0.0_dp
18+
19+
! Perform matrix-vector products.
20+
call spmv(A, x, y)
21+
y_dense = matmul(dense(A), x)
22+
23+
print *, 'dense :', y_dense
24+
print *, 'Tridiagonal :', y
25+
26+
end program example_tridiagonal_matrix
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
program example_tridiagonal_matrix
2+
use stdlib_linalg_constants, only: dp
3+
use stdlib_specialmatrices
4+
implicit none
5+
6+
integer, parameter :: n = 5
7+
type(Tridiagonal_dp_type) :: A
8+
real(dp) :: dl(n - 1), dv(n), du(n - 1)
9+
10+
! Generate random tridiagonal elements.
11+
call random_number(dl)
12+
call random_number(dv)
13+
call random_number(du)
14+
15+
! Create the corresponding Tridiagonal matrix.
16+
A = Tridiagonal(dl, dv, du)
17+
18+
end program example_tridiagonal_matrix

src/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ set(fppFiles
3232
stdlib_linalg_kronecker.fypp
3333
stdlib_linalg_cross_product.fypp
3434
stdlib_linalg_eigenvalues.fypp
35-
stdlib_linalg_solve.fypp
35+
stdlib_linalg_solve.fypp
3636
stdlib_linalg_determinant.fypp
3737
stdlib_linalg_qr.fypp
3838
stdlib_linalg_inverse.fypp
3939
stdlib_linalg_pinv.fypp
4040
stdlib_linalg_norms.fypp
4141
stdlib_linalg_state.fypp
42-
stdlib_linalg_svd.fypp
42+
stdlib_linalg_svd.fypp
4343
stdlib_linalg_cholesky.fypp
4444
stdlib_linalg_schur.fypp
4545
stdlib_optval.fypp
@@ -55,6 +55,8 @@ set(fppFiles
5555
stdlib_specialfunctions_activations.fypp
5656
stdlib_specialfunctions_gamma.fypp
5757
stdlib_specialfunctions.fypp
58+
stdlib_specialmatrices.fypp
59+
stdlib_specialmatrices_tridiagonal.fypp
5860
stdlib_stats.fypp
5961
stdlib_stats_corr.fypp
6062
stdlib_stats_cov.fypp

0 commit comments

Comments
 (0)