module LightKrylov_Utils !! This module provides a set of utility functions used throughout `LightKrylov`. !! It includes: !! !! - `assert_shape`: Assert that the shape of the argument is the expected shape. !! - `eig`: Compute the eigenvalue decomposition of a general matrix. !! - `sqrtm`: Compute the non-negative square root of a symmetric positive definite matrix using its SVD. !! - `ordschur`: Re-order the Schur factorization to have the selected eigenvalues in the upper left block. !! !! Note that as the development of `stdlib` progresses, some of these functions !! will be deprecated in favor of the `stdlib` implementations. !-------------------------------------------- !----- Standard Fortran Library ----- !-------------------------------------------- use iso_fortran_env, only: output_unit !------------------------------- !----- LightKrylov ----- !------------------------------- use LightKrylov_Constants ! use LightKrylov_Logger use LightKrylov_Logger, only: log_warning, log_error, log_message, log_information, & & stop_error, check_info implicit none private character(len=*), parameter :: this_module = 'LK_Utils' character(len=*), parameter :: this_module_long = 'LightKrylov_Utils' !---------------------------------- !----- Public exports ----- !---------------------------------- public :: assert_shape public :: log2 public :: eig public :: ordschur public :: sqrtm public :: expm public :: givens_rotation public :: apply_givens_rotation public :: solve_triangular !------------------------------------------------- !----- Options for iterative solvers ----- !------------------------------------------------- type, abstract, public :: abstract_opts !! Abstract type for options from which all others are extended. end type type, abstract, public :: abstract_metadata !! Abstract type for solver metadata from which all others are extended. private contains procedure(abstract_print_metadata), pass(self), deferred, public :: print procedure(abstract_reset_metadata), pass(self), deferred, public :: reset end type abstract interface subroutine abstract_print_metadata(self, reset_counters, verbose) import abstract_metadata class(abstract_metadata), intent(inout) :: self logical, optional, intent(in) :: reset_counters logical, optional, intent(in) :: verbose end subroutine subroutine abstract_reset_metadata(self) import abstract_metadata class(abstract_metadata), intent(inout) :: self end subroutine end interface !------------------------------------- !----- Utility functions ----- !------------------------------------- ! NOTE : Most of these functions will gradually disappear as more stable ! versions make their ways into the Fortran stdlib library. interface assert_shape !! This interface provides methods to assert tha thte shape of its input vector or !! matrix is as expected. It throws an error if not. module subroutine assert_shape_vector_rsp(v, size, vecname, module, procedure) real(sp), intent(in) :: v(:) integer, intent(in) :: size(:) character(len=*), intent(in) :: vecname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_matrix_rsp(A, size, matname, module, procedure) real(sp), intent(in) :: A(:, :) integer, intent(in) :: size(:) character(len=*), intent(in) :: matname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_vector_rdp(v, size, vecname, module, procedure) real(dp), intent(in) :: v(:) integer, intent(in) :: size(:) character(len=*), intent(in) :: vecname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_matrix_rdp(A, size, matname, module, procedure) real(dp), intent(in) :: A(:, :) integer, intent(in) :: size(:) character(len=*), intent(in) :: matname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_vector_csp(v, size, vecname, module, procedure) complex(sp), intent(in) :: v(:) integer, intent(in) :: size(:) character(len=*), intent(in) :: vecname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_matrix_csp(A, size, matname, module, procedure) complex(sp), intent(in) :: A(:, :) integer, intent(in) :: size(:) character(len=*), intent(in) :: matname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_vector_cdp(v, size, vecname, module, procedure) complex(dp), intent(in) :: v(:) integer, intent(in) :: size(:) character(len=*), intent(in) :: vecname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine module subroutine assert_shape_matrix_cdp(A, size, matname, module, procedure) complex(dp), intent(in) :: A(:, :) integer, intent(in) :: size(:) character(len=*), intent(in) :: matname character(len=*), intent(in) :: module character(len=*), intent(in) :: procedure end subroutine end interface interface log2 !! Utility function to compute the base-2 logarithm of a real number. elemental real(sp) module function log2_rsp(x) result(y) real(sp), intent(in) :: x end function elemental real(dp) module function log2_rdp(x) result(y) real(dp), intent(in) :: x end function end interface interface eig !! Computes the eigenvalue decomposition of a general square matrix. !! !! ### Description !! !! This interface provides methods to compute the solution to the eigenproblem !! \( \mathbf{Ax} = \lambda \mathbf{x} \), where $\mathbf{A}$ is a square `real` !! or `complex` matrix. !! !! Result array `lambda` returns the eigenvalues of \( \mathbf{A} \), while `vecs` !! returns the corresponding eigenvectors. Note that it follows the LAPACK convention !! when \( \mathbf{A} \) is `real`. The solver is based on LAPACK's `*GEEV` backends. !! !! ### Syntax !! !! `call eig(A, vecs, lambda)` !! !! ### Arguments !! !! `A`: `real` or `complex` square array containing the coefficient matrix. It is an `intent(in)` argument. !! !! `vecs`: Square array of the same size, type, and kind as `A` containing the eigenvectors !! (following LAPACK's convention for `real` matrices). It is an `intent(out)` argument. !! !! `lambda`: `complex` rank-1 array of the same kind as `A` containing the eigenvalues. !! It is an `intent(out)` argument. !! !! @note !! Due to the abstrct nature of the vector types defined in `LightKrylov`, it is unlikely !! that this implementation will be superseeded in favor of the `stdlib` one as the latter !! does not follow the LAPACK's convention. !! @endnote module subroutine eig_rsp(A, vecs, vals) real(sp), intent(in) :: A(:, :) real(sp), intent(out) :: vecs(:, :) complex(sp), intent(out) :: vals(:) end subroutine module subroutine eig_rdp(A, vecs, vals) real(dp), intent(in) :: A(:, :) real(dp), intent(out) :: vecs(:, :) complex(dp), intent(out) :: vals(:) end subroutine module subroutine eig_csp(A, vecs, vals) complex(sp), intent(in) :: A(:, :) complex(sp), intent(out) :: vecs(:, :) complex(sp), intent(out) :: vals(:) end subroutine module subroutine eig_cdp(A, vecs, vals) complex(dp), intent(in) :: A(:, :) complex(dp), intent(out) :: vecs(:, :) complex(dp), intent(out) :: vals(:) end subroutine end interface interface ordschur !! Given the Schur factorization and basis of a matrix, reorders it to have the selected !! eigenvalues in the upper left block. !! !! ### Description !! !! This interface provides methods to re-order the Schur factorization of a `real` or !! `complex` square matrix. Note that, if \( \mathbf{A} \) is `real`, it returns the !! real Schur form. !! !! ### Syntax !! !! `call ordschur(T, Q, selected)` !! !! ### Arguments !! !! `T`: `real` or `complex` square array containing the Schur factorization of a matrix. !! On exit, it is overwritten with its re-ordered counterpart. It is an `intent(inout)` argument. !! !! `Q`: Two-dimensional square array of the same size, type and kind as `A`. It contains !! the original Schur basis on entry and the re-ordered one on exit. !! It is an `intent(inout)` argument. !! !! `selected`: `logical` rank-1 array selecting which eigenvalues need to be moved in the !! upper left block of the Schur factorization. !! It is an `intent(in)` arguement. module subroutine ordschur_rsp(T, Q, selected) real(sp), intent(inout) :: T(:, :) real(sp), intent(inout) :: Q(:, :) logical, intent(in) :: selected(:) end subroutine module subroutine ordschur_rdp(T, Q, selected) real(dp), intent(inout) :: T(:, :) real(dp), intent(inout) :: Q(:, :) logical, intent(in) :: selected(:) end subroutine module subroutine ordschur_csp(T, Q, selected) complex(sp), intent(inout) :: T(:, :) complex(sp), intent(inout) :: Q(:, :) logical, intent(in) :: selected(:) end subroutine module subroutine ordschur_cdp(T, Q, selected) complex(dp), intent(inout) :: T(:, :) complex(dp), intent(inout) :: Q(:, :) logical, intent(in) :: selected(:) end subroutine end interface interface sqrtm !! Computes the non-negative square root of a symmetric positive definite matrix !! using its singular value decomposition. !! !! ### Description !! !! This interface provides methods to compute the non-negative square root of a symmetric !! (hermitian) positive definite matrix \( \mathbf{A} \). !! !! ### Syntax !! !! `call sqrtm(A, sqrtmA, info)` !! !! ### Arguments !! !! `A`: Symmetric (hermitian) positive definite matrix whose non-negative square root !! needs to be computed. It is an `intent(in)` argument. !! !! `sqrtmA`: Non-negative square root of `A`. It has the same size, kind and type as `A`. !! It is an `intent(out)` argument. !! !! `info`: Information flag. It is an `intent(out)` argument. module subroutine sqrtm_rsp(A, sqrtA, info) real(sp), intent(inout) :: A(:, :) real(sp), intent(out) :: sqrtA(:, :) integer, intent(out) :: info end subroutine module subroutine sqrtm_rdp(A, sqrtA, info) real(dp), intent(inout) :: A(:, :) real(dp), intent(out) :: sqrtA(:, :) integer, intent(out) :: info end subroutine module subroutine sqrtm_csp(A, sqrtA, info) complex(sp), intent(inout) :: A(:, :) complex(sp), intent(out) :: sqrtA(:, :) integer, intent(out) :: info end subroutine module subroutine sqrtm_cdp(A, sqrtA, info) complex(dp), intent(inout) :: A(:, :) complex(dp), intent(out) :: sqrtA(:, :) integer, intent(out) :: info end subroutine end interface interface expm !! ### Description !! !! Evaluate the exponential of a dense matrix using Pade approximations. !! !! ### Syntax !! !! ```fortran !! E = expm(A, order) !! ``` !! !! ### Arguments !! !! `E` : `real` or `complex` rank-2 array with \( E = \exp(A) \). !! !! `A` : `real` or `complex` matrix that needs to be exponentiated. !! !! `order` (optional) : Order of the Pade approximation. By default `order = 10`. module function expm_rsp(A, order) result(E) real(sp), intent(in) :: A(:, :) !! Matrix to be exponentiated. real(sp) :: E(size(A, 1), size(A, 1)) !! Output matrix E = exp(tA). integer, intent(in), optional :: order !! Order of the Pade approximation. end function module function expm_rdp(A, order) result(E) real(dp), intent(in) :: A(:, :) !! Matrix to be exponentiated. real(dp) :: E(size(A, 1), size(A, 1)) !! Output matrix E = exp(tA). integer, intent(in), optional :: order !! Order of the Pade approximation. end function module function expm_csp(A, order) result(E) complex(sp), intent(in) :: A(:, :) !! Matrix to be exponentiated. complex(sp) :: E(size(A, 1), size(A, 1)) !! Output matrix E = exp(tA). integer, intent(in), optional :: order !! Order of the Pade approximation. end function module function expm_cdp(A, order) result(E) complex(dp), intent(in) :: A(:, :) !! Matrix to be exponentiated. complex(dp) :: E(size(A, 1), size(A, 1)) !! Output matrix E = exp(tA). integer, intent(in), optional :: order !! Order of the Pade approximation. end function end interface interface givens_rotation pure module function givens_rotation_rsp(x) result(g) real(sp), intent(in) :: x(2) !! Vector whose second needs to be eliminated. real(sp) :: g(2) !! Entries of the Givens rotation matrix. end function pure module function givens_rotation_rdp(x) result(g) real(dp), intent(in) :: x(2) !! Vector whose second needs to be eliminated. real(dp) :: g(2) !! Entries of the Givens rotation matrix. end function pure module function givens_rotation_csp(x) result(g) complex(sp), intent(in) :: x(2) !! Vector whose second needs to be eliminated. complex(sp) :: g(2) !! Entries of the Givens rotation matrix. end function pure module function givens_rotation_cdp(x) result(g) complex(dp), intent(in) :: x(2) !! Vector whose second needs to be eliminated. complex(dp) :: g(2) !! Entries of the Givens rotation matrix. end function end interface interface apply_givens_rotation pure module subroutine apply_givens_rotation_rsp(h, c, s) real(sp), intent(inout) :: h(:) !! k-th column of the Hessenberg matrix. real(sp), intent(inout) :: c(:) !! Cosine components of the Givens rotations. real(sp), intent(inout) :: s(:) !! Sine components of the Givens rotations. end subroutine pure module subroutine apply_givens_rotation_rdp(h, c, s) real(dp), intent(inout) :: h(:) !! k-th column of the Hessenberg matrix. real(dp), intent(inout) :: c(:) !! Cosine components of the Givens rotations. real(dp), intent(inout) :: s(:) !! Sine components of the Givens rotations. end subroutine pure module subroutine apply_givens_rotation_csp(h, c, s) complex(sp), intent(inout) :: h(:) !! k-th column of the Hessenberg matrix. complex(sp), intent(inout) :: c(:) !! Cosine components of the Givens rotations. complex(sp), intent(inout) :: s(:) !! Sine components of the Givens rotations. end subroutine pure module subroutine apply_givens_rotation_cdp(h, c, s) complex(dp), intent(inout) :: h(:) !! k-th column of the Hessenberg matrix. complex(dp), intent(inout) :: c(:) !! Cosine components of the Givens rotations. complex(dp), intent(inout) :: s(:) !! Sine components of the Givens rotations. end subroutine end interface interface solve_triangular pure module function solve_triangular_rsp(A, b) result(x) real(sp), intent(in) :: A(:, :) !! Matrix to invert. real(sp), intent(in) :: b(:) !! Right-hand side vector. real(sp), allocatable :: x(:) !! Solution vector. end function pure module function solve_triangular_rdp(A, b) result(x) real(dp), intent(in) :: A(:, :) !! Matrix to invert. real(dp), intent(in) :: b(:) !! Right-hand side vector. real(dp), allocatable :: x(:) !! Solution vector. end function pure module function solve_triangular_csp(A, b) result(x) complex(sp), intent(in) :: A(:, :) !! Matrix to invert. complex(sp), intent(in) :: b(:) !! Right-hand side vector. complex(sp), allocatable :: x(:) !! Solution vector. end function pure module function solve_triangular_cdp(A, b) result(x) complex(dp), intent(in) :: A(:, :) !! Matrix to invert. complex(dp), intent(in) :: b(:) !! Right-hand side vector. complex(dp), allocatable :: x(:) !! Solution vector. end function end interface end module