specialmatrices_strang.f90 Source File


Source Code

module specialmatrices_strang
   use stdlib_linalg_constants, only: dp, ilp, lk
   implicit none(type, external)
   private

   ! --> Linear algebra
   public :: det, trace
   public :: matmul
   public :: solve
   public :: eigh, eigvalsh

   ! --> Utility functions.
   public :: dense
   public :: shape
   public :: size

   !---------------------------------------------------
   !-----     Base type for the Strang matrix     -----
   !---------------------------------------------------

   type, public :: Strang
      !! Base type used to define the `Strang` matrix.
      private
      integer(ilp) :: n
      !! Dimension of the matrix.
   end type

   !--------------------------------
   !-----     Constructors     -----
   !--------------------------------

   interface Strang
      !! Constructor for generating the `Strang` matrix of size `n`. The
      !! matrix corresponds to the standard 3-point finite-difference
      !! approximation of the 1D Laplace operator with unit grid-spacing
      !! (\(\Delta x = 1\)) and homogeneous Dirichlet boundary conditions.
      !! It reads
      !!
      !! \[
      !!    A
      !!    =
      !!    \begin{bmatrix}
      !!       2  &  -1 \\
      !!       -1 &  2        &  -1 \\
      !!          &  \ddots   &  \ddots   &  \ddots   \\
      !!          &           &  -1       &  2  &  -1 \\
      !!          &           &           &  -1 &  2
      !!    \end{bmatrix}
      !! \]
      !!
      !! #### Syntax
      !!
      !! - Construct a `Strang` matrix of size 100.
      !!
      !! ```fortran
      !!    integer, parameter :: n = 100
      !!    type(Strang) :: S
      !!    S = Strang(n)
      !! ```
      !!
      !! @note
      !! Only `double precision` is currently supported for this matrix type.
      !! @endnote
      pure module function initialize(n) result(A)
         !! Construct the Strang matrix of size `n`.
         integer(ilp), intent(in) :: n
         !! Dimension of the matrix.
         type(Strang) :: A
         !! Strang matrix of size `n`.
      end function
   end interface

   !-------------------------------------------------------------------
   !-----     Matrix-vector and Matrix-matrix multiplications     -----
   !-------------------------------------------------------------------

   interface matmul
      !! This interface overloads the Fortran intrinsic `matmul` for the
      !! `Strang` matrix, both for matrix-vector and matrix-matrix products.
      !! For matrix-matrix product \( C = A B \), only \(A\) can be a `Strang`
      !! matrix. Both \( B \) and \( C \) are standard rank-2 arrays. All
      !! underlying functions are defined as `pure`.
      !!
      !! #### Syntax
      !!
      !! ```fortran
      !!    y = matmul(A, x)
      !! ```
      pure module function spmv(A, x) result(y)
         !! Driver for the matrix-vector product.
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp), intent(in) :: x(:)
         !! Input vector.
         real(dp), allocatable :: y(:)
         !! Output vector.
      end function

      pure module function spmvs(A, X) result(Y)
         !! Driver for the matrix-matrix product.
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp), intent(in) :: X(:, :)
         !! Input vector.
         real(dp), allocatable :: Y(:, :)
         !! Output vector.
      end function
   end interface

   !-----------------------------------------------
   !-----     Linear systems of equations     -----
   !-----------------------------------------------

   interface solve
      !! This interface overloads the `solve` interface from `stdlib_linalg`
      !! for solving a system \(Ax = b\) where \(A\) is a `Strang` matrix.
      !! It also enables to solve a linear system with multiple right-hand
      !! sides.
      !!
      !! #### Syntax
      !!
      !! ```fortran
      !!    x = solve(A, b)
      !! ```
      !!
      !! #### Arguments
      !!
      !! - `A` :  Matrix of `Strang` type. It is an `intent(in)` argument.
      !!
      !! - `b` :  Rank-1 or rank-2 array defining the right-hand side(s).
      !!          It is an `intent(in)` argument.
      !!
      !! - `x` :  Solution of the linear system. It has the same type and
      !!          shape as `b`.
      module function solve_single_rhs(A, b, refine) result(x)
         type(Strang), intent(in) :: A
         !! Coefficient matrix.
         real(dp), target, intent(in) :: b(:)
         !! Right-hand side vector.
         logical(lk), optional, intent(in) :: refine
         !! Whether iterative refinement is used or not.
         real(dp), allocatable, target :: x(:)
         !! Solution vector.
      end function

      module function solve_multi_rhs(A, b, refine) result(x)
         type(Strang), intent(in) :: A
         !! Coefficient matrix.
         real(dp), intent(in) :: b(:, :)
         !! Right-hand side vectors.
         logical(lk), optional, intent(in) :: refine
         !! Whether iterative refinement is used or not.
         real(dp), allocatable :: x(:, :)
         !! Solution vectors.
      end function
   end interface

   !-----------------------------------------
   !-----     Determinant and Trace     -----
   !-----------------------------------------

   interface det
      !! This interface overloads the `det` interface from `stdlib_linalg`
      !! to compute the determinant \(\det(A)\) where \(A\) is of type
      !! `Strang`.
      !!
      !! #### Syntax
      !!
      !! ```fortran
      !!    d = det(A)
      !! ```
      !!
      !! #### Arguments
      !!
      !! - `A` :  Matrix of type `Strang`. It is an `intent(in)` argument.
      !!
      !! - `d` :  Determinant of the matrix.
      pure module function det_rdp(A) result(d)
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp) :: d
         !! Determinant of the matrix.
      end function
   end interface

   interface trace
      !! This interface overloads the `trace` interface from `stdlib_linalg`
      !! to compute the trace of a matrix \(A\) of type `Strang`.
      !!
      !! #### Strang
      !!
      !! ```fortran
      !!    tr = trace(A)
      !! ```
      !!
      !! #### Arguments
      !!
      !! - `A` :  Matrix of `Strang` type. It is an `intent(in)` argument.
      !!
      !! - `tr`:  Trace of the matrix.
      pure module function trace_rdp(A) result(tr)
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp) :: tr
         !! Trace of the matrix.
      end function
   end interface

   !--------------------------------------------
   !-----     Eigenvalue Decomposition     -----
   !--------------------------------------------

   interface eigvalsh
      !! This interface overloads the `eigvalsh` interface from `stdlib_linalg`
      !! to compute the eigenvalues of a `Strang` matrix. Note that these
      !! eigenvalues are known analytically.
      !!
      !! #### Syntax
      !!
      !! ```fortran
      !!    lambda = eigvalsh(A)
      !! ```
      !!
      !! #### Arguments
      !!
      !! - `A` :  Matrix of type `Strang`. It is an `intent(in)` argument.
      !! 
      !! - `lambda`  :  Rank-1 `real` array returning the eigenvalues of `A`
      !!                in increasing order. It is an `intent(out)` argument.
      pure module function eigvalsh_rdp(A) result(lambda)
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp), allocatable :: lambda(:)
         !! Eigenvalues.
      end function
   end interface

   interface eigh
      !! This interface overloads the `eigh` interface from `stdlib_linalg`
      !! to compute the eigenvalues and eigenvectors of a `Strang` matrix.
      !!
      !! #### Syntax
      !!
      !! ```fortran
      !!    call eigh(A, lambda, vectors)
      !! ```
      !!
      !! #### Arguments
      !!
      !! - `A` :  Matrix of type `Strang`. It is an `intent(in)` argument.
      !!
      !! - `lambda`  :  Rank-1 `real` array returning the eigenvalues of `A`
      !!                in increasing order. It is an `intent(out)` argument.
      !!
      !! -  `vectors`:  Rank-2 `real` array of size `[n x n]` returning the
      !!                eigenvectors of `A`. It is an `intent(out)` argument.
      !!
      !! @note
      !! Eigenvalues and eigenvectors of the Strang matrix are known
      !! analytically and can thus be constructed very efficiently.
      !! @endnote
      pure module subroutine eigh_rdp(A, lambda, vectors)
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp), allocatable, intent(out) :: lambda(:)
         !! Eigenvalues.
         real(dp), allocatable, intent(out) :: vectors(:, :)
         !! Eigenvectors.
      end subroutine
   end interface

   !-------------------------------------
   !-----     Utility functions     -----
   !-------------------------------------

   interface dense
      !! Convert a matrix of type `Strang` to its dense representation as a
      !! standard rank-2 array
      !!
      !! #### Syntax
      !!
      !! ```fortran
      !!    B = dense(A)
      !! ```
      !!
      !! #### Arguments
      !!
      !! - `A` :  Matrix of type `Strang`. It is an `intent(in)` argument.
      !!
      !! - `B` :  Rank-2 array representation fo the matrix \(A\).
      pure module function dense_rdp(A) result(B)
         type(Strang), intent(in) :: A
         !! Input matrix.
         real(dp), allocatable :: B(:, :)
         !! Dense representation.
      end function
   end interface

   interface shape
      !! Utility function returning the shape of a `Strang` matrix \(A\).
      pure module function shape_rdp(A) result(arr_shape)
         type(Strang), intent(in) :: A
         !! Input matrix.
         integer(ilp) :: arr_shape(2)
         !! Shape of the matrix.
      end function
   end interface

   interface size
      !! Utility function returning the size of a `Strang` matrix \(A\)
      !! along a given dimension.
      pure module function size_rdp(A, dim) result(arr_size)
         type(Strang), intent(in) :: A
         !! Input matrix.
         integer(ilp), intent(in) :: dim
         !! Queried dimension.
         integer(ilp) :: arr_size
         !! Corresponding size.
      end function
   end interface
contains
end module