stdlib_specialmatrices.fypp Source File


Source Code

#:include "common.fypp"
#:set RANKS = range(1, 2+1)
#: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 KINDS_TYPES = R_KINDS_TYPES+C_KINDS_TYPES
module stdlib_specialmatrices
    !! Provides derived-types and associated specialized linear algebra drivers
    !! for highly-structured matrices commonly encountered in the discretization
    !! of partial differential equations, as well as control and signal processing
    !! applications. ([Specifications](../page/specs/stdlib_specialmatrices.html))
    use stdlib_linalg_constants
    use stdlib_constants
    use stdlib_linalg_state, only: linalg_state_type, linalg_error_handling, LINALG_ERROR, &
        LINALG_INTERNAL_ERROR, LINALG_VALUE_ERROR
    implicit none
    private
    public :: tridiagonal
    public :: spmv
    public :: dense, transpose, hermitian
    public :: operator(*), operator(+), operator(-)

    !--------------------------------------
    !-----                           ------
    !-----     TYPE DEFINITIONS      ------
    !-----                           ------
    !--------------------------------------

    !--> Tridiagonal matrices
    #:for k1, t1, s1 in (KINDS_TYPES)
    type, public :: tridiagonal_${s1}$_type
        !! Base type to define a `tridiagonal` matrix.
        private
        ${t1}$, allocatable :: dl(:), dv(:), du(:)
        integer(ilp) :: n
    end type
    #:endfor

    !--------------------------------
    !-----                      -----
    !-----     CONSTRUCTORS     -----
    !-----                      -----
    !--------------------------------

    interface tridiagonal
        !! ([Specifications](../page/specs/stdlib_specialmatrices.html#Tridiagonal)) This
        !! interface provides different methods to construct a `tridiagonal` matrix. Only
        !! the non-zero elements of \( A \) are stored, i.e.
        !!
        !! \[
        !!    A
        !!    =
        !!    \begin{bmatrix}
        !!       a_1   &  b_1  \\
        !!       c_1  &  a_2      &  b_2  \\
        !!             &  \ddots   &  \ddots   &  \ddots   \\
        !!             &           &  c_{n-2} &  a_{n-1}  &  b_{n-1} \\
        !!             &           &           &  c_{n-1} &  a_n
        !!    \end{bmatrix}.
        !! \]
        !!
        !! #### Syntax
        !!
        !! - Construct a real `tridiagonal` matrix from rank-1 arrays:
        !!
        !! ```fortran
        !!    integer, parameter :: n
        !!    real(dp), allocatable :: dl(:), dv(:), du(:)
        !!    type(tridiagonal_rdp_type) :: A
        !!    integer :: i
        !!
        !!    dl = [(i, i=1, n-1)]; dv = [(2*i, i=1, n)]; du = [(3*i, i=1, n)]
        !!    A = Tridiagonal(dl, dv, du)
        !! ```
        !!
        !! - Construct a real `tridiagonal` matrix with constant diagonals:
        !!
        !! ```fortran
        !!    integer, parameter :: n
        !!    real(dp), parameter :: a = 1.0_dp, b = 1.0_dp, c = 2.0_dp
        !!    type(tridiagonal_rdp_type) :: A
        !!
        !!    A = Tridiagonal(a, b, c, n)
        !! ```
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function initialize_tridiagonal_pure_${s1}$(dl, dv, du) result(A)
            !! Construct a `tridiagonal` matrix from the rank-1 arrays
            !! `dl`, `dv` and `du`.
            ${t1}$, intent(in) :: dl(:), dv(:), du(:)
            !! Tridiagonal matrix elements.
            type(tridiagonal_${s1}$_type) :: A
            !! Corresponding Tridiagonal matrix.
        end function

        pure module function initialize_constant_tridiagonal_pure_${s1}$(dl, dv, du, n) result(A)
            !! Construct a `tridiagonal` matrix with constant elements.
            ${t1}$, intent(in) :: dl, dv, du
            !! Tridiagonal matrix elements.
            integer(ilp), intent(in) :: n
            !! Matrix dimension.
            type(tridiagonal_${s1}$_type) :: A
            !! Corresponding Tridiagonal matrix.
        end function   

        module function initialize_tridiagonal_impure_${s1}$(dl, dv, du, err) result(A)
            !! Construct a `tridiagonal` matrix from the rank-1 arrays
            !! `dl`, `dv` and `du`.
            ${t1}$, intent(in) :: dl(:), dv(:), du(:)
            !! Tridiagonal matrix elements.
            type(linalg_state_type), intent(out) :: err
            !! Error handling.
            type(tridiagonal_${s1}$_type) :: A
            !! Corresponding Tridiagonal matrix.
        end function

        module function initialize_constant_tridiagonal_impure_${s1}$(dl, dv, du, n, err) result(A)
            !! Construct a `tridiagonal` matrix with constant elements.
            ${t1}$, intent(in) :: dl, dv, du
            !! Tridiagonal matrix elements.
            integer(ilp), intent(in) :: n
            !! Matrix dimension.
            type(linalg_state_type), intent(out) :: err
            !! Error handling.
            type(tridiagonal_${s1}$_type) :: A
            !! Corresponding Tridiagonal matrix.
        end function   
        #:endfor
    end interface

    !----------------------------------
    !-----                        -----
    !-----     LINEAR ALGEBRA     -----
    !-----                        -----
    !----------------------------------

    interface spmv
        !! ([Specifications](../page/specs/stdlib_specialmatrices.html#spmv)) This
        !! interface provides methods to compute the matrix-vector product
        !!
        !!  $$ y = \alpha \mathrm{op}(A) x + \beta y$$
        !!
        !! for the different matrix types defined by `stdlib_specialmatrices`.
        #:for k1, t1, s1 in (KINDS_TYPES)
        #:for rank in RANKS
        module subroutine spmv_tridiag_${rank}$d_${s1}$(A, x, y, alpha, beta, op)
         type(tridiagonal_${s1}$_type), intent(in) :: A
            ${t1}$, intent(in), contiguous, target :: x${ranksuffix(rank)}$
            ${t1}$, intent(inout), contiguous, target :: y${ranksuffix(rank)}$
            real(${k1}$), intent(in), optional :: alpha
            real(${k1}$), intent(in), optional :: beta
            character(1), intent(in), optional :: op
        end subroutine
        #:endfor
        #:endfor
    end interface

    !-------------------------------------
    !-----                           -----
    !-----     UTILITY FUNCTIONS     -----
    !-----                           -----
    !-------------------------------------

    interface dense
        !! This interface provides methods to convert a matrix of one of the
        !! types defined by `stdlib_specialmatrices` to a standard rank-2 array.
        !! ([Specifications](../page/specs/stdlib_specialmatrices.html#dense))
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function tridiagonal_to_dense_${s1}$(A) result(B)
            !! Convert a `tridiagonal` matrix to its dense representation.
            type(tridiagonal_${s1}$_type), intent(in) :: A
            !! Input Tridiagonal matrix.
            ${t1}$, allocatable :: B(:, :)
            !! Corresponding dense matrix.
        end function
        #:endfor
    end interface

    interface transpose
        !! This interface provides methods to compute the transpose operation for
        !! the different matrix types defined by `stdlib_specialmatrices`.
        !! [Specifications](../page/specs/stdlib_specialmatrices.html#transpose)
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function transpose_tridiagonal_${s1}$(A) result(B)
            type(tridiagonal_${s1}$_type), intent(in) :: A
            !! Input matrix.
            type(tridiagonal_${s1}$_type) :: B
        end function
        #:endfor
    end interface

    interface hermitian
        !! This interface provides methods to compute the hermitian operation for
        !! the different matrix types defined by `stdlib_specialmatrices`. For
        !! real-valued matrices, this is equivalent to the standard `transpose`.
        !! [Specifications](../page/specs/stdlib_specialmatrices.html#hermitian)
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function hermitian_tridiagonal_${s1}$(A) result(B)
            type(tridiagonal_${s1}$_type), intent(in) :: A
            !! Input matrix.
            type(tridiagonal_${s1}$_type) :: B
        end function
        #:endfor
    end interface

    !----------------------------------------
    !-----                              -----
    !-----     ARITHMETIC OPERATORS     -----
    !-----                              -----
    !----------------------------------------

    interface operator(*)
        !! Overload the `*` for scalar-matrix multiplications for the different matrix
        !! types provided by `stdlib_specialmatrices`.
        !! [Specifications](../page/specs/stdlib_specialmatrices.html#operators)
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function scalar_multiplication_tridiagonal_${s1}$(alpha, A) result(B)
            ${t1}$, intent(in) :: alpha
            type(tridiagonal_${s1}$_type), intent(in) :: A
            type(tridiagonal_${s1}$_type) :: B
        end function
        pure module function scalar_multiplication_bis_tridiagonal_${s1}$(A, alpha) result(B)
            type(tridiagonal_${s1}$_type), intent(in) :: A
            ${t1}$, intent(in) :: alpha
            type(tridiagonal_${s1}$_type) :: B
        end function
        #:endfor
    end interface

    interface operator(+)
        !! Overload the `+` operator for matrix-matrix addition. The two matrices need to
        !! be of the same type and kind.
        !! [Specifications](../page/specs/stdlib_specialmatrices.html#operators)
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function matrix_add_tridiagonal_${s1}$(A, B) result(C)
            type(tridiagonal_${s1}$_type), intent(in) :: A
            type(tridiagonal_${s1}$_type), intent(in) :: B
            type(tridiagonal_${s1}$_type) :: C
        end function
        #:endfor
    end interface

    interface operator(-)
        !! Overload the `-` operator for matrix-matrix subtraction. The two matrices need to
        !! be of the same type and kind.
        !! [Specifications](../page/specs/stdlib_specialmatrices.html#operators)
        #:for k1, t1, s1 in (KINDS_TYPES)
        pure module function matrix_sub_tridiagonal_${s1}$(A, B) result(C)
            type(tridiagonal_${s1}$_type), intent(in) :: A
            type(tridiagonal_${s1}$_type), intent(in) :: B
            type(tridiagonal_${s1}$_type) :: C
        end function
        #:endfor
    end interface

end module stdlib_specialmatrices