submodule (lightkrylov_basekrylov) krylov_utilities implicit none(type, external) contains !---------------------------------------- !----- Permutation matrices ----- !---------------------------------------- module procedure permcols_basis_rsp call copy(Q, Q(perm)) end procedure permcols_basis_rsp module procedure permcols_array_rsp Q = Q(:, perm) end procedure permcols_array_rsp module procedure permcols_basis_rdp call copy(Q, Q(perm)) end procedure permcols_basis_rdp module procedure permcols_array_rdp Q = Q(:, perm) end procedure permcols_array_rdp module procedure permcols_basis_csp call copy(Q, Q(perm)) end procedure permcols_basis_csp module procedure permcols_array_csp Q = Q(:, perm) end procedure permcols_array_csp module procedure permcols_basis_cdp call copy(Q, Q(perm)) end procedure permcols_basis_cdp module procedure permcols_array_cdp Q = Q(:, perm) end procedure permcols_array_cdp module procedure invperm integer :: i, iostat character(len=100) :: errmsg allocate(inv_perm(size(perm)), source=0, stat=iostat, errmsg=errmsg) call check_allocation(iostat, errmsg, this_module, "invperm") inv_perm(perm) = [(i, i=1, size(perm))] end procedure invperm !---------------------------------------------- !----- Initialize Krylov subspace ----- !---------------------------------------------- module procedure initialize_krylov_subspace_rsp integer :: p ! Zero-out X. call zero_basis(X) ! Deals with optional args. if(present(X0)) then p = size(X0) ! Initialize. call copy(X(:p), X0) ! Orthonormalize. call orthonormalize_basis(X(:p)) endif end procedure initialize_krylov_subspace_rsp module procedure initialize_krylov_subspace_rdp integer :: p ! Zero-out X. call zero_basis(X) ! Deals with optional args. if(present(X0)) then p = size(X0) ! Initialize. call copy(X(:p), X0) ! Orthonormalize. call orthonormalize_basis(X(:p)) endif end procedure initialize_krylov_subspace_rdp module procedure initialize_krylov_subspace_csp integer :: p ! Zero-out X. call zero_basis(X) ! Deals with optional args. if(present(X0)) then p = size(X0) ! Initialize. call copy(X(:p), X0) ! Orthonormalize. call orthonormalize_basis(X(:p)) endif end procedure initialize_krylov_subspace_csp module procedure initialize_krylov_subspace_cdp integer :: p ! Zero-out X. call zero_basis(X) ! Deals with optional args. if(present(X0)) then p = size(X0) ! Initialize. call copy(X(:p), X0) ! Orthonormalize. call orthonormalize_basis(X(:p)) endif end procedure initialize_krylov_subspace_cdp !------------------------------------------------------- !----- Initialize random orthonormal basis ----- !------------------------------------------------------- module procedure initialize_random_orthonormal_basis_rsp integer :: p ! Fill with random data call rand_basis(X) ! Orthonormalize call orthonormalize_basis(X) end procedure initialize_random_orthonormal_basis_rsp module procedure initialize_random_orthonormal_basis_rdp integer :: p ! Fill with random data call rand_basis(X) ! Orthonormalize call orthonormalize_basis(X) end procedure initialize_random_orthonormal_basis_rdp module procedure initialize_random_orthonormal_basis_csp integer :: p ! Fill with random data call rand_basis(X) ! Orthonormalize call orthonormalize_basis(X) end procedure initialize_random_orthonormal_basis_csp module procedure initialize_random_orthonormal_basis_cdp integer :: p ! Fill with random data call rand_basis(X) ! Orthonormalize call orthonormalize_basis(X) end procedure initialize_random_orthonormal_basis_cdp !---------------------------------------- !----- Orthonormalize basis ----- !---------------------------------------- module procedure orthonormalize_basis_rsp character(len=*), parameter :: this_procedure = 'orthonormalize_basis_rsp' real(sp) :: R(size(X),size(X)) integer :: info if (time_lightkrylov()) call timer%start(this_procedure) ! internals call qr(X, R, info) call check_info(info, 'qr', this_module, this_procedure) if (time_lightkrylov()) call timer%stop(this_procedure) end procedure orthonormalize_basis_rsp module procedure orthonormalize_basis_rdp character(len=*), parameter :: this_procedure = 'orthonormalize_basis_rdp' real(dp) :: R(size(X),size(X)) integer :: info if (time_lightkrylov()) call timer%start(this_procedure) ! internals call qr(X, R, info) call check_info(info, 'qr', this_module, this_procedure) if (time_lightkrylov()) call timer%stop(this_procedure) end procedure orthonormalize_basis_rdp module procedure orthonormalize_basis_csp character(len=*), parameter :: this_procedure = 'orthonormalize_basis_csp' complex(sp) :: R(size(X),size(X)) integer :: info if (time_lightkrylov()) call timer%start(this_procedure) ! internals call qr(X, R, info) call check_info(info, 'qr', this_module, this_procedure) if (time_lightkrylov()) call timer%stop(this_procedure) end procedure orthonormalize_basis_csp module procedure orthonormalize_basis_cdp character(len=*), parameter :: this_procedure = 'orthonormalize_basis_cdp' complex(dp) :: R(size(X),size(X)) integer :: info if (time_lightkrylov()) call timer%start(this_procedure) ! internals call qr(X, R, info) call check_info(info, 'qr', this_module, this_procedure) if (time_lightkrylov()) call timer%stop(this_procedure) end procedure orthonormalize_basis_cdp !--------------------------------------------------- !----- Check orthonormality of a basis ----- !--------------------------------------------------- module procedure is_orthonormal_rsp real(sp), dimension(size(X), size(X)) :: G ortho = .true. G = Gram(X) if (mnorm(G - eye(size(X)), "Fro") > rtol_sp) then ! The basis is not orthonormal. ortho = .false. end if end procedure is_orthonormal_rsp module procedure is_orthonormal_rdp real(dp), dimension(size(X), size(X)) :: G ortho = .true. G = Gram(X) if (mnorm(G - eye(size(X)), "Fro") > rtol_sp) then ! The basis is not orthonormal. ortho = .false. end if end procedure is_orthonormal_rdp module procedure is_orthonormal_csp complex(sp), dimension(size(X), size(X)) :: G ortho = .true. G = Gram(X) if (mnorm(G - eye(size(X)), "Fro") > rtol_sp) then ! The basis is not orthonormal. ortho = .false. end if end procedure is_orthonormal_csp module procedure is_orthonormal_cdp complex(dp), dimension(size(X), size(X)) :: G ortho = .true. G = Gram(X) if (mnorm(G - eye(size(X)), "Fro") > rtol_sp) then ! The basis is not orthonormal. ortho = .false. end if end procedure is_orthonormal_cdp !---------------------------------------------- !----- Biorthonormalize two bases ----- !---------------------------------------------- module procedure biorthonormalize_bases_rsp character(len=*), parameter :: this_procedure = 'biorthonormalize_bases_rsp' !! SVD workspace integer :: n, info_, nretain real(sp), allocatable :: M(:,:), U(:,:), VT(:,:) real(sp), allocatable :: S(:) real(sp) :: tol_ if (time_lightkrylov()) call timer%start(this_procedure) ! Check sizes. if (size(X) /= size(Y)) then call stop_error("Krylov bases X and Y have different sizes.", & & this_module, this_procedure) endif ! handle optional tol tol_ = optval(tol, atol_sp) n = size(X) ! compute SVD of inner product matrix M = innerprod(Y, X) allocate(S(n), U(n, n), VT(n, n)) call svd(M, S, U, VT) ! count + renormalize retained singular values; zero the rest nretain = count(S / S(1) > tol_) call check_info(merge(-1, 0, nretain == 0), 'biorthonormalize_bases', & & this_module, this_procedure) S(:nretain) = one_rsp / sqrt(S(:nretain)) S(nretain+1:) = zero_rsp ! apply symmetric transformation in-place block class(abstract_vector_rsp), allocatable :: Xwrk(:) call linear_combination(Xwrk, X, matmul(transpose(VT(:nretain, :)), diag(S(:nretain)))) call copy(X(:nretain), Xwrk) call zero_basis(X(nretain+1:)) call linear_combination(Xwrk, Y, matmul(U(:, :nretain), diag(S(:nretain)))) call copy(Y(:nretain), Xwrk) call zero_basis(Y(nretain+1:)) end block if (present(info)) info = nretain if (time_lightkrylov()) call timer%stop(this_procedure) end procedure biorthonormalize_bases_rsp module procedure biorthonormalize_bases_rdp character(len=*), parameter :: this_procedure = 'biorthonormalize_bases_rdp' !! SVD workspace integer :: n, info_, nretain real(dp), allocatable :: M(:,:), U(:,:), VT(:,:) real(dp), allocatable :: S(:) real(dp) :: tol_ if (time_lightkrylov()) call timer%start(this_procedure) ! Check sizes. if (size(X) /= size(Y)) then call stop_error("Krylov bases X and Y have different sizes.", & & this_module, this_procedure) endif ! handle optional tol tol_ = optval(tol, atol_dp) n = size(X) ! compute SVD of inner product matrix M = innerprod(Y, X) allocate(S(n), U(n, n), VT(n, n)) call svd(M, S, U, VT) ! count + renormalize retained singular values; zero the rest nretain = count(S / S(1) > tol_) call check_info(merge(-1, 0, nretain == 0), 'biorthonormalize_bases', & & this_module, this_procedure) S(:nretain) = one_rdp / sqrt(S(:nretain)) S(nretain+1:) = zero_rdp ! apply symmetric transformation in-place block class(abstract_vector_rdp), allocatable :: Xwrk(:) call linear_combination(Xwrk, X, matmul(transpose(VT(:nretain, :)), diag(S(:nretain)))) call copy(X(:nretain), Xwrk) call zero_basis(X(nretain+1:)) call linear_combination(Xwrk, Y, matmul(U(:, :nretain), diag(S(:nretain)))) call copy(Y(:nretain), Xwrk) call zero_basis(Y(nretain+1:)) end block if (present(info)) info = nretain if (time_lightkrylov()) call timer%stop(this_procedure) end procedure biorthonormalize_bases_rdp module procedure biorthonormalize_bases_csp character(len=*), parameter :: this_procedure = 'biorthonormalize_bases_csp' !! SVD workspace integer :: n, info_, nretain complex(sp), allocatable :: M(:,:), U(:,:), VT(:,:) real(sp), allocatable :: S(:) real(sp) :: tol_ if (time_lightkrylov()) call timer%start(this_procedure) ! Check sizes. if (size(X) /= size(Y)) then call stop_error("Krylov bases X and Y have different sizes.", & & this_module, this_procedure) endif ! handle optional tol tol_ = optval(tol, atol_sp) n = size(X) ! compute SVD of inner product matrix M = innerprod(Y, X) allocate(S(n), U(n, n), VT(n, n)) call svd(M, S, U, VT) ! count + renormalize retained singular values; zero the rest nretain = count(S / S(1) > tol_) call check_info(merge(-1, 0, nretain == 0), 'biorthonormalize_bases', & & this_module, this_procedure) S(:nretain) = one_rsp / sqrt(S(:nretain)) S(nretain+1:) = zero_rsp ! apply symmetric transformation in-place block class(abstract_vector_csp), allocatable :: Xwrk(:) call linear_combination(Xwrk, X, matmul(hermitian(VT(:nretain, :)), diag(S(:nretain)))) call copy(X(:nretain), Xwrk) call zero_basis(X(nretain+1:)) call linear_combination(Xwrk, Y, matmul(U(:, :nretain), diag(S(:nretain)))) call copy(Y(:nretain), Xwrk) call zero_basis(Y(nretain+1:)) end block if (present(info)) info = nretain if (time_lightkrylov()) call timer%stop(this_procedure) end procedure biorthonormalize_bases_csp module procedure biorthonormalize_bases_cdp character(len=*), parameter :: this_procedure = 'biorthonormalize_bases_cdp' !! SVD workspace integer :: n, info_, nretain complex(dp), allocatable :: M(:,:), U(:,:), VT(:,:) real(dp), allocatable :: S(:) real(dp) :: tol_ if (time_lightkrylov()) call timer%start(this_procedure) ! Check sizes. if (size(X) /= size(Y)) then call stop_error("Krylov bases X and Y have different sizes.", & & this_module, this_procedure) endif ! handle optional tol tol_ = optval(tol, atol_dp) n = size(X) ! compute SVD of inner product matrix M = innerprod(Y, X) allocate(S(n), U(n, n), VT(n, n)) call svd(M, S, U, VT) ! count + renormalize retained singular values; zero the rest nretain = count(S / S(1) > tol_) call check_info(merge(-1, 0, nretain == 0), 'biorthonormalize_bases', & & this_module, this_procedure) S(:nretain) = one_rdp / sqrt(S(:nretain)) S(nretain+1:) = zero_rdp ! apply symmetric transformation in-place block class(abstract_vector_cdp), allocatable :: Xwrk(:) call linear_combination(Xwrk, X, matmul(hermitian(VT(:nretain, :)), diag(S(:nretain)))) call copy(X(:nretain), Xwrk) call zero_basis(X(nretain+1:)) call linear_combination(Xwrk, Y, matmul(U(:, :nretain), diag(S(:nretain)))) call copy(Y(:nretain), Xwrk) call zero_basis(Y(nretain+1:)) end block if (present(info)) info = nretain if (time_lightkrylov()) call timer%stop(this_procedure) end procedure biorthonormalize_bases_cdp end submodule krylov_utilities