#:include "common.fypp" submodule(stdlib_lapack_eig_svd_lsq) stdlib_lapack_eigv_tridiag implicit none contains #:for ik,it,ii in LINALG_INT_KINDS_TYPES pure module subroutine stdlib${ii}$_slaebz( ijob, nitmax, n, mmax, minp, nbmin, abstol,reltol, pivmin, d, & !! SLAEBZ contains the iteration loops which compute and use the !! function N(w), which is the count of eigenvalues of a symmetric !! tridiagonal matrix T less than or equal to its argument w. It !! performs a choice of two types of loops: !! IJOB=1, followed by !! IJOB=2: It takes as input a list of intervals and returns a list of !! sufficiently small intervals whose union contains the same !! eigenvalues as the union of the original intervals. !! The input intervals are (AB(j,1),AB(j,2)], j=1,...,MINP. !! The output interval (AB(j,1),AB(j,2)] will contain !! eigenvalues NAB(j,1)+1,...,NAB(j,2), where 1 <= j <= MOUT. !! IJOB=3: It performs a binary search in each input interval !! (AB(j,1),AB(j,2)] for a point w(j) such that !! N(w(j))=NVAL(j), and uses C(j) as the starting point of !! the search. If such a w(j) is found, then on output !! AB(j,1)=AB(j,2)=w. If no such w(j) is found, then on output !! (AB(j,1),AB(j,2)] will be a small interval containing the !! point where N(w) jumps through NVAL(j), unless that point !! lies outside the initial interval. !! Note that the intervals are in all cases half-open intervals, !! i.e., of the form (a,b] , which includes b but not a . !! To avoid underflow, the matrix should be scaled so that its largest !! element is no greater than overflow**(1/2) * underflow**(1/4) !! in absolute value. To assure the most accurate computation !! of small eigenvalues, the matrix should be scaled to be !! not much smaller than that, either. !! See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal !! Matrix", Report CS41, Computer Science Dept., Stanford !! University, July 21, 1966 !! Note: the arguments are, in general, *not* checked for unreasonable !! values. e, e2, nval, ab, c, mout,nab, work, iwork, info ) ! -- lapack auxiliary routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: ijob, minp, mmax, n, nbmin, nitmax integer(${ik}$), intent(out) :: info, mout real(sp), intent(in) :: abstol, pivmin, reltol ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) integer(${ik}$), intent(inout) :: nab(mmax,*), nval(*) real(sp), intent(inout) :: ab(mmax,*), c(*) real(sp), intent(in) :: d(*), e(*), e2(*) real(sp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: itmp1, itmp2, j, ji, jit, jp, kf, kfnew, kl, klnew real(sp) :: tmp1, tmp2 ! Intrinsic Functions ! Executable Statements ! check for errors info = 0_${ik}$ if( ijob<1_${ik}$ .or. ijob>3_${ik}$ ) then info = -1_${ik}$ return end if ! initialize nab if( ijob==1_${ik}$ ) then ! compute the number of eigenvalues in the initial intervals. mout = 0_${ik}$ do ji = 1, minp do jp = 1, 2 tmp1 = d( 1_${ik}$ ) - ab( ji, jp ) if( abs( tmp1 )<pivmin )tmp1 = -pivmin nab( ji, jp ) = 0_${ik}$ if( tmp1<=zero )nab( ji, jp ) = 1_${ik}$ do j = 2, n tmp1 = d( j ) - e2( j-1 ) / tmp1 - ab( ji, jp ) if( abs( tmp1 )<pivmin )tmp1 = -pivmin if( tmp1<=zero )nab( ji, jp ) = nab( ji, jp ) + 1_${ik}$ end do end do mout = mout + nab( ji, 2_${ik}$ ) - nab( ji, 1_${ik}$ ) end do return end if ! initialize for loop ! kf and kl have the following meaning: ! intervals 1,...,kf-1 have converged. ! intervals kf,...,kl still need to be refined. kf = 1_${ik}$ kl = minp ! if ijob=2, initialize c. ! if ijob=3, use the user-supplied starting point. if( ijob==2_${ik}$ ) then do ji = 1, minp c( ji ) = half*( ab( ji, 1_${ik}$ )+ab( ji, 2_${ik}$ ) ) end do end if ! iteration loop loop_130: do jit = 1, nitmax ! loop over intervals if( kl-kf+1>=nbmin .and. nbmin>0_${ik}$ ) then ! begin of parallel version of the loop do ji = kf, kl ! compute n(c), the number of eigenvalues less than c work( ji ) = d( 1_${ik}$ ) - c( ji ) iwork( ji ) = 0_${ik}$ if( work( ji )<=pivmin ) then iwork( ji ) = 1_${ik}$ work( ji ) = min( work( ji ), -pivmin ) end if do j = 2, n work( ji ) = d( j ) - e2( j-1 ) / work( ji ) - c( ji ) if( work( ji )<=pivmin ) then iwork( ji ) = iwork( ji ) + 1_${ik}$ work( ji ) = min( work( ji ), -pivmin ) end if end do end do if( ijob<=2_${ik}$ ) then ! ijob=2: choose all intervals containing eigenvalues. klnew = kl loop_70: do ji = kf, kl ! insure that n(w) is monotone iwork( ji ) = min( nab( ji, 2_${ik}$ ),max( nab( ji, 1_${ik}$ ), iwork( ji ) ) ) ! update the queue -- add intervals if both halves ! contain eigenvalues. if( iwork( ji )==nab( ji, 2_${ik}$ ) ) then ! no eigenvalue in the upper interval: ! just use the lower interval. ab( ji, 2_${ik}$ ) = c( ji ) else if( iwork( ji )==nab( ji, 1_${ik}$ ) ) then ! no eigenvalue in the lower interval: ! just use the upper interval. ab( ji, 1_${ik}$ ) = c( ji ) else klnew = klnew + 1_${ik}$ if( klnew<=mmax ) then ! eigenvalue in both intervals -- add upper to ! queue. ab( klnew, 2_${ik}$ ) = ab( ji, 2_${ik}$ ) nab( klnew, 2_${ik}$ ) = nab( ji, 2_${ik}$ ) ab( klnew, 1_${ik}$ ) = c( ji ) nab( klnew, 1_${ik}$ ) = iwork( ji ) ab( ji, 2_${ik}$ ) = c( ji ) nab( ji, 2_${ik}$ ) = iwork( ji ) else info = mmax + 1_${ik}$ end if end if end do loop_70 if( info/=0 )return kl = klnew else ! ijob=3: binary search. keep only the interval containing ! w s.t. n(w) = nval do ji = kf, kl if( iwork( ji )<=nval( ji ) ) then ab( ji, 1_${ik}$ ) = c( ji ) nab( ji, 1_${ik}$ ) = iwork( ji ) end if if( iwork( ji )>=nval( ji ) ) then ab( ji, 2_${ik}$ ) = c( ji ) nab( ji, 2_${ik}$ ) = iwork( ji ) end if end do end if else ! end of parallel version of the loop ! begin of serial version of the loop klnew = kl loop_100: do ji = kf, kl ! compute n(w), the number of eigenvalues less than w tmp1 = c( ji ) tmp2 = d( 1_${ik}$ ) - tmp1 itmp1 = 0_${ik}$ if( tmp2<=pivmin ) then itmp1 = 1_${ik}$ tmp2 = min( tmp2, -pivmin ) end if do j = 2, n tmp2 = d( j ) - e2( j-1 ) / tmp2 - tmp1 if( tmp2<=pivmin ) then itmp1 = itmp1 + 1_${ik}$ tmp2 = min( tmp2, -pivmin ) end if end do if( ijob<=2_${ik}$ ) then ! ijob=2: choose all intervals containing eigenvalues. ! insure that n(w) is monotone itmp1 = min( nab( ji, 2_${ik}$ ),max( nab( ji, 1_${ik}$ ), itmp1 ) ) ! update the queue -- add intervals if both halves ! contain eigenvalues. if( itmp1==nab( ji, 2_${ik}$ ) ) then ! no eigenvalue in the upper interval: ! just use the lower interval. ab( ji, 2_${ik}$ ) = tmp1 else if( itmp1==nab( ji, 1_${ik}$ ) ) then ! no eigenvalue in the lower interval: ! just use the upper interval. ab( ji, 1_${ik}$ ) = tmp1 else if( klnew<mmax ) then ! eigenvalue in both intervals -- add upper to queue. klnew = klnew + 1_${ik}$ ab( klnew, 2_${ik}$ ) = ab( ji, 2_${ik}$ ) nab( klnew, 2_${ik}$ ) = nab( ji, 2_${ik}$ ) ab( klnew, 1_${ik}$ ) = tmp1 nab( klnew, 1_${ik}$ ) = itmp1 ab( ji, 2_${ik}$ ) = tmp1 nab( ji, 2_${ik}$ ) = itmp1 else info = mmax + 1_${ik}$ return end if else ! ijob=3: binary search. keep only the interval ! containing w s.t. n(w) = nval if( itmp1<=nval( ji ) ) then ab( ji, 1_${ik}$ ) = tmp1 nab( ji, 1_${ik}$ ) = itmp1 end if if( itmp1>=nval( ji ) ) then ab( ji, 2_${ik}$ ) = tmp1 nab( ji, 2_${ik}$ ) = itmp1 end if end if end do loop_100 kl = klnew end if ! check for convergence kfnew = kf loop_110: do ji = kf, kl tmp1 = abs( ab( ji, 2_${ik}$ )-ab( ji, 1_${ik}$ ) ) tmp2 = max( abs( ab( ji, 2_${ik}$ ) ), abs( ab( ji, 1_${ik}$ ) ) ) if( tmp1<max( abstol, pivmin, reltol*tmp2 ) .or.nab( ji, 1_${ik}$ )>=nab( ji, 2_${ik}$ ) ) & then ! converged -- swap with position kfnew, ! then increment kfnew if( ji>kfnew ) then tmp1 = ab( ji, 1_${ik}$ ) tmp2 = ab( ji, 2_${ik}$ ) itmp1 = nab( ji, 1_${ik}$ ) itmp2 = nab( ji, 2_${ik}$ ) ab( ji, 1_${ik}$ ) = ab( kfnew, 1_${ik}$ ) ab( ji, 2_${ik}$ ) = ab( kfnew, 2_${ik}$ ) nab( ji, 1_${ik}$ ) = nab( kfnew, 1_${ik}$ ) nab( ji, 2_${ik}$ ) = nab( kfnew, 2_${ik}$ ) ab( kfnew, 1_${ik}$ ) = tmp1 ab( kfnew, 2_${ik}$ ) = tmp2 nab( kfnew, 1_${ik}$ ) = itmp1 nab( kfnew, 2_${ik}$ ) = itmp2 if( ijob==3_${ik}$ ) then itmp1 = nval( ji ) nval( ji ) = nval( kfnew ) nval( kfnew ) = itmp1 end if end if kfnew = kfnew + 1_${ik}$ end if end do loop_110 kf = kfnew ! choose midpoints do ji = kf, kl c( ji ) = half*( ab( ji, 1_${ik}$ )+ab( ji, 2_${ik}$ ) ) end do ! if no more intervals to refine, quit. if( kf>kl )go to 140 end do loop_130 ! converged 140 continue info = max( kl+1-kf, 0_${ik}$ ) mout = kl return end subroutine stdlib${ii}$_slaebz pure module subroutine stdlib${ii}$_dlaebz( ijob, nitmax, n, mmax, minp, nbmin, abstol,reltol, pivmin, d, & !! DLAEBZ contains the iteration loops which compute and use the !! function N(w), which is the count of eigenvalues of a symmetric !! tridiagonal matrix T less than or equal to its argument w. It !! performs a choice of two types of loops: !! IJOB=1, followed by !! IJOB=2: It takes as input a list of intervals and returns a list of !! sufficiently small intervals whose union contains the same !! eigenvalues as the union of the original intervals. !! The input intervals are (AB(j,1),AB(j,2)], j=1,...,MINP. !! The output interval (AB(j,1),AB(j,2)] will contain !! eigenvalues NAB(j,1)+1,...,NAB(j,2), where 1 <= j <= MOUT. !! IJOB=3: It performs a binary search in each input interval !! (AB(j,1),AB(j,2)] for a point w(j) such that !! N(w(j))=NVAL(j), and uses C(j) as the starting point of !! the search. If such a w(j) is found, then on output !! AB(j,1)=AB(j,2)=w. If no such w(j) is found, then on output !! (AB(j,1),AB(j,2)] will be a small interval containing the !! point where N(w) jumps through NVAL(j), unless that point !! lies outside the initial interval. !! Note that the intervals are in all cases half-open intervals, !! i.e., of the form (a,b] , which includes b but not a . !! To avoid underflow, the matrix should be scaled so that its largest !! element is no greater than overflow**(1/2) * underflow**(1/4) !! in absolute value. To assure the most accurate computation !! of small eigenvalues, the matrix should be scaled to be !! not much smaller than that, either. !! See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal !! Matrix", Report CS41, Computer Science Dept., Stanford !! University, July 21, 1966 !! Note: the arguments are, in general, *not* checked for unreasonable !! values. e, e2, nval, ab, c, mout,nab, work, iwork, info ) ! -- lapack auxiliary routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: ijob, minp, mmax, n, nbmin, nitmax integer(${ik}$), intent(out) :: info, mout real(dp), intent(in) :: abstol, pivmin, reltol ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) integer(${ik}$), intent(inout) :: nab(mmax,*), nval(*) real(dp), intent(inout) :: ab(mmax,*), c(*) real(dp), intent(in) :: d(*), e(*), e2(*) real(dp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: itmp1, itmp2, j, ji, jit, jp, kf, kfnew, kl, klnew real(dp) :: tmp1, tmp2 ! Intrinsic Functions ! Executable Statements ! check for errors info = 0_${ik}$ if( ijob<1_${ik}$ .or. ijob>3_${ik}$ ) then info = -1_${ik}$ return end if ! initialize nab if( ijob==1_${ik}$ ) then ! compute the number of eigenvalues in the initial intervals. mout = 0_${ik}$ do ji = 1, minp do jp = 1, 2 tmp1 = d( 1_${ik}$ ) - ab( ji, jp ) if( abs( tmp1 )<pivmin )tmp1 = -pivmin nab( ji, jp ) = 0_${ik}$ if( tmp1<=zero )nab( ji, jp ) = 1_${ik}$ do j = 2, n tmp1 = d( j ) - e2( j-1 ) / tmp1 - ab( ji, jp ) if( abs( tmp1 )<pivmin )tmp1 = -pivmin if( tmp1<=zero )nab( ji, jp ) = nab( ji, jp ) + 1_${ik}$ end do end do mout = mout + nab( ji, 2_${ik}$ ) - nab( ji, 1_${ik}$ ) end do return end if ! initialize for loop ! kf and kl have the following meaning: ! intervals 1,...,kf-1 have converged. ! intervals kf,...,kl still need to be refined. kf = 1_${ik}$ kl = minp ! if ijob=2, initialize c. ! if ijob=3, use the user-supplied starting point. if( ijob==2_${ik}$ ) then do ji = 1, minp c( ji ) = half*( ab( ji, 1_${ik}$ )+ab( ji, 2_${ik}$ ) ) end do end if ! iteration loop loop_130: do jit = 1, nitmax ! loop over intervals if( kl-kf+1>=nbmin .and. nbmin>0_${ik}$ ) then ! begin of parallel version of the loop do ji = kf, kl ! compute n(c), the number of eigenvalues less than c work( ji ) = d( 1_${ik}$ ) - c( ji ) iwork( ji ) = 0_${ik}$ if( work( ji )<=pivmin ) then iwork( ji ) = 1_${ik}$ work( ji ) = min( work( ji ), -pivmin ) end if do j = 2, n work( ji ) = d( j ) - e2( j-1 ) / work( ji ) - c( ji ) if( work( ji )<=pivmin ) then iwork( ji ) = iwork( ji ) + 1_${ik}$ work( ji ) = min( work( ji ), -pivmin ) end if end do end do if( ijob<=2_${ik}$ ) then ! ijob=2: choose all intervals containing eigenvalues. klnew = kl loop_70: do ji = kf, kl ! insure that n(w) is monotone iwork( ji ) = min( nab( ji, 2_${ik}$ ),max( nab( ji, 1_${ik}$ ), iwork( ji ) ) ) ! update the queue -- add intervals if both halves ! contain eigenvalues. if( iwork( ji )==nab( ji, 2_${ik}$ ) ) then ! no eigenvalue in the upper interval: ! just use the lower interval. ab( ji, 2_${ik}$ ) = c( ji ) else if( iwork( ji )==nab( ji, 1_${ik}$ ) ) then ! no eigenvalue in the lower interval: ! just use the upper interval. ab( ji, 1_${ik}$ ) = c( ji ) else klnew = klnew + 1_${ik}$ if( klnew<=mmax ) then ! eigenvalue in both intervals -- add upper to ! queue. ab( klnew, 2_${ik}$ ) = ab( ji, 2_${ik}$ ) nab( klnew, 2_${ik}$ ) = nab( ji, 2_${ik}$ ) ab( klnew, 1_${ik}$ ) = c( ji ) nab( klnew, 1_${ik}$ ) = iwork( ji ) ab( ji, 2_${ik}$ ) = c( ji ) nab( ji, 2_${ik}$ ) = iwork( ji ) else info = mmax + 1_${ik}$ end if end if end do loop_70 if( info/=0 )return kl = klnew else ! ijob=3: binary search. keep only the interval containing ! w s.t. n(w) = nval do ji = kf, kl if( iwork( ji )<=nval( ji ) ) then ab( ji, 1_${ik}$ ) = c( ji ) nab( ji, 1_${ik}$ ) = iwork( ji ) end if if( iwork( ji )>=nval( ji ) ) then ab( ji, 2_${ik}$ ) = c( ji ) nab( ji, 2_${ik}$ ) = iwork( ji ) end if end do end if else ! end of parallel version of the loop ! begin of serial version of the loop klnew = kl loop_100: do ji = kf, kl ! compute n(w), the number of eigenvalues less than w tmp1 = c( ji ) tmp2 = d( 1_${ik}$ ) - tmp1 itmp1 = 0_${ik}$ if( tmp2<=pivmin ) then itmp1 = 1_${ik}$ tmp2 = min( tmp2, -pivmin ) end if do j = 2, n tmp2 = d( j ) - e2( j-1 ) / tmp2 - tmp1 if( tmp2<=pivmin ) then itmp1 = itmp1 + 1_${ik}$ tmp2 = min( tmp2, -pivmin ) end if end do if( ijob<=2_${ik}$ ) then ! ijob=2: choose all intervals containing eigenvalues. ! insure that n(w) is monotone itmp1 = min( nab( ji, 2_${ik}$ ),max( nab( ji, 1_${ik}$ ), itmp1 ) ) ! update the queue -- add intervals if both halves ! contain eigenvalues. if( itmp1==nab( ji, 2_${ik}$ ) ) then ! no eigenvalue in the upper interval: ! just use the lower interval. ab( ji, 2_${ik}$ ) = tmp1 else if( itmp1==nab( ji, 1_${ik}$ ) ) then ! no eigenvalue in the lower interval: ! just use the upper interval. ab( ji, 1_${ik}$ ) = tmp1 else if( klnew<mmax ) then ! eigenvalue in both intervals -- add upper to queue. klnew = klnew + 1_${ik}$ ab( klnew, 2_${ik}$ ) = ab( ji, 2_${ik}$ ) nab( klnew, 2_${ik}$ ) = nab( ji, 2_${ik}$ ) ab( klnew, 1_${ik}$ ) = tmp1 nab( klnew, 1_${ik}$ ) = itmp1 ab( ji, 2_${ik}$ ) = tmp1 nab( ji, 2_${ik}$ ) = itmp1 else info = mmax + 1_${ik}$ return end if else ! ijob=3: binary search. keep only the interval ! containing w s.t. n(w) = nval if( itmp1<=nval( ji ) ) then ab( ji, 1_${ik}$ ) = tmp1 nab( ji, 1_${ik}$ ) = itmp1 end if if( itmp1>=nval( ji ) ) then ab( ji, 2_${ik}$ ) = tmp1 nab( ji, 2_${ik}$ ) = itmp1 end if end if end do loop_100 kl = klnew end if ! check for convergence kfnew = kf loop_110: do ji = kf, kl tmp1 = abs( ab( ji, 2_${ik}$ )-ab( ji, 1_${ik}$ ) ) tmp2 = max( abs( ab( ji, 2_${ik}$ ) ), abs( ab( ji, 1_${ik}$ ) ) ) if( tmp1<max( abstol, pivmin, reltol*tmp2 ) .or.nab( ji, 1_${ik}$ )>=nab( ji, 2_${ik}$ ) ) & then ! converged -- swap with position kfnew, ! then increment kfnew if( ji>kfnew ) then tmp1 = ab( ji, 1_${ik}$ ) tmp2 = ab( ji, 2_${ik}$ ) itmp1 = nab( ji, 1_${ik}$ ) itmp2 = nab( ji, 2_${ik}$ ) ab( ji, 1_${ik}$ ) = ab( kfnew, 1_${ik}$ ) ab( ji, 2_${ik}$ ) = ab( kfnew, 2_${ik}$ ) nab( ji, 1_${ik}$ ) = nab( kfnew, 1_${ik}$ ) nab( ji, 2_${ik}$ ) = nab( kfnew, 2_${ik}$ ) ab( kfnew, 1_${ik}$ ) = tmp1 ab( kfnew, 2_${ik}$ ) = tmp2 nab( kfnew, 1_${ik}$ ) = itmp1 nab( kfnew, 2_${ik}$ ) = itmp2 if( ijob==3_${ik}$ ) then itmp1 = nval( ji ) nval( ji ) = nval( kfnew ) nval( kfnew ) = itmp1 end if end if kfnew = kfnew + 1_${ik}$ end if end do loop_110 kf = kfnew ! choose midpoints do ji = kf, kl c( ji ) = half*( ab( ji, 1_${ik}$ )+ab( ji, 2_${ik}$ ) ) end do ! if no more intervals to refine, quit. if( kf>kl )go to 140 end do loop_130 ! converged 140 continue info = max( kl+1-kf, 0_${ik}$ ) mout = kl return end subroutine stdlib${ii}$_dlaebz #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laebz( ijob, nitmax, n, mmax, minp, nbmin, abstol,reltol, pivmin, d, & !! DLAEBZ: contains the iteration loops which compute and use the !! function N(w), which is the count of eigenvalues of a symmetric !! tridiagonal matrix T less than or equal to its argument w. It !! performs a choice of two types of loops: !! IJOB=1, followed by !! IJOB=2: It takes as input a list of intervals and returns a list of !! sufficiently small intervals whose union contains the same !! eigenvalues as the union of the original intervals. !! The input intervals are (AB(j,1),AB(j,2)], j=1,...,MINP. !! The output interval (AB(j,1),AB(j,2)] will contain !! eigenvalues NAB(j,1)+1,...,NAB(j,2), where 1 <= j <= MOUT. !! IJOB=3: It performs a binary search in each input interval !! (AB(j,1),AB(j,2)] for a point w(j) such that !! N(w(j))=NVAL(j), and uses C(j) as the starting point of !! the search. If such a w(j) is found, then on output !! AB(j,1)=AB(j,2)=w. If no such w(j) is found, then on output !! (AB(j,1),AB(j,2)] will be a small interval containing the !! point where N(w) jumps through NVAL(j), unless that point !! lies outside the initial interval. !! Note that the intervals are in all cases half-open intervals, !! i.e., of the form (a,b] , which includes b but not a . !! To avoid underflow, the matrix should be scaled so that its largest !! element is no greater than overflow**(1/2) * underflow**(1/4) !! in absolute value. To assure the most accurate computation !! of small eigenvalues, the matrix should be scaled to be !! not much smaller than that, either. !! See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal !! Matrix", Report CS41, Computer Science Dept., Stanford !! University, July 21, 1966 !! Note: the arguments are, in general, *not* checked for unreasonable !! values. e, e2, nval, ab, c, mout,nab, work, iwork, info ) ! -- lapack auxiliary routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: ijob, minp, mmax, n, nbmin, nitmax integer(${ik}$), intent(out) :: info, mout real(${rk}$), intent(in) :: abstol, pivmin, reltol ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) integer(${ik}$), intent(inout) :: nab(mmax,*), nval(*) real(${rk}$), intent(inout) :: ab(mmax,*), c(*) real(${rk}$), intent(in) :: d(*), e(*), e2(*) real(${rk}$), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: itmp1, itmp2, j, ji, jit, jp, kf, kfnew, kl, klnew real(${rk}$) :: tmp1, tmp2 ! Intrinsic Functions ! Executable Statements ! check for errors info = 0_${ik}$ if( ijob<1_${ik}$ .or. ijob>3_${ik}$ ) then info = -1_${ik}$ return end if ! initialize nab if( ijob==1_${ik}$ ) then ! compute the number of eigenvalues in the initial intervals. mout = 0_${ik}$ do ji = 1, minp do jp = 1, 2 tmp1 = d( 1_${ik}$ ) - ab( ji, jp ) if( abs( tmp1 )<pivmin )tmp1 = -pivmin nab( ji, jp ) = 0_${ik}$ if( tmp1<=zero )nab( ji, jp ) = 1_${ik}$ do j = 2, n tmp1 = d( j ) - e2( j-1 ) / tmp1 - ab( ji, jp ) if( abs( tmp1 )<pivmin )tmp1 = -pivmin if( tmp1<=zero )nab( ji, jp ) = nab( ji, jp ) + 1_${ik}$ end do end do mout = mout + nab( ji, 2_${ik}$ ) - nab( ji, 1_${ik}$ ) end do return end if ! initialize for loop ! kf and kl have the following meaning: ! intervals 1,...,kf-1 have converged. ! intervals kf,...,kl still need to be refined. kf = 1_${ik}$ kl = minp ! if ijob=2, initialize c. ! if ijob=3, use the user-supplied starting point. if( ijob==2_${ik}$ ) then do ji = 1, minp c( ji ) = half*( ab( ji, 1_${ik}$ )+ab( ji, 2_${ik}$ ) ) end do end if ! iteration loop loop_130: do jit = 1, nitmax ! loop over intervals if( kl-kf+1>=nbmin .and. nbmin>0_${ik}$ ) then ! begin of parallel version of the loop do ji = kf, kl ! compute n(c), the number of eigenvalues less than c work( ji ) = d( 1_${ik}$ ) - c( ji ) iwork( ji ) = 0_${ik}$ if( work( ji )<=pivmin ) then iwork( ji ) = 1_${ik}$ work( ji ) = min( work( ji ), -pivmin ) end if do j = 2, n work( ji ) = d( j ) - e2( j-1 ) / work( ji ) - c( ji ) if( work( ji )<=pivmin ) then iwork( ji ) = iwork( ji ) + 1_${ik}$ work( ji ) = min( work( ji ), -pivmin ) end if end do end do if( ijob<=2_${ik}$ ) then ! ijob=2: choose all intervals containing eigenvalues. klnew = kl loop_70: do ji = kf, kl ! insure that n(w) is monotone iwork( ji ) = min( nab( ji, 2_${ik}$ ),max( nab( ji, 1_${ik}$ ), iwork( ji ) ) ) ! update the queue -- add intervals if both halves ! contain eigenvalues. if( iwork( ji )==nab( ji, 2_${ik}$ ) ) then ! no eigenvalue in the upper interval: ! just use the lower interval. ab( ji, 2_${ik}$ ) = c( ji ) else if( iwork( ji )==nab( ji, 1_${ik}$ ) ) then ! no eigenvalue in the lower interval: ! just use the upper interval. ab( ji, 1_${ik}$ ) = c( ji ) else klnew = klnew + 1_${ik}$ if( klnew<=mmax ) then ! eigenvalue in both intervals -- add upper to ! queue. ab( klnew, 2_${ik}$ ) = ab( ji, 2_${ik}$ ) nab( klnew, 2_${ik}$ ) = nab( ji, 2_${ik}$ ) ab( klnew, 1_${ik}$ ) = c( ji ) nab( klnew, 1_${ik}$ ) = iwork( ji ) ab( ji, 2_${ik}$ ) = c( ji ) nab( ji, 2_${ik}$ ) = iwork( ji ) else info = mmax + 1_${ik}$ end if end if end do loop_70 if( info/=0 )return kl = klnew else ! ijob=3: binary search. keep only the interval containing ! w s.t. n(w) = nval do ji = kf, kl if( iwork( ji )<=nval( ji ) ) then ab( ji, 1_${ik}$ ) = c( ji ) nab( ji, 1_${ik}$ ) = iwork( ji ) end if if( iwork( ji )>=nval( ji ) ) then ab( ji, 2_${ik}$ ) = c( ji ) nab( ji, 2_${ik}$ ) = iwork( ji ) end if end do end if else ! end of parallel version of the loop ! begin of serial version of the loop klnew = kl loop_100: do ji = kf, kl ! compute n(w), the number of eigenvalues less than w tmp1 = c( ji ) tmp2 = d( 1_${ik}$ ) - tmp1 itmp1 = 0_${ik}$ if( tmp2<=pivmin ) then itmp1 = 1_${ik}$ tmp2 = min( tmp2, -pivmin ) end if do j = 2, n tmp2 = d( j ) - e2( j-1 ) / tmp2 - tmp1 if( tmp2<=pivmin ) then itmp1 = itmp1 + 1_${ik}$ tmp2 = min( tmp2, -pivmin ) end if end do if( ijob<=2_${ik}$ ) then ! ijob=2: choose all intervals containing eigenvalues. ! insure that n(w) is monotone itmp1 = min( nab( ji, 2_${ik}$ ),max( nab( ji, 1_${ik}$ ), itmp1 ) ) ! update the queue -- add intervals if both halves ! contain eigenvalues. if( itmp1==nab( ji, 2_${ik}$ ) ) then ! no eigenvalue in the upper interval: ! just use the lower interval. ab( ji, 2_${ik}$ ) = tmp1 else if( itmp1==nab( ji, 1_${ik}$ ) ) then ! no eigenvalue in the lower interval: ! just use the upper interval. ab( ji, 1_${ik}$ ) = tmp1 else if( klnew<mmax ) then ! eigenvalue in both intervals -- add upper to queue. klnew = klnew + 1_${ik}$ ab( klnew, 2_${ik}$ ) = ab( ji, 2_${ik}$ ) nab( klnew, 2_${ik}$ ) = nab( ji, 2_${ik}$ ) ab( klnew, 1_${ik}$ ) = tmp1 nab( klnew, 1_${ik}$ ) = itmp1 ab( ji, 2_${ik}$ ) = tmp1 nab( ji, 2_${ik}$ ) = itmp1 else info = mmax + 1_${ik}$ return end if else ! ijob=3: binary search. keep only the interval ! containing w s.t. n(w) = nval if( itmp1<=nval( ji ) ) then ab( ji, 1_${ik}$ ) = tmp1 nab( ji, 1_${ik}$ ) = itmp1 end if if( itmp1>=nval( ji ) ) then ab( ji, 2_${ik}$ ) = tmp1 nab( ji, 2_${ik}$ ) = itmp1 end if end if end do loop_100 kl = klnew end if ! check for convergence kfnew = kf loop_110: do ji = kf, kl tmp1 = abs( ab( ji, 2_${ik}$ )-ab( ji, 1_${ik}$ ) ) tmp2 = max( abs( ab( ji, 2_${ik}$ ) ), abs( ab( ji, 1_${ik}$ ) ) ) if( tmp1<max( abstol, pivmin, reltol*tmp2 ) .or.nab( ji, 1_${ik}$ )>=nab( ji, 2_${ik}$ ) ) & then ! converged -- swap with position kfnew, ! then increment kfnew if( ji>kfnew ) then tmp1 = ab( ji, 1_${ik}$ ) tmp2 = ab( ji, 2_${ik}$ ) itmp1 = nab( ji, 1_${ik}$ ) itmp2 = nab( ji, 2_${ik}$ ) ab( ji, 1_${ik}$ ) = ab( kfnew, 1_${ik}$ ) ab( ji, 2_${ik}$ ) = ab( kfnew, 2_${ik}$ ) nab( ji, 1_${ik}$ ) = nab( kfnew, 1_${ik}$ ) nab( ji, 2_${ik}$ ) = nab( kfnew, 2_${ik}$ ) ab( kfnew, 1_${ik}$ ) = tmp1 ab( kfnew, 2_${ik}$ ) = tmp2 nab( kfnew, 1_${ik}$ ) = itmp1 nab( kfnew, 2_${ik}$ ) = itmp2 if( ijob==3_${ik}$ ) then itmp1 = nval( ji ) nval( ji ) = nval( kfnew ) nval( kfnew ) = itmp1 end if end if kfnew = kfnew + 1_${ik}$ end if end do loop_110 kf = kfnew ! choose midpoints do ji = kf, kl c( ji ) = half*( ab( ji, 1_${ik}$ )+ab( ji, 2_${ik}$ ) ) end do ! if no more intervals to refine, quit. if( kf>kl )go to 140 end do loop_130 ! converged 140 continue info = max( kl+1-kf, 0_${ik}$ ) mout = kl return end subroutine stdlib${ii}$_${ri}$laebz #:endif #:endfor pure integer(${ik}$) module function stdlib${ii}$_slaneg( n, d, lld, sigma, pivmin, r ) !! SLANEG computes the Sturm count, the number of negative pivots !! encountered while factoring tridiagonal T - sigma I = L D L^T. !! This implementation works directly on the factors without forming !! the tridiagonal matrix T. The Sturm count is also the number of !! eigenvalues of T less than sigma. !! This routine is called from SLARRB. !! The current routine does not use the PIVMIN parameter but rather !! requires IEEE-754 propagation of Infinities and NaNs. This !! routine also has no input range restrictions but does require !! default exception handling such that x/0 produces Inf when x is !! non-zero, and Inf/Inf produces NaN. For more information, see: !! Marques, Riedy, and Voemel, "Benefits of IEEE-754 Features in !! Modern Symmetric Tridiagonal Eigensolvers," SIAM Journal on !! Scientific Computing, v28, n5, 2006. DOI 10.1137/050641624 !! (Tech report version in LAWN 172 with the same title.) ! -- lapack auxiliary routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: n, r real(sp), intent(in) :: pivmin, sigma ! Array Arguments real(sp), intent(in) :: d(*), lld(*) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: blklen = 128_${ik}$ ! some architectures propagate infinities and nans very slowly, so ! the code computes counts in blklen chunks. then a nan can ! propagate at most blklen columns before being detected. this is ! not a general tuning parameter; it needs only to be just large ! enough that the overhead is tiny in common cases. ! Local Scalars integer(${ik}$) :: bj, j, neg1, neg2, negcnt real(sp) :: bsav, dminus, dplus, gamma, p, t, tmp logical(lk) :: sawnan ! Intrinsic Functions ! Executable Statements negcnt = 0_${ik}$ ! i) upper part: l d l^t - sigma i = l+ d+ l+^t t = -sigma loop_210: do bj = 1, r-1, blklen neg1 = 0_${ik}$ bsav = t do j = bj, min(bj+blklen-1, r-1) dplus = d( j ) + t if( dplus<zero ) neg1 = neg1 + 1_${ik}$ tmp = t / dplus t = tmp * lld( j ) - sigma end do sawnan = stdlib${ii}$_sisnan( t ) ! run a slower version of the above loop if a nan is detected. ! a nan should occur only with a zero pivot after an infinite ! pivot. in that case, substituting 1 for t/dplus is the ! correct limit. if( sawnan ) then neg1 = 0_${ik}$ t = bsav do j = bj, min(bj+blklen-1, r-1) dplus = d( j ) + t if( dplus<zero ) neg1 = neg1 + 1_${ik}$ tmp = t / dplus if (stdlib${ii}$_sisnan(tmp)) tmp = one t = tmp * lld(j) - sigma end do end if negcnt = negcnt + neg1 end do loop_210 ! ii) lower part: l d l^t - sigma i = u- d- u-^t p = d( n ) - sigma do bj = n-1, r, -blklen neg2 = 0_${ik}$ bsav = p do j = bj, max(bj-blklen+1, r), -1 dminus = lld( j ) + p if( dminus<zero ) neg2 = neg2 + 1_${ik}$ tmp = p / dminus p = tmp * d( j ) - sigma end do sawnan = stdlib${ii}$_sisnan( p ) ! as above, run a slower version that substitutes 1 for inf/inf. if( sawnan ) then neg2 = 0_${ik}$ p = bsav do j = bj, max(bj-blklen+1, r), -1 dminus = lld( j ) + p if( dminus<zero ) neg2 = neg2 + 1_${ik}$ tmp = p / dminus if (stdlib${ii}$_sisnan(tmp)) tmp = one p = tmp * d(j) - sigma end do end if negcnt = negcnt + neg2 end do ! iii) twist index ! t was shifted by sigma initially. gamma = (t + sigma) + p if( gamma<zero ) negcnt = negcnt+1 stdlib${ii}$_slaneg = negcnt end function stdlib${ii}$_slaneg pure integer(${ik}$) module function stdlib${ii}$_dlaneg( n, d, lld, sigma, pivmin, r ) !! DLANEG computes the Sturm count, the number of negative pivots !! encountered while factoring tridiagonal T - sigma I = L D L^T. !! This implementation works directly on the factors without forming !! the tridiagonal matrix T. The Sturm count is also the number of !! eigenvalues of T less than sigma. !! This routine is called from DLARRB. !! The current routine does not use the PIVMIN parameter but rather !! requires IEEE-754 propagation of Infinities and NaNs. This !! routine also has no input range restrictions but does require !! default exception handling such that x/0 produces Inf when x is !! non-zero, and Inf/Inf produces NaN. For more information, see: !! Marques, Riedy, and Voemel, "Benefits of IEEE-754 Features in !! Modern Symmetric Tridiagonal Eigensolvers," SIAM Journal on !! Scientific Computing, v28, n5, 2006. DOI 10.1137/050641624 !! (Tech report version in LAWN 172 with the same title.) ! -- lapack auxiliary routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: n, r real(dp), intent(in) :: pivmin, sigma ! Array Arguments real(dp), intent(in) :: d(*), lld(*) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: blklen = 128_${ik}$ ! some architectures propagate infinities and nans very slowly, so ! the code computes counts in blklen chunks. then a nan can ! propagate at most blklen columns before being detected. this is ! not a general tuning parameter; it needs only to be just large ! enough that the overhead is tiny in common cases. ! Local Scalars integer(${ik}$) :: bj, j, neg1, neg2, negcnt real(dp) :: bsav, dminus, dplus, gamma, p, t, tmp logical(lk) :: sawnan ! Intrinsic Functions ! Executable Statements negcnt = 0_${ik}$ ! i) upper part: l d l^t - sigma i = l+ d+ l+^t t = -sigma loop_210: do bj = 1, r-1, blklen neg1 = 0_${ik}$ bsav = t do j = bj, min(bj+blklen-1, r-1) dplus = d( j ) + t if( dplus<zero ) neg1 = neg1 + 1_${ik}$ tmp = t / dplus t = tmp * lld( j ) - sigma end do sawnan = stdlib${ii}$_disnan( t ) ! run a slower version of the above loop if a nan is detected. ! a nan should occur only with a zero pivot after an infinite ! pivot. in that case, substituting 1 for t/dplus is the ! correct limit. if( sawnan ) then neg1 = 0_${ik}$ t = bsav do j = bj, min(bj+blklen-1, r-1) dplus = d( j ) + t if( dplus<zero ) neg1 = neg1 + 1_${ik}$ tmp = t / dplus if (stdlib${ii}$_disnan(tmp)) tmp = one t = tmp * lld(j) - sigma end do end if negcnt = negcnt + neg1 end do loop_210 ! ii) lower part: l d l^t - sigma i = u- d- u-^t p = d( n ) - sigma do bj = n-1, r, -blklen neg2 = 0_${ik}$ bsav = p do j = bj, max(bj-blklen+1, r), -1 dminus = lld( j ) + p if( dminus<zero ) neg2 = neg2 + 1_${ik}$ tmp = p / dminus p = tmp * d( j ) - sigma end do sawnan = stdlib${ii}$_disnan( p ) ! as above, run a slower version that substitutes 1 for inf/inf. if( sawnan ) then neg2 = 0_${ik}$ p = bsav do j = bj, max(bj-blklen+1, r), -1 dminus = lld( j ) + p if( dminus<zero ) neg2 = neg2 + 1_${ik}$ tmp = p / dminus if (stdlib${ii}$_disnan(tmp)) tmp = one p = tmp * d(j) - sigma end do end if negcnt = negcnt + neg2 end do ! iii) twist index ! t was shifted by sigma initially. gamma = (t + sigma) + p if( gamma<zero ) negcnt = negcnt+1 stdlib${ii}$_dlaneg = negcnt end function stdlib${ii}$_dlaneg #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure integer(${ik}$) module function stdlib${ii}$_${ri}$laneg( n, d, lld, sigma, pivmin, r ) !! DLANEG: computes the Sturm count, the number of negative pivots !! encountered while factoring tridiagonal T - sigma I = L D L^T. !! This implementation works directly on the factors without forming !! the tridiagonal matrix T. The Sturm count is also the number of !! eigenvalues of T less than sigma. !! This routine is called from DLARRB. !! The current routine does not use the PIVMIN parameter but rather !! requires IEEE-754 propagation of Infinities and NaNs. This !! routine also has no input range restrictions but does require !! default exception handling such that x/0 produces Inf when x is !! non-zero, and Inf/Inf produces NaN. For more information, see: !! Marques, Riedy, and Voemel, "Benefits of IEEE-754 Features in !! Modern Symmetric Tridiagonal Eigensolvers," SIAM Journal on !! Scientific Computing, v28, n5, 2006. DOI 10.1137/050641624 !! (Tech report version in LAWN 172 with the same title.) ! -- lapack auxiliary routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: n, r real(${rk}$), intent(in) :: pivmin, sigma ! Array Arguments real(${rk}$), intent(in) :: d(*), lld(*) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: blklen = 128_${ik}$ ! some architectures propagate infinities and nans very slowly, so ! the code computes counts in blklen chunks. then a nan can ! propagate at most blklen columns before being detected. this is ! not a general tuning parameter; it needs only to be just large ! enough that the overhead is tiny in common cases. ! Local Scalars integer(${ik}$) :: bj, j, neg1, neg2, negcnt real(${rk}$) :: bsav, dminus, dplus, gamma, p, t, tmp logical(lk) :: sawnan ! Intrinsic Functions ! Executable Statements negcnt = 0_${ik}$ ! i) upper part: l d l^t - sigma i = l+ d+ l+^t t = -sigma loop_210: do bj = 1, r-1, blklen neg1 = 0_${ik}$ bsav = t do j = bj, min(bj+blklen-1, r-1) dplus = d( j ) + t if( dplus<zero ) neg1 = neg1 + 1_${ik}$ tmp = t / dplus t = tmp * lld( j ) - sigma end do sawnan = stdlib${ii}$_${ri}$isnan( t ) ! run a slower version of the above loop if a nan is detected. ! a nan should occur only with a zero pivot after an infinite ! pivot. in that case, substituting 1 for t/dplus is the ! correct limit. if( sawnan ) then neg1 = 0_${ik}$ t = bsav do j = bj, min(bj+blklen-1, r-1) dplus = d( j ) + t if( dplus<zero ) neg1 = neg1 + 1_${ik}$ tmp = t / dplus if (stdlib${ii}$_${ri}$isnan(tmp)) tmp = one t = tmp * lld(j) - sigma end do end if negcnt = negcnt + neg1 end do loop_210 ! ii) lower part: l d l^t - sigma i = u- d- u-^t p = d( n ) - sigma do bj = n-1, r, -blklen neg2 = 0_${ik}$ bsav = p do j = bj, max(bj-blklen+1, r), -1 dminus = lld( j ) + p if( dminus<zero ) neg2 = neg2 + 1_${ik}$ tmp = p / dminus p = tmp * d( j ) - sigma end do sawnan = stdlib${ii}$_${ri}$isnan( p ) ! as above, run a slower version that substitutes 1 for inf/inf. if( sawnan ) then neg2 = 0_${ik}$ p = bsav do j = bj, max(bj-blklen+1, r), -1 dminus = lld( j ) + p if( dminus<zero ) neg2 = neg2 + 1_${ik}$ tmp = p / dminus if (stdlib${ii}$_${ri}$isnan(tmp)) tmp = one p = tmp * d(j) - sigma end do end if negcnt = negcnt + neg2 end do ! iii) twist index ! t was shifted by sigma initially. gamma = (t + sigma) + p if( gamma<zero ) negcnt = negcnt+1 stdlib${ii}$_${ri}$laneg = negcnt end function stdlib${ii}$_${ri}$laneg #:endif #:endfor pure module subroutine stdlib${ii}$_slaed0( icompq, qsiz, n, d, e, q, ldq, qstore, ldqs,work, iwork, info & !! SLAED0 computes all eigenvalues and corresponding eigenvectors of a !! symmetric tridiagonal matrix using the divide and conquer method. ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: icompq, ldq, ldqs, n, qsiz integer(${ik}$), intent(out) :: info ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) real(sp), intent(inout) :: d(*), e(*), q(ldq,*) real(sp), intent(out) :: qstore(ldqs,*), work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: curlvl, curprb, curr, i, igivcl, igivnm, igivpt, indxq, iperm, iprmpt, & iq, iqptr, iwrem, j, k, lgn, matsiz, msd2, smlsiz, smm1, spm1, spm2, submat, subpbs, & tlvls real(sp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>2_${ik}$ ) then info = -1_${ik}$ else if( ( icompq==1_${ik}$ ) .and. ( qsiz<max( 0_${ik}$, n ) ) ) then info = -2_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -7_${ik}$ else if( ldqs<max( 1_${ik}$, n ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED0', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'SLAED0', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) ! determine the size and placement of the submatrices, and save in ! the leading elements of iwork. iwork( 1_${ik}$ ) = n subpbs = 1_${ik}$ tlvls = 0_${ik}$ 10 continue if( iwork( subpbs )>smlsiz ) then do j = subpbs, 1, -1 iwork( 2_${ik}$*j ) = ( iwork( j )+1_${ik}$ ) / 2_${ik}$ iwork( 2_${ik}$*j-1 ) = iwork( j ) / 2_${ik}$ end do tlvls = tlvls + 1_${ik}$ subpbs = 2_${ik}$*subpbs go to 10 end if do j = 2, subpbs iwork( j ) = iwork( j ) + iwork( j-1 ) end do ! divide the matrix into subpbs submatrices of size at most smlsiz+1 ! using rank-1 modifications (cuts). spm1 = subpbs - 1_${ik}$ do i = 1, spm1 submat = iwork( i ) + 1_${ik}$ smm1 = submat - 1_${ik}$ d( smm1 ) = d( smm1 ) - abs( e( smm1 ) ) d( submat ) = d( submat ) - abs( e( smm1 ) ) end do indxq = 4_${ik}$*n + 3_${ik}$ if( icompq/=2_${ik}$ ) then ! set up workspaces for eigenvalues only/accumulate new vectors ! routine temp = log( real( n,KIND=sp) ) / log( two ) lgn = int( temp,KIND=${ik}$) if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ iprmpt = indxq + n + 1_${ik}$ iperm = iprmpt + n*lgn iqptr = iperm + n*lgn igivpt = iqptr + n + 2_${ik}$ igivcl = igivpt + n*lgn igivnm = 1_${ik}$ iq = igivnm + 2_${ik}$*n*lgn iwrem = iq + n**2_${ik}$ + 1_${ik}$ ! initialize pointers do i = 0, subpbs iwork( iprmpt+i ) = 1_${ik}$ iwork( igivpt+i ) = 1_${ik}$ end do iwork( iqptr ) = 1_${ik}$ end if ! solve each submatrix eigenproblem at the bottom of the divide and ! conquer tree. curr = 0_${ik}$ loop_70: do i = 0, spm1 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 1_${ik}$ ) else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+1 ) - iwork( i ) end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_ssteqr( 'I', matsiz, d( submat ), e( submat ),q( submat, submat ), & ldq, work, info ) if( info/=0 )go to 130 else call stdlib${ii}$_ssteqr( 'I', matsiz, d( submat ), e( submat ),work( iq-1+iwork( & iqptr+curr ) ), matsiz, work,info ) if( info/=0 )go to 130 if( icompq==1_${ik}$ ) then call stdlib${ii}$_sgemm( 'N', 'N', qsiz, matsiz, matsiz, one,q( 1_${ik}$, submat ), ldq, & work( iq-1+iwork( iqptr+curr ) ), matsiz, zero, qstore( 1_${ik}$, submat ),ldqs ) end if iwork( iqptr+curr+1 ) = iwork( iqptr+curr ) + matsiz**2_${ik}$ curr = curr + 1_${ik}$ end if k = 1_${ik}$ do j = submat, iwork( i+1 ) iwork( indxq+j ) = k k = k + 1_${ik}$ end do end do loop_70 ! successively merge eigensystems of adjacent submatrices ! into eigensystem for the corresponding larger matrix. ! while ( subpbs > 1 ) curlvl = 1_${ik}$ 80 continue if( subpbs>1_${ik}$ ) then spm2 = subpbs - 2_${ik}$ loop_90: do i = 0, spm2, 2 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 2_${ik}$ ) msd2 = iwork( 1_${ik}$ ) curprb = 0_${ik}$ else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+2 ) - iwork( i ) msd2 = matsiz / 2_${ik}$ curprb = curprb + 1_${ik}$ end if ! merge lower order eigensystems (of size msd2 and matsiz - msd2) ! into an eigensystem of size matsiz. ! stdlib${ii}$_slaed1 is used only for the full eigensystem of a tridiagonal ! matrix. ! stdlib${ii}$_slaed7 handles the cases in which eigenvalues only or eigenvalues ! and eigenvectors of a full symmetric matrix (which was reduced to ! tridiagonal form) are desired. if( icompq==2_${ik}$ ) then call stdlib${ii}$_slaed1( matsiz, d( submat ), q( submat, submat ),ldq, iwork( & indxq+submat ),e( submat+msd2-1 ), msd2, work,iwork( subpbs+1 ), info ) else call stdlib${ii}$_slaed7( icompq, matsiz, qsiz, tlvls, curlvl, curprb,d( submat ), & qstore( 1_${ik}$, submat ), ldqs,iwork( indxq+submat ), e( submat+msd2-1 ),msd2, & work( iq ), iwork( iqptr ),iwork( iprmpt ), iwork( iperm ),iwork( igivpt ), & iwork( igivcl ),work( igivnm ), work( iwrem ),iwork( subpbs+1 ), info ) end if if( info/=0 )go to 130 iwork( i / 2_${ik}$+1 ) = iwork( i+2 ) end do loop_90 subpbs = subpbs / 2_${ik}$ curlvl = curlvl + 1_${ik}$ go to 80 end if ! end while ! re-merge the eigenvalues/vectors which were deflated at the final ! merge step. if( icompq==1_${ik}$ ) then do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) call stdlib${ii}$_scopy( qsiz, qstore( 1_${ik}$, j ), 1_${ik}$, q( 1_${ik}$, i ), 1_${ik}$ ) end do call stdlib${ii}$_scopy( n, work, 1_${ik}$, d, 1_${ik}$ ) else if( icompq==2_${ik}$ ) then do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) call stdlib${ii}$_scopy( n, q( 1_${ik}$, j ), 1_${ik}$, work( n*i+1 ), 1_${ik}$ ) end do call stdlib${ii}$_scopy( n, work, 1_${ik}$, d, 1_${ik}$ ) call stdlib${ii}$_slacpy( 'A', n, n, work( n+1 ), n, q, ldq ) else do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) end do call stdlib${ii}$_scopy( n, work, 1_${ik}$, d, 1_${ik}$ ) end if go to 140 130 continue info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ 140 continue return end subroutine stdlib${ii}$_slaed0 pure module subroutine stdlib${ii}$_dlaed0( icompq, qsiz, n, d, e, q, ldq, qstore, ldqs,work, iwork, info & !! DLAED0 computes all eigenvalues and corresponding eigenvectors of a !! symmetric tridiagonal matrix using the divide and conquer method. ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: icompq, ldq, ldqs, n, qsiz integer(${ik}$), intent(out) :: info ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) real(dp), intent(inout) :: d(*), e(*), q(ldq,*) real(dp), intent(out) :: qstore(ldqs,*), work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: curlvl, curprb, curr, i, igivcl, igivnm, igivpt, indxq, iperm, iprmpt, & iq, iqptr, iwrem, j, k, lgn, matsiz, msd2, smlsiz, smm1, spm1, spm2, submat, subpbs, & tlvls real(dp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>2_${ik}$ ) then info = -1_${ik}$ else if( ( icompq==1_${ik}$ ) .and. ( qsiz<max( 0_${ik}$, n ) ) ) then info = -2_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -7_${ik}$ else if( ldqs<max( 1_${ik}$, n ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED0', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'DLAED0', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) ! determine the size and placement of the submatrices, and save in ! the leading elements of iwork. iwork( 1_${ik}$ ) = n subpbs = 1_${ik}$ tlvls = 0_${ik}$ 10 continue if( iwork( subpbs )>smlsiz ) then do j = subpbs, 1, -1 iwork( 2_${ik}$*j ) = ( iwork( j )+1_${ik}$ ) / 2_${ik}$ iwork( 2_${ik}$*j-1 ) = iwork( j ) / 2_${ik}$ end do tlvls = tlvls + 1_${ik}$ subpbs = 2_${ik}$*subpbs go to 10 end if do j = 2, subpbs iwork( j ) = iwork( j ) + iwork( j-1 ) end do ! divide the matrix into subpbs submatrices of size at most smlsiz+1 ! using rank-1 modifications (cuts). spm1 = subpbs - 1_${ik}$ do i = 1, spm1 submat = iwork( i ) + 1_${ik}$ smm1 = submat - 1_${ik}$ d( smm1 ) = d( smm1 ) - abs( e( smm1 ) ) d( submat ) = d( submat ) - abs( e( smm1 ) ) end do indxq = 4_${ik}$*n + 3_${ik}$ if( icompq/=2_${ik}$ ) then ! set up workspaces for eigenvalues only/accumulate new vectors ! routine temp = log( real( n,KIND=dp) ) / log( two ) lgn = int( temp,KIND=${ik}$) if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ iprmpt = indxq + n + 1_${ik}$ iperm = iprmpt + n*lgn iqptr = iperm + n*lgn igivpt = iqptr + n + 2_${ik}$ igivcl = igivpt + n*lgn igivnm = 1_${ik}$ iq = igivnm + 2_${ik}$*n*lgn iwrem = iq + n**2_${ik}$ + 1_${ik}$ ! initialize pointers do i = 0, subpbs iwork( iprmpt+i ) = 1_${ik}$ iwork( igivpt+i ) = 1_${ik}$ end do iwork( iqptr ) = 1_${ik}$ end if ! solve each submatrix eigenproblem at the bottom of the divide and ! conquer tree. curr = 0_${ik}$ loop_70: do i = 0, spm1 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 1_${ik}$ ) else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+1 ) - iwork( i ) end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_dsteqr( 'I', matsiz, d( submat ), e( submat ),q( submat, submat ), & ldq, work, info ) if( info/=0 )go to 130 else call stdlib${ii}$_dsteqr( 'I', matsiz, d( submat ), e( submat ),work( iq-1+iwork( & iqptr+curr ) ), matsiz, work,info ) if( info/=0 )go to 130 if( icompq==1_${ik}$ ) then call stdlib${ii}$_dgemm( 'N', 'N', qsiz, matsiz, matsiz, one,q( 1_${ik}$, submat ), ldq, & work( iq-1+iwork( iqptr+curr ) ), matsiz, zero, qstore( 1_${ik}$, submat ),ldqs ) end if iwork( iqptr+curr+1 ) = iwork( iqptr+curr ) + matsiz**2_${ik}$ curr = curr + 1_${ik}$ end if k = 1_${ik}$ do j = submat, iwork( i+1 ) iwork( indxq+j ) = k k = k + 1_${ik}$ end do end do loop_70 ! successively merge eigensystems of adjacent submatrices ! into eigensystem for the corresponding larger matrix. ! while ( subpbs > 1 ) curlvl = 1_${ik}$ 80 continue if( subpbs>1_${ik}$ ) then spm2 = subpbs - 2_${ik}$ loop_90: do i = 0, spm2, 2 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 2_${ik}$ ) msd2 = iwork( 1_${ik}$ ) curprb = 0_${ik}$ else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+2 ) - iwork( i ) msd2 = matsiz / 2_${ik}$ curprb = curprb + 1_${ik}$ end if ! merge lower order eigensystems (of size msd2 and matsiz - msd2) ! into an eigensystem of size matsiz. ! stdlib${ii}$_dlaed1 is used only for the full eigensystem of a tridiagonal ! matrix. ! stdlib${ii}$_dlaed7 handles the cases in which eigenvalues only or eigenvalues ! and eigenvectors of a full symmetric matrix (which was reduced to ! tridiagonal form) are desired. if( icompq==2_${ik}$ ) then call stdlib${ii}$_dlaed1( matsiz, d( submat ), q( submat, submat ),ldq, iwork( & indxq+submat ),e( submat+msd2-1 ), msd2, work,iwork( subpbs+1 ), info ) else call stdlib${ii}$_dlaed7( icompq, matsiz, qsiz, tlvls, curlvl, curprb,d( submat ), & qstore( 1_${ik}$, submat ), ldqs,iwork( indxq+submat ), e( submat+msd2-1 ),msd2, & work( iq ), iwork( iqptr ),iwork( iprmpt ), iwork( iperm ),iwork( igivpt ), & iwork( igivcl ),work( igivnm ), work( iwrem ),iwork( subpbs+1 ), info ) end if if( info/=0 )go to 130 iwork( i / 2_${ik}$+1 ) = iwork( i+2 ) end do loop_90 subpbs = subpbs / 2_${ik}$ curlvl = curlvl + 1_${ik}$ go to 80 end if ! end while ! re-merge the eigenvalues/vectors which were deflated at the final ! merge step. if( icompq==1_${ik}$ ) then do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) call stdlib${ii}$_dcopy( qsiz, qstore( 1_${ik}$, j ), 1_${ik}$, q( 1_${ik}$, i ), 1_${ik}$ ) end do call stdlib${ii}$_dcopy( n, work, 1_${ik}$, d, 1_${ik}$ ) else if( icompq==2_${ik}$ ) then do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) call stdlib${ii}$_dcopy( n, q( 1_${ik}$, j ), 1_${ik}$, work( n*i+1 ), 1_${ik}$ ) end do call stdlib${ii}$_dcopy( n, work, 1_${ik}$, d, 1_${ik}$ ) call stdlib${ii}$_dlacpy( 'A', n, n, work( n+1 ), n, q, ldq ) else do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) end do call stdlib${ii}$_dcopy( n, work, 1_${ik}$, d, 1_${ik}$ ) end if go to 140 130 continue info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ 140 continue return end subroutine stdlib${ii}$_dlaed0 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed0( icompq, qsiz, n, d, e, q, ldq, qstore, ldqs,work, iwork, info & !! DLAED0: computes all eigenvalues and corresponding eigenvectors of a !! symmetric tridiagonal matrix using the divide and conquer method. ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: icompq, ldq, ldqs, n, qsiz integer(${ik}$), intent(out) :: info ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) real(${rk}$), intent(inout) :: d(*), e(*), q(ldq,*) real(${rk}$), intent(out) :: qstore(ldqs,*), work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: curlvl, curprb, curr, i, igivcl, igivnm, igivpt, indxq, iperm, iprmpt, & iq, iqptr, iwrem, j, k, lgn, matsiz, msd2, smlsiz, smm1, spm1, spm2, submat, subpbs, & tlvls real(${rk}$) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>2_${ik}$ ) then info = -1_${ik}$ else if( ( icompq==1_${ik}$ ) .and. ( qsiz<max( 0_${ik}$, n ) ) ) then info = -2_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -7_${ik}$ else if( ldqs<max( 1_${ik}$, n ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED0', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'DLAED0', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) ! determine the size and placement of the submatrices, and save in ! the leading elements of iwork. iwork( 1_${ik}$ ) = n subpbs = 1_${ik}$ tlvls = 0_${ik}$ 10 continue if( iwork( subpbs )>smlsiz ) then do j = subpbs, 1, -1 iwork( 2_${ik}$*j ) = ( iwork( j )+1_${ik}$ ) / 2_${ik}$ iwork( 2_${ik}$*j-1 ) = iwork( j ) / 2_${ik}$ end do tlvls = tlvls + 1_${ik}$ subpbs = 2_${ik}$*subpbs go to 10 end if do j = 2, subpbs iwork( j ) = iwork( j ) + iwork( j-1 ) end do ! divide the matrix into subpbs submatrices of size at most smlsiz+1 ! using rank-1 modifications (cuts). spm1 = subpbs - 1_${ik}$ do i = 1, spm1 submat = iwork( i ) + 1_${ik}$ smm1 = submat - 1_${ik}$ d( smm1 ) = d( smm1 ) - abs( e( smm1 ) ) d( submat ) = d( submat ) - abs( e( smm1 ) ) end do indxq = 4_${ik}$*n + 3_${ik}$ if( icompq/=2_${ik}$ ) then ! set up workspaces for eigenvalues only/accumulate new vectors ! routine temp = log( real( n,KIND=${rk}$) ) / log( two ) lgn = int( temp,KIND=${ik}$) if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ iprmpt = indxq + n + 1_${ik}$ iperm = iprmpt + n*lgn iqptr = iperm + n*lgn igivpt = iqptr + n + 2_${ik}$ igivcl = igivpt + n*lgn igivnm = 1_${ik}$ iq = igivnm + 2_${ik}$*n*lgn iwrem = iq + n**2_${ik}$ + 1_${ik}$ ! initialize pointers do i = 0, subpbs iwork( iprmpt+i ) = 1_${ik}$ iwork( igivpt+i ) = 1_${ik}$ end do iwork( iqptr ) = 1_${ik}$ end if ! solve each submatrix eigenproblem at the bottom of the divide and ! conquer tree. curr = 0_${ik}$ loop_70: do i = 0, spm1 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 1_${ik}$ ) else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+1 ) - iwork( i ) end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_${ri}$steqr( 'I', matsiz, d( submat ), e( submat ),q( submat, submat ), & ldq, work, info ) if( info/=0 )go to 130 else call stdlib${ii}$_${ri}$steqr( 'I', matsiz, d( submat ), e( submat ),work( iq-1+iwork( & iqptr+curr ) ), matsiz, work,info ) if( info/=0 )go to 130 if( icompq==1_${ik}$ ) then call stdlib${ii}$_${ri}$gemm( 'N', 'N', qsiz, matsiz, matsiz, one,q( 1_${ik}$, submat ), ldq, & work( iq-1+iwork( iqptr+curr ) ), matsiz, zero, qstore( 1_${ik}$, submat ),ldqs ) end if iwork( iqptr+curr+1 ) = iwork( iqptr+curr ) + matsiz**2_${ik}$ curr = curr + 1_${ik}$ end if k = 1_${ik}$ do j = submat, iwork( i+1 ) iwork( indxq+j ) = k k = k + 1_${ik}$ end do end do loop_70 ! successively merge eigensystems of adjacent submatrices ! into eigensystem for the corresponding larger matrix. ! while ( subpbs > 1 ) curlvl = 1_${ik}$ 80 continue if( subpbs>1_${ik}$ ) then spm2 = subpbs - 2_${ik}$ loop_90: do i = 0, spm2, 2 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 2_${ik}$ ) msd2 = iwork( 1_${ik}$ ) curprb = 0_${ik}$ else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+2 ) - iwork( i ) msd2 = matsiz / 2_${ik}$ curprb = curprb + 1_${ik}$ end if ! merge lower order eigensystems (of size msd2 and matsiz - msd2) ! into an eigensystem of size matsiz. ! stdlib${ii}$_${ri}$laed1 is used only for the full eigensystem of a tridiagonal ! matrix. ! stdlib${ii}$_${ri}$laed7 handles the cases in which eigenvalues only or eigenvalues ! and eigenvectors of a full symmetric matrix (which was reduced to ! tridiagonal form) are desired. if( icompq==2_${ik}$ ) then call stdlib${ii}$_${ri}$laed1( matsiz, d( submat ), q( submat, submat ),ldq, iwork( & indxq+submat ),e( submat+msd2-1 ), msd2, work,iwork( subpbs+1 ), info ) else call stdlib${ii}$_${ri}$laed7( icompq, matsiz, qsiz, tlvls, curlvl, curprb,d( submat ), & qstore( 1_${ik}$, submat ), ldqs,iwork( indxq+submat ), e( submat+msd2-1 ),msd2, & work( iq ), iwork( iqptr ),iwork( iprmpt ), iwork( iperm ),iwork( igivpt ), & iwork( igivcl ),work( igivnm ), work( iwrem ),iwork( subpbs+1 ), info ) end if if( info/=0 )go to 130 iwork( i / 2_${ik}$+1 ) = iwork( i+2 ) end do loop_90 subpbs = subpbs / 2_${ik}$ curlvl = curlvl + 1_${ik}$ go to 80 end if ! end while ! re-merge the eigenvalues/vectors which were deflated at the final ! merge step. if( icompq==1_${ik}$ ) then do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) call stdlib${ii}$_${ri}$copy( qsiz, qstore( 1_${ik}$, j ), 1_${ik}$, q( 1_${ik}$, i ), 1_${ik}$ ) end do call stdlib${ii}$_${ri}$copy( n, work, 1_${ik}$, d, 1_${ik}$ ) else if( icompq==2_${ik}$ ) then do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) call stdlib${ii}$_${ri}$copy( n, q( 1_${ik}$, j ), 1_${ik}$, work( n*i+1 ), 1_${ik}$ ) end do call stdlib${ii}$_${ri}$copy( n, work, 1_${ik}$, d, 1_${ik}$ ) call stdlib${ii}$_${ri}$lacpy( 'A', n, n, work( n+1 ), n, q, ldq ) else do i = 1, n j = iwork( indxq+i ) work( i ) = d( j ) end do call stdlib${ii}$_${ri}$copy( n, work, 1_${ik}$, d, 1_${ik}$ ) end if go to 140 130 continue info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ 140 continue return end subroutine stdlib${ii}$_${ri}$laed0 #:endif #:endfor pure module subroutine stdlib${ii}$_claed0( qsiz, n, d, e, q, ldq, qstore, ldqs, rwork,iwork, info ) !! Using the divide and conquer method, CLAED0: computes all eigenvalues !! of a symmetric tridiagonal matrix which is one diagonal block of !! those from reducing a dense or band Hermitian matrix and !! corresponding eigenvectors of the dense or band matrix. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldq, ldqs, n, qsiz ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) real(sp), intent(inout) :: d(*), e(*) real(sp), intent(out) :: rwork(*) complex(sp), intent(inout) :: q(ldq,*) complex(sp), intent(out) :: qstore(ldqs,*) ! ===================================================================== ! warning: n could be as big as qsiz! ! Local Scalars integer(${ik}$) :: curlvl, curprb, curr, i, igivcl, igivnm, igivpt, indxq, iperm, iprmpt, & iq, iqptr, iwrem, j, k, lgn, ll, matsiz, msd2, smlsiz, smm1, spm1, spm2, submat, & subpbs, tlvls real(sp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ ! if( icompq < 0 .or. icompq > 2 ) then ! info = -1 ! else if( ( icompq == 1 ) .and. ( qsiz < max( 0, n ) ) ) ! $ then if( qsiz<max( 0_${ik}$, n ) ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ else if( ldqs<max( 1_${ik}$, n ) ) then info = -8_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'CLAED0', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'CLAED0', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) ! determine the size and placement of the submatrices, and save in ! the leading elements of iwork. iwork( 1_${ik}$ ) = n subpbs = 1_${ik}$ tlvls = 0_${ik}$ 10 continue if( iwork( subpbs )>smlsiz ) then do j = subpbs, 1, -1 iwork( 2_${ik}$*j ) = ( iwork( j )+1_${ik}$ ) / 2_${ik}$ iwork( 2_${ik}$*j-1 ) = iwork( j ) / 2_${ik}$ end do tlvls = tlvls + 1_${ik}$ subpbs = 2_${ik}$*subpbs go to 10 end if do j = 2, subpbs iwork( j ) = iwork( j ) + iwork( j-1 ) end do ! divide the matrix into subpbs submatrices of size at most smlsiz+1 ! using rank-1 modifications (cuts). spm1 = subpbs - 1_${ik}$ do i = 1, spm1 submat = iwork( i ) + 1_${ik}$ smm1 = submat - 1_${ik}$ d( smm1 ) = d( smm1 ) - abs( e( smm1 ) ) d( submat ) = d( submat ) - abs( e( smm1 ) ) end do indxq = 4_${ik}$*n + 3_${ik}$ ! set up workspaces for eigenvalues only/accumulate new vectors ! routine temp = log( real( n,KIND=sp) ) / log( two ) lgn = int( temp,KIND=${ik}$) if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ iprmpt = indxq + n + 1_${ik}$ iperm = iprmpt + n*lgn iqptr = iperm + n*lgn igivpt = iqptr + n + 2_${ik}$ igivcl = igivpt + n*lgn igivnm = 1_${ik}$ iq = igivnm + 2_${ik}$*n*lgn iwrem = iq + n**2_${ik}$ + 1_${ik}$ ! initialize pointers do i = 0, subpbs iwork( iprmpt+i ) = 1_${ik}$ iwork( igivpt+i ) = 1_${ik}$ end do iwork( iqptr ) = 1_${ik}$ ! solve each submatrix eigenproblem at the bottom of the divide and ! conquer tree. curr = 0_${ik}$ do i = 0, spm1 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 1_${ik}$ ) else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+1 ) - iwork( i ) end if ll = iq - 1_${ik}$ + iwork( iqptr+curr ) call stdlib${ii}$_ssteqr( 'I', matsiz, d( submat ), e( submat ),rwork( ll ), matsiz, & rwork, info ) call stdlib${ii}$_clacrm( qsiz, matsiz, q( 1_${ik}$, submat ), ldq, rwork( ll ),matsiz, qstore( & 1_${ik}$, submat ), ldqs,rwork( iwrem ) ) iwork( iqptr+curr+1 ) = iwork( iqptr+curr ) + matsiz**2_${ik}$ curr = curr + 1_${ik}$ if( info>0_${ik}$ ) then info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ return end if k = 1_${ik}$ do j = submat, iwork( i+1 ) iwork( indxq+j ) = k k = k + 1_${ik}$ end do end do ! successively merge eigensystems of adjacent submatrices ! into eigensystem for the corresponding larger matrix. ! while ( subpbs > 1 ) curlvl = 1_${ik}$ 80 continue if( subpbs>1_${ik}$ ) then spm2 = subpbs - 2_${ik}$ do i = 0, spm2, 2 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 2_${ik}$ ) msd2 = iwork( 1_${ik}$ ) curprb = 0_${ik}$ else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+2 ) - iwork( i ) msd2 = matsiz / 2_${ik}$ curprb = curprb + 1_${ik}$ end if ! merge lower order eigensystems (of size msd2 and matsiz - msd2) ! into an eigensystem of size matsiz. stdlib${ii}$_claed7 handles the case ! when the eigenvectors of a full or band hermitian matrix (which ! was reduced to tridiagonal form) are desired. ! i am free to use q as a valuable working space until loop 150. call stdlib${ii}$_claed7( matsiz, msd2, qsiz, tlvls, curlvl, curprb,d( submat ), & qstore( 1_${ik}$, submat ), ldqs,e( submat+msd2-1 ), iwork( indxq+submat ),rwork( iq ), & iwork( iqptr ), iwork( iprmpt ),iwork( iperm ), iwork( igivpt ),iwork( igivcl ), & rwork( igivnm ),q( 1_${ik}$, submat ), rwork( iwrem ),iwork( subpbs+1 ), info ) if( info>0_${ik}$ ) then info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ return end if iwork( i / 2_${ik}$+1 ) = iwork( i+2 ) end do subpbs = subpbs / 2_${ik}$ curlvl = curlvl + 1_${ik}$ go to 80 end if ! end while ! re-merge the eigenvalues/vectors which were deflated at the final ! merge step. do i = 1, n j = iwork( indxq+i ) rwork( i ) = d( j ) call stdlib${ii}$_ccopy( qsiz, qstore( 1_${ik}$, j ), 1_${ik}$, q( 1_${ik}$, i ), 1_${ik}$ ) end do call stdlib${ii}$_scopy( n, rwork, 1_${ik}$, d, 1_${ik}$ ) return end subroutine stdlib${ii}$_claed0 pure module subroutine stdlib${ii}$_zlaed0( qsiz, n, d, e, q, ldq, qstore, ldqs, rwork,iwork, info ) !! Using the divide and conquer method, ZLAED0: computes all eigenvalues !! of a symmetric tridiagonal matrix which is one diagonal block of !! those from reducing a dense or band Hermitian matrix and !! corresponding eigenvectors of the dense or band matrix. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldq, ldqs, n, qsiz ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) real(dp), intent(inout) :: d(*), e(*) real(dp), intent(out) :: rwork(*) complex(dp), intent(inout) :: q(ldq,*) complex(dp), intent(out) :: qstore(ldqs,*) ! ===================================================================== ! warning: n could be as big as qsiz! ! Local Scalars integer(${ik}$) :: curlvl, curprb, curr, i, igivcl, igivnm, igivpt, indxq, iperm, iprmpt, & iq, iqptr, iwrem, j, k, lgn, ll, matsiz, msd2, smlsiz, smm1, spm1, spm2, submat, & subpbs, tlvls real(dp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ ! if( icompq < 0 .or. icompq > 2 ) then ! info = -1 ! else if( ( icompq == 1 ) .and. ( qsiz < max( 0, n ) ) ) ! $ then if( qsiz<max( 0_${ik}$, n ) ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ else if( ldqs<max( 1_${ik}$, n ) ) then info = -8_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZLAED0', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'ZLAED0', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) ! determine the size and placement of the submatrices, and save in ! the leading elements of iwork. iwork( 1_${ik}$ ) = n subpbs = 1_${ik}$ tlvls = 0_${ik}$ 10 continue if( iwork( subpbs )>smlsiz ) then do j = subpbs, 1, -1 iwork( 2_${ik}$*j ) = ( iwork( j )+1_${ik}$ ) / 2_${ik}$ iwork( 2_${ik}$*j-1 ) = iwork( j ) / 2_${ik}$ end do tlvls = tlvls + 1_${ik}$ subpbs = 2_${ik}$*subpbs go to 10 end if do j = 2, subpbs iwork( j ) = iwork( j ) + iwork( j-1 ) end do ! divide the matrix into subpbs submatrices of size at most smlsiz+1 ! using rank-1 modifications (cuts). spm1 = subpbs - 1_${ik}$ do i = 1, spm1 submat = iwork( i ) + 1_${ik}$ smm1 = submat - 1_${ik}$ d( smm1 ) = d( smm1 ) - abs( e( smm1 ) ) d( submat ) = d( submat ) - abs( e( smm1 ) ) end do indxq = 4_${ik}$*n + 3_${ik}$ ! set up workspaces for eigenvalues only/accumulate new vectors ! routine temp = log( real( n,KIND=dp) ) / log( two ) lgn = int( temp,KIND=${ik}$) if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ iprmpt = indxq + n + 1_${ik}$ iperm = iprmpt + n*lgn iqptr = iperm + n*lgn igivpt = iqptr + n + 2_${ik}$ igivcl = igivpt + n*lgn igivnm = 1_${ik}$ iq = igivnm + 2_${ik}$*n*lgn iwrem = iq + n**2_${ik}$ + 1_${ik}$ ! initialize pointers do i = 0, subpbs iwork( iprmpt+i ) = 1_${ik}$ iwork( igivpt+i ) = 1_${ik}$ end do iwork( iqptr ) = 1_${ik}$ ! solve each submatrix eigenproblem at the bottom of the divide and ! conquer tree. curr = 0_${ik}$ do i = 0, spm1 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 1_${ik}$ ) else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+1 ) - iwork( i ) end if ll = iq - 1_${ik}$ + iwork( iqptr+curr ) call stdlib${ii}$_dsteqr( 'I', matsiz, d( submat ), e( submat ),rwork( ll ), matsiz, & rwork, info ) call stdlib${ii}$_zlacrm( qsiz, matsiz, q( 1_${ik}$, submat ), ldq, rwork( ll ),matsiz, qstore( & 1_${ik}$, submat ), ldqs,rwork( iwrem ) ) iwork( iqptr+curr+1 ) = iwork( iqptr+curr ) + matsiz**2_${ik}$ curr = curr + 1_${ik}$ if( info>0_${ik}$ ) then info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ return end if k = 1_${ik}$ do j = submat, iwork( i+1 ) iwork( indxq+j ) = k k = k + 1_${ik}$ end do end do ! successively merge eigensystems of adjacent submatrices ! into eigensystem for the corresponding larger matrix. ! while ( subpbs > 1 ) curlvl = 1_${ik}$ 80 continue if( subpbs>1_${ik}$ ) then spm2 = subpbs - 2_${ik}$ do i = 0, spm2, 2 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 2_${ik}$ ) msd2 = iwork( 1_${ik}$ ) curprb = 0_${ik}$ else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+2 ) - iwork( i ) msd2 = matsiz / 2_${ik}$ curprb = curprb + 1_${ik}$ end if ! merge lower order eigensystems (of size msd2 and matsiz - msd2) ! into an eigensystem of size matsiz. stdlib${ii}$_zlaed7 handles the case ! when the eigenvectors of a full or band hermitian matrix (which ! was reduced to tridiagonal form) are desired. ! i am free to use q as a valuable working space until loop 150. call stdlib${ii}$_zlaed7( matsiz, msd2, qsiz, tlvls, curlvl, curprb,d( submat ), & qstore( 1_${ik}$, submat ), ldqs,e( submat+msd2-1 ), iwork( indxq+submat ),rwork( iq ), & iwork( iqptr ), iwork( iprmpt ),iwork( iperm ), iwork( igivpt ),iwork( igivcl ), & rwork( igivnm ),q( 1_${ik}$, submat ), rwork( iwrem ),iwork( subpbs+1 ), info ) if( info>0_${ik}$ ) then info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ return end if iwork( i / 2_${ik}$+1 ) = iwork( i+2 ) end do subpbs = subpbs / 2_${ik}$ curlvl = curlvl + 1_${ik}$ go to 80 end if ! end while ! re-merge the eigenvalues/vectors which were deflated at the final ! merge step. do i = 1, n j = iwork( indxq+i ) rwork( i ) = d( j ) call stdlib${ii}$_zcopy( qsiz, qstore( 1_${ik}$, j ), 1_${ik}$, q( 1_${ik}$, i ), 1_${ik}$ ) end do call stdlib${ii}$_dcopy( n, rwork, 1_${ik}$, d, 1_${ik}$ ) return end subroutine stdlib${ii}$_zlaed0 #:for ck,ct,ci in CMPLX_KINDS_TYPES #:if not ck in ["sp","dp"] pure module subroutine stdlib${ii}$_${ci}$laed0( qsiz, n, d, e, q, ldq, qstore, ldqs, rwork,iwork, info ) !! Using the divide and conquer method, ZLAED0: computes all eigenvalues !! of a symmetric tridiagonal matrix which is one diagonal block of !! those from reducing a dense or band Hermitian matrix and !! corresponding eigenvectors of the dense or band matrix. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${ck}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldq, ldqs, n, qsiz ! Array Arguments integer(${ik}$), intent(out) :: iwork(*) real(${ck}$), intent(inout) :: d(*), e(*) real(${ck}$), intent(out) :: rwork(*) complex(${ck}$), intent(inout) :: q(ldq,*) complex(${ck}$), intent(out) :: qstore(ldqs,*) ! ===================================================================== ! warning: n could be as big as qsiz! ! Local Scalars integer(${ik}$) :: curlvl, curprb, curr, i, igivcl, igivnm, igivpt, indxq, iperm, iprmpt, & iq, iqptr, iwrem, j, k, lgn, ll, matsiz, msd2, smlsiz, smm1, spm1, spm2, submat, & subpbs, tlvls real(${ck}$) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ ! if( icompq < 0 .or. icompq > 2 ) then ! info = -1 ! else if( ( icompq == 1 ) .and. ( qsiz < max( 0, n ) ) ) ! $ then if( qsiz<max( 0_${ik}$, n ) ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ else if( ldqs<max( 1_${ik}$, n ) ) then info = -8_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZLAED0', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'ZLAED0', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) ! determine the size and placement of the submatrices, and save in ! the leading elements of iwork. iwork( 1_${ik}$ ) = n subpbs = 1_${ik}$ tlvls = 0_${ik}$ 10 continue if( iwork( subpbs )>smlsiz ) then do j = subpbs, 1, -1 iwork( 2_${ik}$*j ) = ( iwork( j )+1_${ik}$ ) / 2_${ik}$ iwork( 2_${ik}$*j-1 ) = iwork( j ) / 2_${ik}$ end do tlvls = tlvls + 1_${ik}$ subpbs = 2_${ik}$*subpbs go to 10 end if do j = 2, subpbs iwork( j ) = iwork( j ) + iwork( j-1 ) end do ! divide the matrix into subpbs submatrices of size at most smlsiz+1 ! using rank-1 modifications (cuts). spm1 = subpbs - 1_${ik}$ do i = 1, spm1 submat = iwork( i ) + 1_${ik}$ smm1 = submat - 1_${ik}$ d( smm1 ) = d( smm1 ) - abs( e( smm1 ) ) d( submat ) = d( submat ) - abs( e( smm1 ) ) end do indxq = 4_${ik}$*n + 3_${ik}$ ! set up workspaces for eigenvalues only/accumulate new vectors ! routine temp = log( real( n,KIND=${ck}$) ) / log( two ) lgn = int( temp,KIND=${ik}$) if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$ iprmpt = indxq + n + 1_${ik}$ iperm = iprmpt + n*lgn iqptr = iperm + n*lgn igivpt = iqptr + n + 2_${ik}$ igivcl = igivpt + n*lgn igivnm = 1_${ik}$ iq = igivnm + 2_${ik}$*n*lgn iwrem = iq + n**2_${ik}$ + 1_${ik}$ ! initialize pointers do i = 0, subpbs iwork( iprmpt+i ) = 1_${ik}$ iwork( igivpt+i ) = 1_${ik}$ end do iwork( iqptr ) = 1_${ik}$ ! solve each submatrix eigenproblem at the bottom of the divide and ! conquer tree. curr = 0_${ik}$ do i = 0, spm1 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 1_${ik}$ ) else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+1 ) - iwork( i ) end if ll = iq - 1_${ik}$ + iwork( iqptr+curr ) call stdlib${ii}$_${c2ri(ci)}$steqr( 'I', matsiz, d( submat ), e( submat ),rwork( ll ), matsiz, & rwork, info ) call stdlib${ii}$_${ci}$lacrm( qsiz, matsiz, q( 1_${ik}$, submat ), ldq, rwork( ll ),matsiz, qstore( & 1_${ik}$, submat ), ldqs,rwork( iwrem ) ) iwork( iqptr+curr+1 ) = iwork( iqptr+curr ) + matsiz**2_${ik}$ curr = curr + 1_${ik}$ if( info>0_${ik}$ ) then info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ return end if k = 1_${ik}$ do j = submat, iwork( i+1 ) iwork( indxq+j ) = k k = k + 1_${ik}$ end do end do ! successively merge eigensystems of adjacent submatrices ! into eigensystem for the corresponding larger matrix. ! while ( subpbs > 1 ) curlvl = 1_${ik}$ 80 continue if( subpbs>1_${ik}$ ) then spm2 = subpbs - 2_${ik}$ do i = 0, spm2, 2 if( i==0_${ik}$ ) then submat = 1_${ik}$ matsiz = iwork( 2_${ik}$ ) msd2 = iwork( 1_${ik}$ ) curprb = 0_${ik}$ else submat = iwork( i ) + 1_${ik}$ matsiz = iwork( i+2 ) - iwork( i ) msd2 = matsiz / 2_${ik}$ curprb = curprb + 1_${ik}$ end if ! merge lower order eigensystems (of size msd2 and matsiz - msd2) ! into an eigensystem of size matsiz. stdlib${ii}$_${ci}$laed7 handles the case ! when the eigenvectors of a full or band hermitian matrix (which ! was reduced to tridiagonal form) are desired. ! i am free to use q as a valuable working space until loop 150. call stdlib${ii}$_${ci}$laed7( matsiz, msd2, qsiz, tlvls, curlvl, curprb,d( submat ), & qstore( 1_${ik}$, submat ), ldqs,e( submat+msd2-1 ), iwork( indxq+submat ),rwork( iq ), & iwork( iqptr ), iwork( iprmpt ),iwork( iperm ), iwork( igivpt ),iwork( igivcl ), & rwork( igivnm ),q( 1_${ik}$, submat ), rwork( iwrem ),iwork( subpbs+1 ), info ) if( info>0_${ik}$ ) then info = submat*( n+1 ) + submat + matsiz - 1_${ik}$ return end if iwork( i / 2_${ik}$+1 ) = iwork( i+2 ) end do subpbs = subpbs / 2_${ik}$ curlvl = curlvl + 1_${ik}$ go to 80 end if ! end while ! re-merge the eigenvalues/vectors which were deflated at the final ! merge step. do i = 1, n j = iwork( indxq+i ) rwork( i ) = d( j ) call stdlib${ii}$_${ci}$copy( qsiz, qstore( 1_${ik}$, j ), 1_${ik}$, q( 1_${ik}$, i ), 1_${ik}$ ) end do call stdlib${ii}$_${c2ri(ci)}$copy( n, rwork, 1_${ik}$, d, 1_${ik}$ ) return end subroutine stdlib${ii}$_${ci}$laed0 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed1( n, d, q, ldq, indxq, rho, cutpnt, work, iwork,info ) !! SLAED1 computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and eigenvectors of a tridiagonal matrix. SLAED7 handles !! the case in which eigenvalues only or eigenvalues and eigenvectors !! of a full symmetric matrix (which was reduced to tridiagonal form) !! are desired. !! T = Q(in) ( D(in) + RHO * Z*Z**T ) Q**T(in) = Q(out) * D(out) * Q**T(out) !! where Z = Q**T*u, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine SLAED2. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine SLAED4 (as called by SLAED3). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, ldq, n integer(${ik}$), intent(out) :: info real(sp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: indxq(*) integer(${ik}$), intent(out) :: iwork(*) real(sp), intent(inout) :: d(*), q(ldq,*) real(sp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, cpp1, i, idlmda, indx, indxc, indxp, iq2, is, iw, iz, k, n1, & n2 ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -1_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -4_${ik}$ else if( min( 1_${ik}$, n / 2_${ik}$ )>cutpnt .or. ( n / 2_${ik}$ )<cutpnt ) then info = -7_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED1', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are integer pointers which indicate ! the portion of the workspace ! used by a particular array in stdlib${ii}$_slaed2 and stdlib${ii}$_slaed3. iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq2 = iw + n indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. call stdlib${ii}$_scopy( cutpnt, q( cutpnt, 1_${ik}$ ), ldq, work( iz ), 1_${ik}$ ) cpp1 = cutpnt + 1_${ik}$ call stdlib${ii}$_scopy( n-cutpnt, q( cpp1, cpp1 ), ldq, work( iz+cutpnt ), 1_${ik}$ ) ! deflate eigenvalues. call stdlib${ii}$_slaed2( k, n, cutpnt, d, q, ldq, indxq, rho, work( iz ),work( idlmda ), & work( iw ), work( iq2 ),iwork( indx ), iwork( indxc ), iwork( indxp ),iwork( coltyp ), & info ) if( info/=0 )go to 20 ! solve secular equation. if( k/=0_${ik}$ ) then is = ( iwork( coltyp )+iwork( coltyp+1 ) )*cutpnt +( iwork( coltyp+1 )+iwork( & coltyp+2 ) )*( n-cutpnt ) + iq2 call stdlib${ii}$_slaed3( k, n, cutpnt, d, q, ldq, rho, work( idlmda ),work( iq2 ), iwork(& indxc ), iwork( coltyp ),work( iw ), work( is ), info ) if( info/=0 )go to 20 ! prepare the indxq sorting permutation. n1 = k n2 = n - k call stdlib${ii}$_slamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else do i = 1, n indxq( i ) = i end do end if 20 continue return end subroutine stdlib${ii}$_slaed1 pure module subroutine stdlib${ii}$_dlaed1( n, d, q, ldq, indxq, rho, cutpnt, work, iwork,info ) !! DLAED1 computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and eigenvectors of a tridiagonal matrix. DLAED7 handles !! the case in which eigenvalues only or eigenvalues and eigenvectors !! of a full symmetric matrix (which was reduced to tridiagonal form) !! are desired. !! T = Q(in) ( D(in) + RHO * Z*Z**T ) Q**T(in) = Q(out) * D(out) * Q**T(out) !! where Z = Q**T*u, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine DLAED2. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine DLAED4 (as called by DLAED3). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, ldq, n integer(${ik}$), intent(out) :: info real(dp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: indxq(*) integer(${ik}$), intent(out) :: iwork(*) real(dp), intent(inout) :: d(*), q(ldq,*) real(dp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, i, idlmda, indx, indxc, indxp, iq2, is, iw, iz, k, n1, n2, & zpp1 ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -1_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -4_${ik}$ else if( min( 1_${ik}$, n / 2_${ik}$ )>cutpnt .or. ( n / 2_${ik}$ )<cutpnt ) then info = -7_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED1', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are integer pointers which indicate ! the portion of the workspace ! used by a particular array in stdlib${ii}$_dlaed2 and stdlib${ii}$_dlaed3. iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq2 = iw + n indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. call stdlib${ii}$_dcopy( cutpnt, q( cutpnt, 1_${ik}$ ), ldq, work( iz ), 1_${ik}$ ) zpp1 = cutpnt + 1_${ik}$ call stdlib${ii}$_dcopy( n-cutpnt, q( zpp1, zpp1 ), ldq, work( iz+cutpnt ), 1_${ik}$ ) ! deflate eigenvalues. call stdlib${ii}$_dlaed2( k, n, cutpnt, d, q, ldq, indxq, rho, work( iz ),work( idlmda ), & work( iw ), work( iq2 ),iwork( indx ), iwork( indxc ), iwork( indxp ),iwork( coltyp ), & info ) if( info/=0 )go to 20 ! solve secular equation. if( k/=0_${ik}$ ) then is = ( iwork( coltyp )+iwork( coltyp+1 ) )*cutpnt +( iwork( coltyp+1 )+iwork( & coltyp+2 ) )*( n-cutpnt ) + iq2 call stdlib${ii}$_dlaed3( k, n, cutpnt, d, q, ldq, rho, work( idlmda ),work( iq2 ), iwork(& indxc ), iwork( coltyp ),work( iw ), work( is ), info ) if( info/=0 )go to 20 ! prepare the indxq sorting permutation. n1 = k n2 = n - k call stdlib${ii}$_dlamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else do i = 1, n indxq( i ) = i end do end if 20 continue return end subroutine stdlib${ii}$_dlaed1 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed1( n, d, q, ldq, indxq, rho, cutpnt, work, iwork,info ) !! DLAED1: computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and eigenvectors of a tridiagonal matrix. DLAED7 handles !! the case in which eigenvalues only or eigenvalues and eigenvectors !! of a full symmetric matrix (which was reduced to tridiagonal form) !! are desired. !! T = Q(in) ( D(in) + RHO * Z*Z**T ) Q**T(in) = Q(out) * D(out) * Q**T(out) !! where Z = Q**T*u, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine DLAED2. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine DLAED4 (as called by DLAED3). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, ldq, n integer(${ik}$), intent(out) :: info real(${rk}$), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: indxq(*) integer(${ik}$), intent(out) :: iwork(*) real(${rk}$), intent(inout) :: d(*), q(ldq,*) real(${rk}$), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, i, idlmda, indx, indxc, indxp, iq2, is, iw, iz, k, n1, n2, & zpp1 ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -1_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -4_${ik}$ else if( min( 1_${ik}$, n / 2_${ik}$ )>cutpnt .or. ( n / 2_${ik}$ )<cutpnt ) then info = -7_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED1', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are integer pointers which indicate ! the portion of the workspace ! used by a particular array in stdlib${ii}$_${ri}$laed2 and stdlib${ii}$_${ri}$laed3. iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq2 = iw + n indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. call stdlib${ii}$_${ri}$copy( cutpnt, q( cutpnt, 1_${ik}$ ), ldq, work( iz ), 1_${ik}$ ) zpp1 = cutpnt + 1_${ik}$ call stdlib${ii}$_${ri}$copy( n-cutpnt, q( zpp1, zpp1 ), ldq, work( iz+cutpnt ), 1_${ik}$ ) ! deflate eigenvalues. call stdlib${ii}$_${ri}$laed2( k, n, cutpnt, d, q, ldq, indxq, rho, work( iz ),work( idlmda ), & work( iw ), work( iq2 ),iwork( indx ), iwork( indxc ), iwork( indxp ),iwork( coltyp ), & info ) if( info/=0 )go to 20 ! solve secular equation. if( k/=0_${ik}$ ) then is = ( iwork( coltyp )+iwork( coltyp+1 ) )*cutpnt +( iwork( coltyp+1 )+iwork( & coltyp+2 ) )*( n-cutpnt ) + iq2 call stdlib${ii}$_${ri}$laed3( k, n, cutpnt, d, q, ldq, rho, work( idlmda ),work( iq2 ), iwork(& indxc ), iwork( coltyp ),work( iw ), work( is ), info ) if( info/=0 )go to 20 ! prepare the indxq sorting permutation. n1 = k n2 = n - k call stdlib${ii}$_${ri}$lamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else do i = 1, n indxq( i ) = i end do end if 20 continue return end subroutine stdlib${ii}$_${ri}$laed1 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed2( k, n, n1, d, q, ldq, indxq, rho, z, dlamda, w,q2, indx, indxc,& !! SLAED2 merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny entry in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. indxp, coltyp, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info, k integer(${ik}$), intent(in) :: ldq, n, n1 real(sp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: coltyp(*), indx(*), indxc(*), indxp(*) integer(${ik}$), intent(inout) :: indxq(*) real(sp), intent(inout) :: d(*), q(ldq,*), z(*) real(sp), intent(out) :: dlamda(*), q2(*), w(*) ! ===================================================================== ! Parameters real(sp), parameter :: mone = -1.0_sp ! Local Arrays integer(${ik}$) :: ctot(4_${ik}$), psm(4_${ik}$) ! Local Scalars integer(${ik}$) :: ct, i, imax, iq1, iq2, j, jmax, js, k2, n1p1, n2, nj, pj real(sp) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ else if( min( 1_${ik}$, ( n / 2_${ik}$ ) )>n1 .or. ( n / 2_${ik}$ )<n1 ) then info = -3_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED2', -info ) return end if ! quick return if possible if( n==0 )return n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_sscal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1. since z is the concatenation of ! two normalized vectors, norm2(z) = sqrt(2). t = one / sqrt( two ) call stdlib${ii}$_sscal( n, t, z, 1_${ik}$ ) ! rho = abs( norm(z)**2 * rho ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = n1p1, n indxq( i ) = indxq( i ) + n1 end do ! re-integrate the deflated parts from the last pass do i = 1, n dlamda( i ) = d( indxq( i ) ) end do call stdlib${ii}$_slamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indxc ) do i = 1, n indx( i ) = indxq( indxc( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_isamax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_isamax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_slamch( 'EPSILON' ) tol = eight*eps*max( abs( d( jmax ) ), abs( z( imax ) ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ iq2 = 1_${ik}$ do j = 1, n i = indx( j ) call stdlib${ii}$_scopy( n, q( 1_${ik}$, i ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) dlamda( j ) = d( i ) iq2 = iq2 + n end do call stdlib${ii}$_slacpy( 'A', n, n, q2, n, q, ldq ) call stdlib${ii}$_scopy( n, dlamda, 1_${ik}$, d, 1_${ik}$ ) go to 190 end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. do i = 1, n1 coltyp( i ) = 1_${ik}$ end do do i = n1p1, n coltyp( i ) = 3_${ik}$ end do k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n nj = indx( j ) if( rho*abs( z( nj ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ coltyp( nj ) = 4_${ik}$ indxp( k2 ) = nj if( j==n )go to 100 else pj = nj go to 80 end if end do 80 continue j = j + 1_${ik}$ nj = indx( j ) if( j>n )go to 100 if( rho*abs( z( nj ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ coltyp( nj ) = 4_${ik}$ indxp( k2 ) = nj else ! check if eigenvalues are close enough to allow deflation. s = z( pj ) c = z( nj ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_slapy2( c, s ) t = d( nj ) - d( pj ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( nj ) = tau z( pj ) = zero if( coltyp( nj )/=coltyp( pj ) )coltyp( nj ) = 2_${ik}$ coltyp( pj ) = 4_${ik}$ call stdlib${ii}$_srot( n, q( 1_${ik}$, pj ), 1_${ik}$, q( 1_${ik}$, nj ), 1_${ik}$, c, s ) t = d( pj )*c**2_${ik}$ + d( nj )*s**2_${ik}$ d( nj ) = d( pj )*s**2_${ik}$ + d( nj )*c**2_${ik}$ d( pj ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 90 continue if( k2+i<=n ) then if( d( pj )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = pj i = i + 1_${ik}$ go to 90 else indxp( k2+i-1 ) = pj end if else indxp( k2+i-1 ) = pj end if pj = nj else k = k + 1_${ik}$ dlamda( k ) = d( pj ) w( k ) = z( pj ) indxp( k ) = pj pj = nj end if end if go to 80 100 continue ! record the last eigenvalue. k = k + 1_${ik}$ dlamda( k ) = d( pj ) w( k ) = z( pj ) indxp( k ) = pj ! count up the total number of the various types of columns, then ! form a permutation which positions the four column types into ! four uniform groups (although one or more of these groups may be ! empty). do j = 1, 4 ctot( j ) = 0_${ik}$ end do do j = 1, n ct = coltyp( j ) ctot( ct ) = ctot( ct ) + 1_${ik}$ end do ! psm(*) = position in submatrix (of types 1 through 4) psm( 1_${ik}$ ) = 1_${ik}$ psm( 2_${ik}$ ) = 1_${ik}$ + ctot( 1_${ik}$ ) psm( 3_${ik}$ ) = psm( 2_${ik}$ ) + ctot( 2_${ik}$ ) psm( 4_${ik}$ ) = psm( 3_${ik}$ ) + ctot( 3_${ik}$ ) k = n - ctot( 4_${ik}$ ) ! fill out the indxc array so that the permutation which it induces ! will place all type-1 columns first, all type-2 columns next, ! then all type-3's, and finally all type-4's. do j = 1, n js = indxp( j ) ct = coltyp( js ) indx( psm( ct ) ) = js indxc( psm( ct ) ) = j psm( ct ) = psm( ct ) + 1_${ik}$ end do ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. i = 1_${ik}$ iq1 = 1_${ik}$ iq2 = 1_${ik}$ + ( ctot( 1_${ik}$ )+ctot( 2_${ik}$ ) )*n1 do j = 1, ctot( 1 ) js = indx( i ) call stdlib${ii}$_scopy( n1, q( 1_${ik}$, js ), 1_${ik}$, q2( iq1 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq1 = iq1 + n1 end do do j = 1, ctot( 2 ) js = indx( i ) call stdlib${ii}$_scopy( n1, q( 1_${ik}$, js ), 1_${ik}$, q2( iq1 ), 1_${ik}$ ) call stdlib${ii}$_scopy( n2, q( n1+1, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq1 = iq1 + n1 iq2 = iq2 + n2 end do do j = 1, ctot( 3 ) js = indx( i ) call stdlib${ii}$_scopy( n2, q( n1+1, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq2 = iq2 + n2 end do iq1 = iq2 do j = 1, ctot( 4 ) js = indx( i ) call stdlib${ii}$_scopy( n, q( 1_${ik}$, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) iq2 = iq2 + n z( i ) = d( js ) i = i + 1_${ik}$ end do ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then call stdlib${ii}$_slacpy( 'A', n, ctot( 4_${ik}$ ), q2( iq1 ), n,q( 1_${ik}$, k+1 ), ldq ) call stdlib${ii}$_scopy( n-k, z( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) end if ! copy ctot into coltyp for referencing in stdlib${ii}$_slaed3. do j = 1, 4 coltyp( j ) = ctot( j ) end do 190 continue return end subroutine stdlib${ii}$_slaed2 pure module subroutine stdlib${ii}$_dlaed2( k, n, n1, d, q, ldq, indxq, rho, z, dlamda, w,q2, indx, indxc,& !! DLAED2 merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny entry in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. indxp, coltyp, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info, k integer(${ik}$), intent(in) :: ldq, n, n1 real(dp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: coltyp(*), indx(*), indxc(*), indxp(*) integer(${ik}$), intent(inout) :: indxq(*) real(dp), intent(inout) :: d(*), q(ldq,*), z(*) real(dp), intent(out) :: dlamda(*), q2(*), w(*) ! ===================================================================== ! Parameters real(dp), parameter :: mone = -1.0_dp ! Local Arrays integer(${ik}$) :: ctot(4_${ik}$), psm(4_${ik}$) ! Local Scalars integer(${ik}$) :: ct, i, imax, iq1, iq2, j, jmax, js, k2, n1p1, n2, nj, pj real(dp) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ else if( min( 1_${ik}$, ( n / 2_${ik}$ ) )>n1 .or. ( n / 2_${ik}$ )<n1 ) then info = -3_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED2', -info ) return end if ! quick return if possible if( n==0 )return n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_dscal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1. since z is the concatenation of ! two normalized vectors, norm2(z) = sqrt(2). t = one / sqrt( two ) call stdlib${ii}$_dscal( n, t, z, 1_${ik}$ ) ! rho = abs( norm(z)**2 * rho ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = n1p1, n indxq( i ) = indxq( i ) + n1 end do ! re-integrate the deflated parts from the last pass do i = 1, n dlamda( i ) = d( indxq( i ) ) end do call stdlib${ii}$_dlamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indxc ) do i = 1, n indx( i ) = indxq( indxc( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_idamax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_idamax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_dlamch( 'EPSILON' ) tol = eight*eps*max( abs( d( jmax ) ), abs( z( imax ) ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ iq2 = 1_${ik}$ do j = 1, n i = indx( j ) call stdlib${ii}$_dcopy( n, q( 1_${ik}$, i ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) dlamda( j ) = d( i ) iq2 = iq2 + n end do call stdlib${ii}$_dlacpy( 'A', n, n, q2, n, q, ldq ) call stdlib${ii}$_dcopy( n, dlamda, 1_${ik}$, d, 1_${ik}$ ) go to 190 end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. do i = 1, n1 coltyp( i ) = 1_${ik}$ end do do i = n1p1, n coltyp( i ) = 3_${ik}$ end do k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n nj = indx( j ) if( rho*abs( z( nj ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ coltyp( nj ) = 4_${ik}$ indxp( k2 ) = nj if( j==n )go to 100 else pj = nj go to 80 end if end do 80 continue j = j + 1_${ik}$ nj = indx( j ) if( j>n )go to 100 if( rho*abs( z( nj ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ coltyp( nj ) = 4_${ik}$ indxp( k2 ) = nj else ! check if eigenvalues are close enough to allow deflation. s = z( pj ) c = z( nj ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_dlapy2( c, s ) t = d( nj ) - d( pj ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( nj ) = tau z( pj ) = zero if( coltyp( nj )/=coltyp( pj ) )coltyp( nj ) = 2_${ik}$ coltyp( pj ) = 4_${ik}$ call stdlib${ii}$_drot( n, q( 1_${ik}$, pj ), 1_${ik}$, q( 1_${ik}$, nj ), 1_${ik}$, c, s ) t = d( pj )*c**2_${ik}$ + d( nj )*s**2_${ik}$ d( nj ) = d( pj )*s**2_${ik}$ + d( nj )*c**2_${ik}$ d( pj ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 90 continue if( k2+i<=n ) then if( d( pj )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = pj i = i + 1_${ik}$ go to 90 else indxp( k2+i-1 ) = pj end if else indxp( k2+i-1 ) = pj end if pj = nj else k = k + 1_${ik}$ dlamda( k ) = d( pj ) w( k ) = z( pj ) indxp( k ) = pj pj = nj end if end if go to 80 100 continue ! record the last eigenvalue. k = k + 1_${ik}$ dlamda( k ) = d( pj ) w( k ) = z( pj ) indxp( k ) = pj ! count up the total number of the various types of columns, then ! form a permutation which positions the four column types into ! four uniform groups (although one or more of these groups may be ! empty). do j = 1, 4 ctot( j ) = 0_${ik}$ end do do j = 1, n ct = coltyp( j ) ctot( ct ) = ctot( ct ) + 1_${ik}$ end do ! psm(*) = position in submatrix (of types 1 through 4) psm( 1_${ik}$ ) = 1_${ik}$ psm( 2_${ik}$ ) = 1_${ik}$ + ctot( 1_${ik}$ ) psm( 3_${ik}$ ) = psm( 2_${ik}$ ) + ctot( 2_${ik}$ ) psm( 4_${ik}$ ) = psm( 3_${ik}$ ) + ctot( 3_${ik}$ ) k = n - ctot( 4_${ik}$ ) ! fill out the indxc array so that the permutation which it induces ! will place all type-1 columns first, all type-2 columns next, ! then all type-3's, and finally all type-4's. do j = 1, n js = indxp( j ) ct = coltyp( js ) indx( psm( ct ) ) = js indxc( psm( ct ) ) = j psm( ct ) = psm( ct ) + 1_${ik}$ end do ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. i = 1_${ik}$ iq1 = 1_${ik}$ iq2 = 1_${ik}$ + ( ctot( 1_${ik}$ )+ctot( 2_${ik}$ ) )*n1 do j = 1, ctot( 1 ) js = indx( i ) call stdlib${ii}$_dcopy( n1, q( 1_${ik}$, js ), 1_${ik}$, q2( iq1 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq1 = iq1 + n1 end do do j = 1, ctot( 2 ) js = indx( i ) call stdlib${ii}$_dcopy( n1, q( 1_${ik}$, js ), 1_${ik}$, q2( iq1 ), 1_${ik}$ ) call stdlib${ii}$_dcopy( n2, q( n1+1, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq1 = iq1 + n1 iq2 = iq2 + n2 end do do j = 1, ctot( 3 ) js = indx( i ) call stdlib${ii}$_dcopy( n2, q( n1+1, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq2 = iq2 + n2 end do iq1 = iq2 do j = 1, ctot( 4 ) js = indx( i ) call stdlib${ii}$_dcopy( n, q( 1_${ik}$, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) iq2 = iq2 + n z( i ) = d( js ) i = i + 1_${ik}$ end do ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then call stdlib${ii}$_dlacpy( 'A', n, ctot( 4_${ik}$ ), q2( iq1 ), n,q( 1_${ik}$, k+1 ), ldq ) call stdlib${ii}$_dcopy( n-k, z( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) end if ! copy ctot into coltyp for referencing in stdlib${ii}$_dlaed3. do j = 1, 4 coltyp( j ) = ctot( j ) end do 190 continue return end subroutine stdlib${ii}$_dlaed2 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed2( k, n, n1, d, q, ldq, indxq, rho, z, dlamda, w,q2, indx, indxc,& !! DLAED2: merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny entry in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. indxp, coltyp, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info, k integer(${ik}$), intent(in) :: ldq, n, n1 real(${rk}$), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: coltyp(*), indx(*), indxc(*), indxp(*) integer(${ik}$), intent(inout) :: indxq(*) real(${rk}$), intent(inout) :: d(*), q(ldq,*), z(*) real(${rk}$), intent(out) :: dlamda(*), q2(*), w(*) ! ===================================================================== ! Parameters real(${rk}$), parameter :: mone = -1.0_${rk}$ ! Local Arrays integer(${ik}$) :: ctot(4_${ik}$), psm(4_${ik}$) ! Local Scalars integer(${ik}$) :: ct, i, imax, iq1, iq2, j, jmax, js, k2, n1p1, n2, nj, pj real(${rk}$) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ else if( min( 1_${ik}$, ( n / 2_${ik}$ ) )>n1 .or. ( n / 2_${ik}$ )<n1 ) then info = -3_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED2', -info ) return end if ! quick return if possible if( n==0 )return n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_${ri}$scal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1. since z is the concatenation of ! two normalized vectors, norm2(z) = sqrt(2). t = one / sqrt( two ) call stdlib${ii}$_${ri}$scal( n, t, z, 1_${ik}$ ) ! rho = abs( norm(z)**2 * rho ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = n1p1, n indxq( i ) = indxq( i ) + n1 end do ! re-integrate the deflated parts from the last pass do i = 1, n dlamda( i ) = d( indxq( i ) ) end do call stdlib${ii}$_${ri}$lamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indxc ) do i = 1, n indx( i ) = indxq( indxc( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_i${ri}$amax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_i${ri}$amax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_${ri}$lamch( 'EPSILON' ) tol = eight*eps*max( abs( d( jmax ) ), abs( z( imax ) ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ iq2 = 1_${ik}$ do j = 1, n i = indx( j ) call stdlib${ii}$_${ri}$copy( n, q( 1_${ik}$, i ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) dlamda( j ) = d( i ) iq2 = iq2 + n end do call stdlib${ii}$_${ri}$lacpy( 'A', n, n, q2, n, q, ldq ) call stdlib${ii}$_${ri}$copy( n, dlamda, 1_${ik}$, d, 1_${ik}$ ) go to 190 end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. do i = 1, n1 coltyp( i ) = 1_${ik}$ end do do i = n1p1, n coltyp( i ) = 3_${ik}$ end do k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n nj = indx( j ) if( rho*abs( z( nj ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ coltyp( nj ) = 4_${ik}$ indxp( k2 ) = nj if( j==n )go to 100 else pj = nj go to 80 end if end do 80 continue j = j + 1_${ik}$ nj = indx( j ) if( j>n )go to 100 if( rho*abs( z( nj ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ coltyp( nj ) = 4_${ik}$ indxp( k2 ) = nj else ! check if eigenvalues are close enough to allow deflation. s = z( pj ) c = z( nj ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_${ri}$lapy2( c, s ) t = d( nj ) - d( pj ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( nj ) = tau z( pj ) = zero if( coltyp( nj )/=coltyp( pj ) )coltyp( nj ) = 2_${ik}$ coltyp( pj ) = 4_${ik}$ call stdlib${ii}$_${ri}$rot( n, q( 1_${ik}$, pj ), 1_${ik}$, q( 1_${ik}$, nj ), 1_${ik}$, c, s ) t = d( pj )*c**2_${ik}$ + d( nj )*s**2_${ik}$ d( nj ) = d( pj )*s**2_${ik}$ + d( nj )*c**2_${ik}$ d( pj ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 90 continue if( k2+i<=n ) then if( d( pj )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = pj i = i + 1_${ik}$ go to 90 else indxp( k2+i-1 ) = pj end if else indxp( k2+i-1 ) = pj end if pj = nj else k = k + 1_${ik}$ dlamda( k ) = d( pj ) w( k ) = z( pj ) indxp( k ) = pj pj = nj end if end if go to 80 100 continue ! record the last eigenvalue. k = k + 1_${ik}$ dlamda( k ) = d( pj ) w( k ) = z( pj ) indxp( k ) = pj ! count up the total number of the various types of columns, then ! form a permutation which positions the four column types into ! four uniform groups (although one or more of these groups may be ! empty). do j = 1, 4 ctot( j ) = 0_${ik}$ end do do j = 1, n ct = coltyp( j ) ctot( ct ) = ctot( ct ) + 1_${ik}$ end do ! psm(*) = position in submatrix (of types 1 through 4) psm( 1_${ik}$ ) = 1_${ik}$ psm( 2_${ik}$ ) = 1_${ik}$ + ctot( 1_${ik}$ ) psm( 3_${ik}$ ) = psm( 2_${ik}$ ) + ctot( 2_${ik}$ ) psm( 4_${ik}$ ) = psm( 3_${ik}$ ) + ctot( 3_${ik}$ ) k = n - ctot( 4_${ik}$ ) ! fill out the indxc array so that the permutation which it induces ! will place all type-1 columns first, all type-2 columns next, ! then all type-3's, and finally all type-4's. do j = 1, n js = indxp( j ) ct = coltyp( js ) indx( psm( ct ) ) = js indxc( psm( ct ) ) = j psm( ct ) = psm( ct ) + 1_${ik}$ end do ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. i = 1_${ik}$ iq1 = 1_${ik}$ iq2 = 1_${ik}$ + ( ctot( 1_${ik}$ )+ctot( 2_${ik}$ ) )*n1 do j = 1, ctot( 1 ) js = indx( i ) call stdlib${ii}$_${ri}$copy( n1, q( 1_${ik}$, js ), 1_${ik}$, q2( iq1 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq1 = iq1 + n1 end do do j = 1, ctot( 2 ) js = indx( i ) call stdlib${ii}$_${ri}$copy( n1, q( 1_${ik}$, js ), 1_${ik}$, q2( iq1 ), 1_${ik}$ ) call stdlib${ii}$_${ri}$copy( n2, q( n1+1, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq1 = iq1 + n1 iq2 = iq2 + n2 end do do j = 1, ctot( 3 ) js = indx( i ) call stdlib${ii}$_${ri}$copy( n2, q( n1+1, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) z( i ) = d( js ) i = i + 1_${ik}$ iq2 = iq2 + n2 end do iq1 = iq2 do j = 1, ctot( 4 ) js = indx( i ) call stdlib${ii}$_${ri}$copy( n, q( 1_${ik}$, js ), 1_${ik}$, q2( iq2 ), 1_${ik}$ ) iq2 = iq2 + n z( i ) = d( js ) i = i + 1_${ik}$ end do ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then call stdlib${ii}$_${ri}$lacpy( 'A', n, ctot( 4_${ik}$ ), q2( iq1 ), n,q( 1_${ik}$, k+1 ), ldq ) call stdlib${ii}$_${ri}$copy( n-k, z( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) end if ! copy ctot into coltyp for referencing in stdlib${ii}$_${ri}$laed3. do j = 1, 4 coltyp( j ) = ctot( j ) end do 190 continue return end subroutine stdlib${ii}$_${ri}$laed2 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed3( k, n, n1, d, q, ldq, rho, dlamda, q2, indx,ctot, w, s, info ) !! SLAED3 finds the roots of the secular equation, as defined by the !! values in D, W, and RHO, between 1 and K. It makes the !! appropriate calls to SLAED4 and then updates the eigenvectors by !! multiplying the matrix of eigenvectors of the pair of eigensystems !! being combined by the matrix of eigenvectors of the K-by-K system !! which is solved here. !! This code makes very mild assumptions about floating point !! arithmetic. It will work on machines with a guard digit in !! add/subtract, or on those binary machines without guard digits !! which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. !! It could conceivably fail on hexadecimal or decimal machines !! without guard digits, but we know of none. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: k, ldq, n, n1 real(sp), intent(in) :: rho ! Array Arguments integer(${ik}$), intent(in) :: ctot(*), indx(*) real(sp), intent(out) :: d(*), q(ldq,*), s(*) real(sp), intent(inout) :: dlamda(*), w(*) real(sp), intent(in) :: q2(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: i, ii, iq2, j, n12, n2, n23 real(sp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( k<0_${ik}$ ) then info = -1_${ik}$ else if( n<k ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED3', -info ) return end if ! quick return if possible if( k==0 )return ! modify values dlamda(i) to make sure all dlamda(i)-dlamda(j) can ! be computed with high relative accuracy (barring over/underflow). ! this is a problem on machines without a guard digit in ! add/subtract (cray xmp, cray ymp, cray c 90 and cray 2). ! the following code replaces dlamda(i) by 2*dlamda(i)-dlamda(i), ! which on any of these machines zeros out the bottommost ! bit of dlamda(i) if it is 1; this makes the subsequent ! subtractions dlamda(i)-dlamda(j) unproblematic when cancellation ! occurs. on binary machines with a guard digit (almost all ! machines) it does not change dlamda(i) at all. on hexadecimal ! and decimal machines with a guard digit, it slightly ! changes the bottommost bits of dlamda(i). it does not account ! for hexadecimal or decimal machines without guard digits ! (we know of none). we use a subroutine call to compute ! 2*dlambda(i) to prevent optimizing compilers from eliminating ! this code. do i = 1, k dlamda( i ) = stdlib${ii}$_slamc3( dlamda( i ), dlamda( i ) ) - dlamda( i ) end do do j = 1, k call stdlib${ii}$_slaed4( k, j, dlamda, w, q( 1_${ik}$, j ), rho, d( j ), info ) ! if the zero finder fails, the computation is terminated. if( info/=0 )go to 120 end do if( k==1 )go to 110 if( k==2_${ik}$ ) then do j = 1, k w( 1_${ik}$ ) = q( 1_${ik}$, j ) w( 2_${ik}$ ) = q( 2_${ik}$, j ) ii = indx( 1_${ik}$ ) q( 1_${ik}$, j ) = w( ii ) ii = indx( 2_${ik}$ ) q( 2_${ik}$, j ) = w( ii ) end do go to 110 end if ! compute updated w. call stdlib${ii}$_scopy( k, w, 1_${ik}$, s, 1_${ik}$ ) ! initialize w(i) = q(i,i) call stdlib${ii}$_scopy( k, q, ldq+1, w, 1_${ik}$ ) do j = 1, k do i = 1, j - 1 w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do do i = j + 1, k w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do end do do i = 1, k w( i ) = sign( sqrt( -w( i ) ), s( i ) ) end do ! compute eigenvectors of the modified rank-1 modification. do j = 1, k do i = 1, k s( i ) = w( i ) / q( i, j ) end do temp = stdlib${ii}$_snrm2( k, s, 1_${ik}$ ) do i = 1, k ii = indx( i ) q( i, j ) = s( ii ) / temp end do end do ! compute the updated eigenvectors. 110 continue n2 = n - n1 n12 = ctot( 1_${ik}$ ) + ctot( 2_${ik}$ ) n23 = ctot( 2_${ik}$ ) + ctot( 3_${ik}$ ) call stdlib${ii}$_slacpy( 'A', n23, k, q( ctot( 1_${ik}$ )+1_${ik}$, 1_${ik}$ ), ldq, s, n23 ) iq2 = n1*n12 + 1_${ik}$ if( n23/=0_${ik}$ ) then call stdlib${ii}$_sgemm( 'N', 'N', n2, k, n23, one, q2( iq2 ), n2, s, n23,zero, q( n1+1, & 1_${ik}$ ), ldq ) else call stdlib${ii}$_slaset( 'A', n2, k, zero, zero, q( n1+1, 1_${ik}$ ), ldq ) end if call stdlib${ii}$_slacpy( 'A', n12, k, q, ldq, s, n12 ) if( n12/=0_${ik}$ ) then call stdlib${ii}$_sgemm( 'N', 'N', n1, k, n12, one, q2, n1, s, n12, zero, q,ldq ) else call stdlib${ii}$_slaset( 'A', n1, k, zero, zero, q( 1_${ik}$, 1_${ik}$ ), ldq ) end if 120 continue return end subroutine stdlib${ii}$_slaed3 pure module subroutine stdlib${ii}$_dlaed3( k, n, n1, d, q, ldq, rho, dlamda, q2, indx,ctot, w, s, info ) !! DLAED3 finds the roots of the secular equation, as defined by the !! values in D, W, and RHO, between 1 and K. It makes the !! appropriate calls to DLAED4 and then updates the eigenvectors by !! multiplying the matrix of eigenvectors of the pair of eigensystems !! being combined by the matrix of eigenvectors of the K-by-K system !! which is solved here. !! This code makes very mild assumptions about floating point !! arithmetic. It will work on machines with a guard digit in !! add/subtract, or on those binary machines without guard digits !! which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. !! It could conceivably fail on hexadecimal or decimal machines !! without guard digits, but we know of none. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: k, ldq, n, n1 real(dp), intent(in) :: rho ! Array Arguments integer(${ik}$), intent(in) :: ctot(*), indx(*) real(dp), intent(out) :: d(*), q(ldq,*), s(*) real(dp), intent(inout) :: dlamda(*), w(*) real(dp), intent(in) :: q2(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: i, ii, iq2, j, n12, n2, n23 real(dp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( k<0_${ik}$ ) then info = -1_${ik}$ else if( n<k ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED3', -info ) return end if ! quick return if possible if( k==0 )return ! modify values dlamda(i) to make sure all dlamda(i)-dlamda(j) can ! be computed with high relative accuracy (barring over/underflow). ! this is a problem on machines without a guard digit in ! add/subtract (cray xmp, cray ymp, cray c 90 and cray 2). ! the following code replaces dlamda(i) by 2*dlamda(i)-dlamda(i), ! which on any of these machines zeros out the bottommost ! bit of dlamda(i) if it is 1; this makes the subsequent ! subtractions dlamda(i)-dlamda(j) unproblematic when cancellation ! occurs. on binary machines with a guard digit (almost all ! machines) it does not change dlamda(i) at all. on hexadecimal ! and decimal machines with a guard digit, it slightly ! changes the bottommost bits of dlamda(i). it does not account ! for hexadecimal or decimal machines without guard digits ! (we know of none). we use a subroutine call to compute ! 2*dlambda(i) to prevent optimizing compilers from eliminating ! this code. do i = 1, k dlamda( i ) = stdlib${ii}$_dlamc3( dlamda( i ), dlamda( i ) ) - dlamda( i ) end do do j = 1, k call stdlib${ii}$_dlaed4( k, j, dlamda, w, q( 1_${ik}$, j ), rho, d( j ), info ) ! if the zero finder fails, the computation is terminated. if( info/=0 )go to 120 end do if( k==1 )go to 110 if( k==2_${ik}$ ) then do j = 1, k w( 1_${ik}$ ) = q( 1_${ik}$, j ) w( 2_${ik}$ ) = q( 2_${ik}$, j ) ii = indx( 1_${ik}$ ) q( 1_${ik}$, j ) = w( ii ) ii = indx( 2_${ik}$ ) q( 2_${ik}$, j ) = w( ii ) end do go to 110 end if ! compute updated w. call stdlib${ii}$_dcopy( k, w, 1_${ik}$, s, 1_${ik}$ ) ! initialize w(i) = q(i,i) call stdlib${ii}$_dcopy( k, q, ldq+1, w, 1_${ik}$ ) do j = 1, k do i = 1, j - 1 w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do do i = j + 1, k w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do end do do i = 1, k w( i ) = sign( sqrt( -w( i ) ), s( i ) ) end do ! compute eigenvectors of the modified rank-1 modification. do j = 1, k do i = 1, k s( i ) = w( i ) / q( i, j ) end do temp = stdlib${ii}$_dnrm2( k, s, 1_${ik}$ ) do i = 1, k ii = indx( i ) q( i, j ) = s( ii ) / temp end do end do ! compute the updated eigenvectors. 110 continue n2 = n - n1 n12 = ctot( 1_${ik}$ ) + ctot( 2_${ik}$ ) n23 = ctot( 2_${ik}$ ) + ctot( 3_${ik}$ ) call stdlib${ii}$_dlacpy( 'A', n23, k, q( ctot( 1_${ik}$ )+1_${ik}$, 1_${ik}$ ), ldq, s, n23 ) iq2 = n1*n12 + 1_${ik}$ if( n23/=0_${ik}$ ) then call stdlib${ii}$_dgemm( 'N', 'N', n2, k, n23, one, q2( iq2 ), n2, s, n23,zero, q( n1+1, & 1_${ik}$ ), ldq ) else call stdlib${ii}$_dlaset( 'A', n2, k, zero, zero, q( n1+1, 1_${ik}$ ), ldq ) end if call stdlib${ii}$_dlacpy( 'A', n12, k, q, ldq, s, n12 ) if( n12/=0_${ik}$ ) then call stdlib${ii}$_dgemm( 'N', 'N', n1, k, n12, one, q2, n1, s, n12, zero, q,ldq ) else call stdlib${ii}$_dlaset( 'A', n1, k, zero, zero, q( 1_${ik}$, 1_${ik}$ ), ldq ) end if 120 continue return end subroutine stdlib${ii}$_dlaed3 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed3( k, n, n1, d, q, ldq, rho, dlamda, q2, indx,ctot, w, s, info ) !! DLAED3: finds the roots of the secular equation, as defined by the !! values in D, W, and RHO, between 1 and K. It makes the !! appropriate calls to DLAED4 and then updates the eigenvectors by !! multiplying the matrix of eigenvectors of the pair of eigensystems !! being combined by the matrix of eigenvectors of the K-by-K system !! which is solved here. !! This code makes very mild assumptions about floating point !! arithmetic. It will work on machines with a guard digit in !! add/subtract, or on those binary machines without guard digits !! which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. !! It could conceivably fail on hexadecimal or decimal machines !! without guard digits, but we know of none. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: k, ldq, n, n1 real(${rk}$), intent(in) :: rho ! Array Arguments integer(${ik}$), intent(in) :: ctot(*), indx(*) real(${rk}$), intent(out) :: d(*), q(ldq,*), s(*) real(${rk}$), intent(inout) :: dlamda(*), w(*) real(${rk}$), intent(in) :: q2(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: i, ii, iq2, j, n12, n2, n23 real(${rk}$) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( k<0_${ik}$ ) then info = -1_${ik}$ else if( n<k ) then info = -2_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -6_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED3', -info ) return end if ! quick return if possible if( k==0 )return ! modify values dlamda(i) to make sure all dlamda(i)-dlamda(j) can ! be computed with high relative accuracy (barring over/underflow). ! this is a problem on machines without a guard digit in ! add/subtract (cray xmp, cray ymp, cray c 90 and cray 2). ! the following code replaces dlamda(i) by 2*dlamda(i)-dlamda(i), ! which on any of these machines zeros out the bottommost ! bit of dlamda(i) if it is 1; this makes the subsequent ! subtractions dlamda(i)-dlamda(j) unproblematic when cancellation ! occurs. on binary machines with a guard digit (almost all ! machines) it does not change dlamda(i) at all. on hexadecimal ! and decimal machines with a guard digit, it slightly ! changes the bottommost bits of dlamda(i). it does not account ! for hexadecimal or decimal machines without guard digits ! (we know of none). we use a subroutine call to compute ! 2*dlambda(i) to prevent optimizing compilers from eliminating ! this code. do i = 1, k dlamda( i ) = stdlib${ii}$_${ri}$lamc3( dlamda( i ), dlamda( i ) ) - dlamda( i ) end do do j = 1, k call stdlib${ii}$_${ri}$laed4( k, j, dlamda, w, q( 1_${ik}$, j ), rho, d( j ), info ) ! if the zero finder fails, the computation is terminated. if( info/=0 )go to 120 end do if( k==1 )go to 110 if( k==2_${ik}$ ) then do j = 1, k w( 1_${ik}$ ) = q( 1_${ik}$, j ) w( 2_${ik}$ ) = q( 2_${ik}$, j ) ii = indx( 1_${ik}$ ) q( 1_${ik}$, j ) = w( ii ) ii = indx( 2_${ik}$ ) q( 2_${ik}$, j ) = w( ii ) end do go to 110 end if ! compute updated w. call stdlib${ii}$_${ri}$copy( k, w, 1_${ik}$, s, 1_${ik}$ ) ! initialize w(i) = q(i,i) call stdlib${ii}$_${ri}$copy( k, q, ldq+1, w, 1_${ik}$ ) do j = 1, k do i = 1, j - 1 w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do do i = j + 1, k w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do end do do i = 1, k w( i ) = sign( sqrt( -w( i ) ), s( i ) ) end do ! compute eigenvectors of the modified rank-1 modification. do j = 1, k do i = 1, k s( i ) = w( i ) / q( i, j ) end do temp = stdlib${ii}$_${ri}$nrm2( k, s, 1_${ik}$ ) do i = 1, k ii = indx( i ) q( i, j ) = s( ii ) / temp end do end do ! compute the updated eigenvectors. 110 continue n2 = n - n1 n12 = ctot( 1_${ik}$ ) + ctot( 2_${ik}$ ) n23 = ctot( 2_${ik}$ ) + ctot( 3_${ik}$ ) call stdlib${ii}$_${ri}$lacpy( 'A', n23, k, q( ctot( 1_${ik}$ )+1_${ik}$, 1_${ik}$ ), ldq, s, n23 ) iq2 = n1*n12 + 1_${ik}$ if( n23/=0_${ik}$ ) then call stdlib${ii}$_${ri}$gemm( 'N', 'N', n2, k, n23, one, q2( iq2 ), n2, s, n23,zero, q( n1+1, & 1_${ik}$ ), ldq ) else call stdlib${ii}$_${ri}$laset( 'A', n2, k, zero, zero, q( n1+1, 1_${ik}$ ), ldq ) end if call stdlib${ii}$_${ri}$lacpy( 'A', n12, k, q, ldq, s, n12 ) if( n12/=0_${ik}$ ) then call stdlib${ii}$_${ri}$gemm( 'N', 'N', n1, k, n12, one, q2, n1, s, n12, zero, q,ldq ) else call stdlib${ii}$_${ri}$laset( 'A', n1, k, zero, zero, q( 1_${ik}$, 1_${ik}$ ), ldq ) end if 120 continue return end subroutine stdlib${ii}$_${ri}$laed3 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed4( n, i, d, z, delta, rho, dlam, info ) !! This subroutine computes the I-th updated eigenvalue of a symmetric !! rank-one modification to a diagonal matrix whose elements are !! given in the array d, and that !! D(i) < D(j) for i < j !! and that RHO > 0. This is arranged by the calling routine, and is !! no loss in generality. The rank-one modified system is thus !! diag( D ) + RHO * Z * Z_transpose. !! where we assume the Euclidean norm of Z is 1. !! The method consists of approximating the rational functions in the !! secular equation by simpler interpolating rational functions. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: i, n integer(${ik}$), intent(out) :: info real(sp), intent(out) :: dlam real(sp), intent(in) :: rho ! Array Arguments real(sp), intent(in) :: d(*), z(*) real(sp), intent(out) :: delta(*) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: maxit = 30_${ik}$ ! Local Scalars logical(lk) :: orgati, swtch, swtch3 integer(${ik}$) :: ii, iim1, iip1, ip1, iter, j, niter real(sp) :: a, b, c, del, dltlb, dltub, dphi, dpsi, dw, eps, erretm, eta, midpt, phi, & prew, psi, rhoinv, tau, temp, temp1, w ! Local Arrays real(sp) :: zz(3_${ik}$) ! Intrinsic Functions ! Executable Statements ! since this routine is called in an inner loop, we do no argument ! checking. ! quick return for n=1 and 2. info = 0_${ik}$ if( n==1_${ik}$ ) then ! presumably, i=1 upon entry dlam = d( 1_${ik}$ ) + rho*z( 1_${ik}$ )*z( 1_${ik}$ ) delta( 1_${ik}$ ) = one return end if if( n==2_${ik}$ ) then call stdlib${ii}$_slaed5( i, d, z, delta, rho, dlam ) return end if ! compute machine epsilon eps = stdlib${ii}$_slamch( 'EPSILON' ) rhoinv = one / rho ! the case i = n if( i==n ) then ! initialize some basic variables ii = n - 1_${ik}$ niter = 1_${ik}$ ! calculate initial guess midpt = rho / two ! if ||z||_2 is not one, then temp should be set to ! rho * ||z||_2^2 / two do j = 1, n delta( j ) = ( d( j )-d( i ) ) - midpt end do psi = zero do j = 1, n - 2 psi = psi + z( j )*z( j ) / delta( j ) end do c = rhoinv + psi w = c + z( ii )*z( ii ) / delta( ii ) +z( n )*z( n ) / delta( n ) if( w<=zero ) then temp = z( n-1 )*z( n-1 ) / ( d( n )-d( n-1 )+rho ) +z( n )*z( n ) / rho if( c<=temp ) then tau = rho else del = d( n ) - d( n-1 ) a = -c*del + z( n-1 )*z( n-1 ) + z( n )*z( n ) b = z( n )*z( n )*del if( a<zero ) then tau = two*b / ( sqrt( a*a+four*b*c )-a ) else tau = ( a+sqrt( a*a+four*b*c ) ) / ( two*c ) end if end if ! it can be proved that ! d(n)+rho/2 <= lambda(n) < d(n)+tau <= d(n)+rho dltlb = midpt dltub = rho else del = d( n ) - d( n-1 ) a = -c*del + z( n-1 )*z( n-1 ) + z( n )*z( n ) b = z( n )*z( n )*del if( a<zero ) then tau = two*b / ( sqrt( a*a+four*b*c )-a ) else tau = ( a+sqrt( a*a+four*b*c ) ) / ( two*c ) end if ! it can be proved that ! d(n) < d(n)+tau < lambda(n) < d(n)+rho/2 dltlb = zero dltub = midpt end if do j = 1, n delta( j ) = ( d( j )-d( i ) ) - tau end do ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi ! test for convergence if( abs( w )<=eps*erretm ) then dlam = d( i ) + tau go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step niter = niter + 1_${ik}$ c = w - delta( n-1 )*dpsi - delta( n )*dphi a = ( delta( n-1 )+delta( n ) )*w -delta( n-1 )*delta( n )*( dpsi+dphi ) b = delta( n-1 )*delta( n )*w if( c<zero )c = abs( c ) if( c==zero ) then ! eta = b/a ! eta = rho - tau eta = dltub - tau else if( a>=zero ) then eta = ( a+sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a-sqrt( abs( a*a-four*b*c ) ) ) end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>zero )eta = -w / ( dpsi+dphi ) temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi ! main loop to update the values of the array delta iter = niter + 1_${ik}$ loop_90: do niter = iter, maxit ! test for convergence if( abs( w )<=eps*erretm ) then dlam = d( i ) + tau go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step c = w - delta( n-1 )*dpsi - delta( n )*dphi a = ( delta( n-1 )+delta( n ) )*w -delta( n-1 )*delta( n )*( dpsi+dphi ) b = delta( n-1 )*delta( n )*w if( a>=zero ) then eta = ( a+sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a-sqrt( abs( a*a-four*b*c ) ) ) end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>zero )eta = -w / ( dpsi+dphi ) temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi end do loop_90 ! return with info = 1, niter = maxit and not converged info = 1_${ik}$ dlam = d( i ) + tau go to 250 ! end for the case i = n else ! the case for i < n niter = 1_${ik}$ ip1 = i + 1_${ik}$ ! calculate initial guess del = d( ip1 ) - d( i ) midpt = del / two do j = 1, n delta( j ) = ( d( j )-d( i ) ) - midpt end do psi = zero do j = 1, i - 1 psi = psi + z( j )*z( j ) / delta( j ) end do phi = zero do j = n, i + 2, -1 phi = phi + z( j )*z( j ) / delta( j ) end do c = rhoinv + psi + phi w = c + z( i )*z( i ) / delta( i ) +z( ip1 )*z( ip1 ) / delta( ip1 ) if( w>zero ) then ! d(i)< the ith eigenvalue < (d(i)+d(i+1))/2 ! we choose d(i) as origin. orgati = .true. a = c*del + z( i )*z( i ) + z( ip1 )*z( ip1 ) b = z( i )*z( i )*del if( a>zero ) then tau = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) else tau = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) end if dltlb = zero dltub = midpt else ! (d(i)+d(i+1))/2 <= the ith eigenvalue < d(i+1) ! we choose d(i+1) as origin. orgati = .false. a = c*del - z( i )*z( i ) - z( ip1 )*z( ip1 ) b = z( ip1 )*z( ip1 )*del if( a<zero ) then tau = two*b / ( a-sqrt( abs( a*a+four*b*c ) ) ) else tau = -( a+sqrt( abs( a*a+four*b*c ) ) ) / ( two*c ) end if dltlb = -midpt dltub = zero end if if( orgati ) then do j = 1, n delta( j ) = ( d( j )-d( i ) ) - tau end do else do j = 1, n delta( j ) = ( d( j )-d( ip1 ) ) - tau end do end if if( orgati ) then ii = i else ii = i + 1_${ik}$ end if iim1 = ii - 1_${ik}$ iip1 = ii + 1_${ik}$ ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do w = rhoinv + phi + psi ! w is the value of the secular function with ! its ii-th element removed. swtch3 = .false. if( orgati ) then if( w<zero )swtch3 = .true. else if( w>zero )swtch3 = .true. end if if( ii==1_${ik}$ .or. ii==n )swtch3 = .false. temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = w + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau )& *dw ! test for convergence if( abs( w )<=eps*erretm ) then if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step niter = niter + 1_${ik}$ if( .not.swtch3 ) then if( orgati ) then c = w - delta( ip1 )*dw - ( d( i )-d( ip1 ) )*( z( i ) / delta( i ) )& **2_${ik}$ else c = w - delta( i )*dw - ( d( ip1 )-d( i ) )*( z( ip1 ) / delta( ip1 ) )& **2_${ik}$ end if a = ( delta( i )+delta( ip1 ) )*w -delta( i )*delta( ip1 )*dw b = delta( i )*delta( ip1 )*w if( c==zero ) then if( a==zero ) then if( orgati ) then a = z( i )*z( i ) + delta( ip1 )*delta( ip1 )*( dpsi+dphi ) else a = z( ip1 )*z( ip1 ) + delta( i )*delta( i )*( dpsi+dphi ) end if end if eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if else ! interpolation using three most relevant poles temp = rhoinv + psi + phi if( orgati ) then temp1 = z( iim1 ) / delta( iim1 ) temp1 = temp1*temp1 c = temp - delta( iip1 )*( dpsi+dphi ) -( d( iim1 )-d( iip1 ) )*temp1 zz( 1_${ik}$ ) = z( iim1 )*z( iim1 ) zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*( ( dpsi-temp1 )+dphi ) else temp1 = z( iip1 ) / delta( iip1 ) temp1 = temp1*temp1 c = temp - delta( iim1 )*( dpsi+dphi ) -( d( iip1 )-d( iim1 ) )*temp1 zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*( dpsi+( dphi-temp1 ) ) zz( 3_${ik}$ ) = z( iip1 )*z( iip1 ) end if zz( 2_${ik}$ ) = z( ii )*z( ii ) call stdlib${ii}$_slaed6( niter, orgati, c, delta( iim1 ), zz, w, eta,info ) if( info/=0 )go to 250 end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>=zero )eta = -w / dw temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if prew = w do j = 1, n delta( j ) = delta( j ) - eta end do ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = rhoinv + phi + psi + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau+eta )& *dw swtch = .false. if( orgati ) then if( -w>abs( prew ) / ten )swtch = .true. else if( w>abs( prew ) / ten )swtch = .true. end if tau = tau + eta ! main loop to update the values of the array delta iter = niter + 1_${ik}$ loop_240: do niter = iter, maxit ! test for convergence if( abs( w )<=eps*erretm ) then if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step if( .not.swtch3 ) then if( .not.swtch ) then if( orgati ) then c = w - delta( ip1 )*dw -( d( i )-d( ip1 ) )*( z( i ) / delta( i ) )& **2_${ik}$ else c = w - delta( i )*dw - ( d( ip1 )-d( i ) )*( z( ip1 ) / delta( ip1 ) )& **2_${ik}$ end if else temp = z( ii ) / delta( ii ) if( orgati ) then dpsi = dpsi + temp*temp else dphi = dphi + temp*temp end if c = w - delta( i )*dpsi - delta( ip1 )*dphi end if a = ( delta( i )+delta( ip1 ) )*w -delta( i )*delta( ip1 )*dw b = delta( i )*delta( ip1 )*w if( c==zero ) then if( a==zero ) then if( .not.swtch ) then if( orgati ) then a = z( i )*z( i ) + delta( ip1 )*delta( ip1 )*( dpsi+dphi ) else a = z( ip1 )*z( ip1 ) +delta( i )*delta( i )*( dpsi+dphi ) end if else a = delta( i )*delta( i )*dpsi +delta( ip1 )*delta( ip1 )& *dphi end if end if eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if else ! interpolation using three most relevant poles temp = rhoinv + psi + phi if( swtch ) then c = temp - delta( iim1 )*dpsi - delta( iip1 )*dphi zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*dpsi zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*dphi else if( orgati ) then temp1 = z( iim1 ) / delta( iim1 ) temp1 = temp1*temp1 c = temp - delta( iip1 )*( dpsi+dphi ) -( d( iim1 )-d( iip1 ) )& *temp1 zz( 1_${ik}$ ) = z( iim1 )*z( iim1 ) zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*( ( dpsi-temp1 )+dphi ) else temp1 = z( iip1 ) / delta( iip1 ) temp1 = temp1*temp1 c = temp - delta( iim1 )*( dpsi+dphi ) -( d( iip1 )-d( iim1 ) )& *temp1 zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*( dpsi+( dphi-temp1 ) ) zz( 3_${ik}$ ) = z( iip1 )*z( iip1 ) end if end if call stdlib${ii}$_slaed6( niter, orgati, c, delta( iim1 ), zz, w, eta,info ) if( info/=0 )go to 250 end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>=zero )eta = -w / dw temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta prew = w ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = rhoinv + phi + psi + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau )& *dw if( w*prew>zero .and. abs( w )>abs( prew ) / ten )swtch = .not.swtch end do loop_240 ! return with info = 1, niter = maxit and not converged info = 1_${ik}$ if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if end if 250 continue return end subroutine stdlib${ii}$_slaed4 pure module subroutine stdlib${ii}$_dlaed4( n, i, d, z, delta, rho, dlam, info ) !! This subroutine computes the I-th updated eigenvalue of a symmetric !! rank-one modification to a diagonal matrix whose elements are !! given in the array d, and that !! D(i) < D(j) for i < j !! and that RHO > 0. This is arranged by the calling routine, and is !! no loss in generality. The rank-one modified system is thus !! diag( D ) + RHO * Z * Z_transpose. !! where we assume the Euclidean norm of Z is 1. !! The method consists of approximating the rational functions in the !! secular equation by simpler interpolating rational functions. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: i, n integer(${ik}$), intent(out) :: info real(dp), intent(out) :: dlam real(dp), intent(in) :: rho ! Array Arguments real(dp), intent(in) :: d(*), z(*) real(dp), intent(out) :: delta(*) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: maxit = 30_${ik}$ ! Local Scalars logical(lk) :: orgati, swtch, swtch3 integer(${ik}$) :: ii, iim1, iip1, ip1, iter, j, niter real(dp) :: a, b, c, del, dltlb, dltub, dphi, dpsi, dw, eps, erretm, eta, midpt, phi, & prew, psi, rhoinv, tau, temp, temp1, w ! Local Arrays real(dp) :: zz(3_${ik}$) ! Intrinsic Functions ! Executable Statements ! since this routine is called in an inner loop, we do no argument ! checking. ! quick return for n=1 and 2. info = 0_${ik}$ if( n==1_${ik}$ ) then ! presumably, i=1 upon entry dlam = d( 1_${ik}$ ) + rho*z( 1_${ik}$ )*z( 1_${ik}$ ) delta( 1_${ik}$ ) = one return end if if( n==2_${ik}$ ) then call stdlib${ii}$_dlaed5( i, d, z, delta, rho, dlam ) return end if ! compute machine epsilon eps = stdlib${ii}$_dlamch( 'EPSILON' ) rhoinv = one / rho ! the case i = n if( i==n ) then ! initialize some basic variables ii = n - 1_${ik}$ niter = 1_${ik}$ ! calculate initial guess midpt = rho / two ! if ||z||_2 is not one, then temp should be set to ! rho * ||z||_2^2 / two do j = 1, n delta( j ) = ( d( j )-d( i ) ) - midpt end do psi = zero do j = 1, n - 2 psi = psi + z( j )*z( j ) / delta( j ) end do c = rhoinv + psi w = c + z( ii )*z( ii ) / delta( ii ) +z( n )*z( n ) / delta( n ) if( w<=zero ) then temp = z( n-1 )*z( n-1 ) / ( d( n )-d( n-1 )+rho ) +z( n )*z( n ) / rho if( c<=temp ) then tau = rho else del = d( n ) - d( n-1 ) a = -c*del + z( n-1 )*z( n-1 ) + z( n )*z( n ) b = z( n )*z( n )*del if( a<zero ) then tau = two*b / ( sqrt( a*a+four*b*c )-a ) else tau = ( a+sqrt( a*a+four*b*c ) ) / ( two*c ) end if end if ! it can be proved that ! d(n)+rho/2 <= lambda(n) < d(n)+tau <= d(n)+rho dltlb = midpt dltub = rho else del = d( n ) - d( n-1 ) a = -c*del + z( n-1 )*z( n-1 ) + z( n )*z( n ) b = z( n )*z( n )*del if( a<zero ) then tau = two*b / ( sqrt( a*a+four*b*c )-a ) else tau = ( a+sqrt( a*a+four*b*c ) ) / ( two*c ) end if ! it can be proved that ! d(n) < d(n)+tau < lambda(n) < d(n)+rho/2 dltlb = zero dltub = midpt end if do j = 1, n delta( j ) = ( d( j )-d( i ) ) - tau end do ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi ! test for convergence if( abs( w )<=eps*erretm ) then dlam = d( i ) + tau go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step niter = niter + 1_${ik}$ c = w - delta( n-1 )*dpsi - delta( n )*dphi a = ( delta( n-1 )+delta( n ) )*w -delta( n-1 )*delta( n )*( dpsi+dphi ) b = delta( n-1 )*delta( n )*w if( c<zero )c = abs( c ) if( c==zero ) then ! eta = b/a ! eta = rho - tau eta = dltub - tau else if( a>=zero ) then eta = ( a+sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a-sqrt( abs( a*a-four*b*c ) ) ) end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>zero )eta = -w / ( dpsi+dphi ) temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi ! main loop to update the values of the array delta iter = niter + 1_${ik}$ loop_90: do niter = iter, maxit ! test for convergence if( abs( w )<=eps*erretm ) then dlam = d( i ) + tau go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step c = w - delta( n-1 )*dpsi - delta( n )*dphi a = ( delta( n-1 )+delta( n ) )*w -delta( n-1 )*delta( n )*( dpsi+dphi ) b = delta( n-1 )*delta( n )*w if( a>=zero ) then eta = ( a+sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a-sqrt( abs( a*a-four*b*c ) ) ) end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>zero )eta = -w / ( dpsi+dphi ) temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi end do loop_90 ! return with info = 1, niter = maxit and not converged info = 1_${ik}$ dlam = d( i ) + tau go to 250 ! end for the case i = n else ! the case for i < n niter = 1_${ik}$ ip1 = i + 1_${ik}$ ! calculate initial guess del = d( ip1 ) - d( i ) midpt = del / two do j = 1, n delta( j ) = ( d( j )-d( i ) ) - midpt end do psi = zero do j = 1, i - 1 psi = psi + z( j )*z( j ) / delta( j ) end do phi = zero do j = n, i + 2, -1 phi = phi + z( j )*z( j ) / delta( j ) end do c = rhoinv + psi + phi w = c + z( i )*z( i ) / delta( i ) +z( ip1 )*z( ip1 ) / delta( ip1 ) if( w>zero ) then ! d(i)< the ith eigenvalue < (d(i)+d(i+1))/2 ! we choose d(i) as origin. orgati = .true. a = c*del + z( i )*z( i ) + z( ip1 )*z( ip1 ) b = z( i )*z( i )*del if( a>zero ) then tau = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) else tau = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) end if dltlb = zero dltub = midpt else ! (d(i)+d(i+1))/2 <= the ith eigenvalue < d(i+1) ! we choose d(i+1) as origin. orgati = .false. a = c*del - z( i )*z( i ) - z( ip1 )*z( ip1 ) b = z( ip1 )*z( ip1 )*del if( a<zero ) then tau = two*b / ( a-sqrt( abs( a*a+four*b*c ) ) ) else tau = -( a+sqrt( abs( a*a+four*b*c ) ) ) / ( two*c ) end if dltlb = -midpt dltub = zero end if if( orgati ) then do j = 1, n delta( j ) = ( d( j )-d( i ) ) - tau end do else do j = 1, n delta( j ) = ( d( j )-d( ip1 ) ) - tau end do end if if( orgati ) then ii = i else ii = i + 1_${ik}$ end if iim1 = ii - 1_${ik}$ iip1 = ii + 1_${ik}$ ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do w = rhoinv + phi + psi ! w is the value of the secular function with ! its ii-th element removed. swtch3 = .false. if( orgati ) then if( w<zero )swtch3 = .true. else if( w>zero )swtch3 = .true. end if if( ii==1_${ik}$ .or. ii==n )swtch3 = .false. temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = w + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau )& *dw ! test for convergence if( abs( w )<=eps*erretm ) then if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step niter = niter + 1_${ik}$ if( .not.swtch3 ) then if( orgati ) then c = w - delta( ip1 )*dw - ( d( i )-d( ip1 ) )*( z( i ) / delta( i ) )& **2_${ik}$ else c = w - delta( i )*dw - ( d( ip1 )-d( i ) )*( z( ip1 ) / delta( ip1 ) )& **2_${ik}$ end if a = ( delta( i )+delta( ip1 ) )*w -delta( i )*delta( ip1 )*dw b = delta( i )*delta( ip1 )*w if( c==zero ) then if( a==zero ) then if( orgati ) then a = z( i )*z( i ) + delta( ip1 )*delta( ip1 )*( dpsi+dphi ) else a = z( ip1 )*z( ip1 ) + delta( i )*delta( i )*( dpsi+dphi ) end if end if eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if else ! interpolation using three most relevant poles temp = rhoinv + psi + phi if( orgati ) then temp1 = z( iim1 ) / delta( iim1 ) temp1 = temp1*temp1 c = temp - delta( iip1 )*( dpsi+dphi ) -( d( iim1 )-d( iip1 ) )*temp1 zz( 1_${ik}$ ) = z( iim1 )*z( iim1 ) zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*( ( dpsi-temp1 )+dphi ) else temp1 = z( iip1 ) / delta( iip1 ) temp1 = temp1*temp1 c = temp - delta( iim1 )*( dpsi+dphi ) -( d( iip1 )-d( iim1 ) )*temp1 zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*( dpsi+( dphi-temp1 ) ) zz( 3_${ik}$ ) = z( iip1 )*z( iip1 ) end if zz( 2_${ik}$ ) = z( ii )*z( ii ) call stdlib${ii}$_dlaed6( niter, orgati, c, delta( iim1 ), zz, w, eta,info ) if( info/=0 )go to 250 end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>=zero )eta = -w / dw temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if prew = w do j = 1, n delta( j ) = delta( j ) - eta end do ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = rhoinv + phi + psi + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau+eta )& *dw swtch = .false. if( orgati ) then if( -w>abs( prew ) / ten )swtch = .true. else if( w>abs( prew ) / ten )swtch = .true. end if tau = tau + eta ! main loop to update the values of the array delta iter = niter + 1_${ik}$ loop_240: do niter = iter, maxit ! test for convergence if( abs( w )<=eps*erretm ) then if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step if( .not.swtch3 ) then if( .not.swtch ) then if( orgati ) then c = w - delta( ip1 )*dw -( d( i )-d( ip1 ) )*( z( i ) / delta( i ) )& **2_${ik}$ else c = w - delta( i )*dw - ( d( ip1 )-d( i ) )*( z( ip1 ) / delta( ip1 ) )& **2_${ik}$ end if else temp = z( ii ) / delta( ii ) if( orgati ) then dpsi = dpsi + temp*temp else dphi = dphi + temp*temp end if c = w - delta( i )*dpsi - delta( ip1 )*dphi end if a = ( delta( i )+delta( ip1 ) )*w -delta( i )*delta( ip1 )*dw b = delta( i )*delta( ip1 )*w if( c==zero ) then if( a==zero ) then if( .not.swtch ) then if( orgati ) then a = z( i )*z( i ) + delta( ip1 )*delta( ip1 )*( dpsi+dphi ) else a = z( ip1 )*z( ip1 ) +delta( i )*delta( i )*( dpsi+dphi ) end if else a = delta( i )*delta( i )*dpsi +delta( ip1 )*delta( ip1 )& *dphi end if end if eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if else ! interpolation using three most relevant poles temp = rhoinv + psi + phi if( swtch ) then c = temp - delta( iim1 )*dpsi - delta( iip1 )*dphi zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*dpsi zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*dphi else if( orgati ) then temp1 = z( iim1 ) / delta( iim1 ) temp1 = temp1*temp1 c = temp - delta( iip1 )*( dpsi+dphi ) -( d( iim1 )-d( iip1 ) )& *temp1 zz( 1_${ik}$ ) = z( iim1 )*z( iim1 ) zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*( ( dpsi-temp1 )+dphi ) else temp1 = z( iip1 ) / delta( iip1 ) temp1 = temp1*temp1 c = temp - delta( iim1 )*( dpsi+dphi ) -( d( iip1 )-d( iim1 ) )& *temp1 zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*( dpsi+( dphi-temp1 ) ) zz( 3_${ik}$ ) = z( iip1 )*z( iip1 ) end if end if call stdlib${ii}$_dlaed6( niter, orgati, c, delta( iim1 ), zz, w, eta,info ) if( info/=0 )go to 250 end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>=zero )eta = -w / dw temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta prew = w ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = rhoinv + phi + psi + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau )& *dw if( w*prew>zero .and. abs( w )>abs( prew ) / ten )swtch = .not.swtch end do loop_240 ! return with info = 1, niter = maxit and not converged info = 1_${ik}$ if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if end if 250 continue return end subroutine stdlib${ii}$_dlaed4 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed4( n, i, d, z, delta, rho, dlam, info ) !! This subroutine computes the I-th updated eigenvalue of a symmetric !! rank-one modification to a diagonal matrix whose elements are !! given in the array d, and that !! D(i) < D(j) for i < j !! and that RHO > 0. This is arranged by the calling routine, and is !! no loss in generality. The rank-one modified system is thus !! diag( D ) + RHO * Z * Z_transpose. !! where we assume the Euclidean norm of Z is 1. !! The method consists of approximating the rational functions in the !! secular equation by simpler interpolating rational functions. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: i, n integer(${ik}$), intent(out) :: info real(${rk}$), intent(out) :: dlam real(${rk}$), intent(in) :: rho ! Array Arguments real(${rk}$), intent(in) :: d(*), z(*) real(${rk}$), intent(out) :: delta(*) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: maxit = 30_${ik}$ ! Local Scalars logical(lk) :: orgati, swtch, swtch3 integer(${ik}$) :: ii, iim1, iip1, ip1, iter, j, niter real(${rk}$) :: a, b, c, del, dltlb, dltub, dphi, dpsi, dw, eps, erretm, eta, midpt, phi, & prew, psi, rhoinv, tau, temp, temp1, w ! Local Arrays real(${rk}$) :: zz(3_${ik}$) ! Intrinsic Functions ! Executable Statements ! since this routine is called in an inner loop, we do no argument ! checking. ! quick return for n=1 and 2. info = 0_${ik}$ if( n==1_${ik}$ ) then ! presumably, i=1 upon entry dlam = d( 1_${ik}$ ) + rho*z( 1_${ik}$ )*z( 1_${ik}$ ) delta( 1_${ik}$ ) = one return end if if( n==2_${ik}$ ) then call stdlib${ii}$_${ri}$laed5( i, d, z, delta, rho, dlam ) return end if ! compute machine epsilon eps = stdlib${ii}$_${ri}$lamch( 'EPSILON' ) rhoinv = one / rho ! the case i = n if( i==n ) then ! initialize some basic variables ii = n - 1_${ik}$ niter = 1_${ik}$ ! calculate initial guess midpt = rho / two ! if ||z||_2 is not one, then temp should be set to ! rho * ||z||_2^2 / two do j = 1, n delta( j ) = ( d( j )-d( i ) ) - midpt end do psi = zero do j = 1, n - 2 psi = psi + z( j )*z( j ) / delta( j ) end do c = rhoinv + psi w = c + z( ii )*z( ii ) / delta( ii ) +z( n )*z( n ) / delta( n ) if( w<=zero ) then temp = z( n-1 )*z( n-1 ) / ( d( n )-d( n-1 )+rho ) +z( n )*z( n ) / rho if( c<=temp ) then tau = rho else del = d( n ) - d( n-1 ) a = -c*del + z( n-1 )*z( n-1 ) + z( n )*z( n ) b = z( n )*z( n )*del if( a<zero ) then tau = two*b / ( sqrt( a*a+four*b*c )-a ) else tau = ( a+sqrt( a*a+four*b*c ) ) / ( two*c ) end if end if ! it can be proved that ! d(n)+rho/2 <= lambda(n) < d(n)+tau <= d(n)+rho dltlb = midpt dltub = rho else del = d( n ) - d( n-1 ) a = -c*del + z( n-1 )*z( n-1 ) + z( n )*z( n ) b = z( n )*z( n )*del if( a<zero ) then tau = two*b / ( sqrt( a*a+four*b*c )-a ) else tau = ( a+sqrt( a*a+four*b*c ) ) / ( two*c ) end if ! it can be proved that ! d(n) < d(n)+tau < lambda(n) < d(n)+rho/2 dltlb = zero dltub = midpt end if do j = 1, n delta( j ) = ( d( j )-d( i ) ) - tau end do ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi ! test for convergence if( abs( w )<=eps*erretm ) then dlam = d( i ) + tau go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step niter = niter + 1_${ik}$ c = w - delta( n-1 )*dpsi - delta( n )*dphi a = ( delta( n-1 )+delta( n ) )*w -delta( n-1 )*delta( n )*( dpsi+dphi ) b = delta( n-1 )*delta( n )*w if( c<zero )c = abs( c ) if( c==zero ) then ! eta = b/a ! eta = rho - tau eta = dltub - tau else if( a>=zero ) then eta = ( a+sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a-sqrt( abs( a*a-four*b*c ) ) ) end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>zero )eta = -w / ( dpsi+dphi ) temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi ! main loop to update the values of the array delta iter = niter + 1_${ik}$ loop_90: do niter = iter, maxit ! test for convergence if( abs( w )<=eps*erretm ) then dlam = d( i ) + tau go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step c = w - delta( n-1 )*dpsi - delta( n )*dphi a = ( delta( n-1 )+delta( n ) )*w -delta( n-1 )*delta( n )*( dpsi+dphi ) b = delta( n-1 )*delta( n )*w if( a>=zero ) then eta = ( a+sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a-sqrt( abs( a*a-four*b*c ) ) ) end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>zero )eta = -w / ( dpsi+dphi ) temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, ii temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi temp = z( n ) / delta( n ) phi = z( n )*temp dphi = temp*temp erretm = eight*( -phi-psi ) + erretm - phi + rhoinv +abs( tau )*( dpsi+dphi ) w = rhoinv + phi + psi end do loop_90 ! return with info = 1, niter = maxit and not converged info = 1_${ik}$ dlam = d( i ) + tau go to 250 ! end for the case i = n else ! the case for i < n niter = 1_${ik}$ ip1 = i + 1_${ik}$ ! calculate initial guess del = d( ip1 ) - d( i ) midpt = del / two do j = 1, n delta( j ) = ( d( j )-d( i ) ) - midpt end do psi = zero do j = 1, i - 1 psi = psi + z( j )*z( j ) / delta( j ) end do phi = zero do j = n, i + 2, -1 phi = phi + z( j )*z( j ) / delta( j ) end do c = rhoinv + psi + phi w = c + z( i )*z( i ) / delta( i ) +z( ip1 )*z( ip1 ) / delta( ip1 ) if( w>zero ) then ! d(i)< the ith eigenvalue < (d(i)+d(i+1))/2 ! we choose d(i) as origin. orgati = .true. a = c*del + z( i )*z( i ) + z( ip1 )*z( ip1 ) b = z( i )*z( i )*del if( a>zero ) then tau = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) else tau = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) end if dltlb = zero dltub = midpt else ! (d(i)+d(i+1))/2 <= the ith eigenvalue < d(i+1) ! we choose d(i+1) as origin. orgati = .false. a = c*del - z( i )*z( i ) - z( ip1 )*z( ip1 ) b = z( ip1 )*z( ip1 )*del if( a<zero ) then tau = two*b / ( a-sqrt( abs( a*a+four*b*c ) ) ) else tau = -( a+sqrt( abs( a*a+four*b*c ) ) ) / ( two*c ) end if dltlb = -midpt dltub = zero end if if( orgati ) then do j = 1, n delta( j ) = ( d( j )-d( i ) ) - tau end do else do j = 1, n delta( j ) = ( d( j )-d( ip1 ) ) - tau end do end if if( orgati ) then ii = i else ii = i + 1_${ik}$ end if iim1 = ii - 1_${ik}$ iip1 = ii + 1_${ik}$ ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do w = rhoinv + phi + psi ! w is the value of the secular function with ! its ii-th element removed. swtch3 = .false. if( orgati ) then if( w<zero )swtch3 = .true. else if( w>zero )swtch3 = .true. end if if( ii==1_${ik}$ .or. ii==n )swtch3 = .false. temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = w + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau )& *dw ! test for convergence if( abs( w )<=eps*erretm ) then if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step niter = niter + 1_${ik}$ if( .not.swtch3 ) then if( orgati ) then c = w - delta( ip1 )*dw - ( d( i )-d( ip1 ) )*( z( i ) / delta( i ) )& **2_${ik}$ else c = w - delta( i )*dw - ( d( ip1 )-d( i ) )*( z( ip1 ) / delta( ip1 ) )& **2_${ik}$ end if a = ( delta( i )+delta( ip1 ) )*w -delta( i )*delta( ip1 )*dw b = delta( i )*delta( ip1 )*w if( c==zero ) then if( a==zero ) then if( orgati ) then a = z( i )*z( i ) + delta( ip1 )*delta( ip1 )*( dpsi+dphi ) else a = z( ip1 )*z( ip1 ) + delta( i )*delta( i )*( dpsi+dphi ) end if end if eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if else ! interpolation using three most relevant poles temp = rhoinv + psi + phi if( orgati ) then temp1 = z( iim1 ) / delta( iim1 ) temp1 = temp1*temp1 c = temp - delta( iip1 )*( dpsi+dphi ) -( d( iim1 )-d( iip1 ) )*temp1 zz( 1_${ik}$ ) = z( iim1 )*z( iim1 ) zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*( ( dpsi-temp1 )+dphi ) else temp1 = z( iip1 ) / delta( iip1 ) temp1 = temp1*temp1 c = temp - delta( iim1 )*( dpsi+dphi ) -( d( iip1 )-d( iim1 ) )*temp1 zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*( dpsi+( dphi-temp1 ) ) zz( 3_${ik}$ ) = z( iip1 )*z( iip1 ) end if zz( 2_${ik}$ ) = z( ii )*z( ii ) call stdlib${ii}$_${ri}$laed6( niter, orgati, c, delta( iim1 ), zz, w, eta,info ) if( info/=0 )go to 250 end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>=zero )eta = -w / dw temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if prew = w do j = 1, n delta( j ) = delta( j ) - eta end do ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = rhoinv + phi + psi + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau+eta )& *dw swtch = .false. if( orgati ) then if( -w>abs( prew ) / ten )swtch = .true. else if( w>abs( prew ) / ten )swtch = .true. end if tau = tau + eta ! main loop to update the values of the array delta iter = niter + 1_${ik}$ loop_240: do niter = iter, maxit ! test for convergence if( abs( w )<=eps*erretm ) then if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if go to 250 end if if( w<=zero ) then dltlb = max( dltlb, tau ) else dltub = min( dltub, tau ) end if ! calculate the new step if( .not.swtch3 ) then if( .not.swtch ) then if( orgati ) then c = w - delta( ip1 )*dw -( d( i )-d( ip1 ) )*( z( i ) / delta( i ) )& **2_${ik}$ else c = w - delta( i )*dw - ( d( ip1 )-d( i ) )*( z( ip1 ) / delta( ip1 ) )& **2_${ik}$ end if else temp = z( ii ) / delta( ii ) if( orgati ) then dpsi = dpsi + temp*temp else dphi = dphi + temp*temp end if c = w - delta( i )*dpsi - delta( ip1 )*dphi end if a = ( delta( i )+delta( ip1 ) )*w -delta( i )*delta( ip1 )*dw b = delta( i )*delta( ip1 )*w if( c==zero ) then if( a==zero ) then if( .not.swtch ) then if( orgati ) then a = z( i )*z( i ) + delta( ip1 )*delta( ip1 )*( dpsi+dphi ) else a = z( ip1 )*z( ip1 ) +delta( i )*delta( i )*( dpsi+dphi ) end if else a = delta( i )*delta( i )*dpsi +delta( ip1 )*delta( ip1 )& *dphi end if end if eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if else ! interpolation using three most relevant poles temp = rhoinv + psi + phi if( swtch ) then c = temp - delta( iim1 )*dpsi - delta( iip1 )*dphi zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*dpsi zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*dphi else if( orgati ) then temp1 = z( iim1 ) / delta( iim1 ) temp1 = temp1*temp1 c = temp - delta( iip1 )*( dpsi+dphi ) -( d( iim1 )-d( iip1 ) )& *temp1 zz( 1_${ik}$ ) = z( iim1 )*z( iim1 ) zz( 3_${ik}$ ) = delta( iip1 )*delta( iip1 )*( ( dpsi-temp1 )+dphi ) else temp1 = z( iip1 ) / delta( iip1 ) temp1 = temp1*temp1 c = temp - delta( iim1 )*( dpsi+dphi ) -( d( iip1 )-d( iim1 ) )& *temp1 zz( 1_${ik}$ ) = delta( iim1 )*delta( iim1 )*( dpsi+( dphi-temp1 ) ) zz( 3_${ik}$ ) = z( iip1 )*z( iip1 ) end if end if call stdlib${ii}$_${ri}$laed6( niter, orgati, c, delta( iim1 ), zz, w, eta,info ) if( info/=0 )go to 250 end if ! note, eta should be positive if w is negative, and ! eta should be negative otherwise. however, ! if for some reason caused by roundoff, eta*w > 0, ! we simply use one newton step instead. this way ! will guarantee eta*w < 0. if( w*eta>=zero )eta = -w / dw temp = tau + eta if( temp>dltub .or. temp<dltlb ) then if( w<zero ) then eta = ( dltub-tau ) / two else eta = ( dltlb-tau ) / two end if end if do j = 1, n delta( j ) = delta( j ) - eta end do tau = tau + eta prew = w ! evaluate psi and the derivative dpsi dpsi = zero psi = zero erretm = zero do j = 1, iim1 temp = z( j ) / delta( j ) psi = psi + z( j )*temp dpsi = dpsi + temp*temp erretm = erretm + psi end do erretm = abs( erretm ) ! evaluate phi and the derivative dphi dphi = zero phi = zero do j = n, iip1, -1 temp = z( j ) / delta( j ) phi = phi + z( j )*temp dphi = dphi + temp*temp erretm = erretm + phi end do temp = z( ii ) / delta( ii ) dw = dpsi + dphi + temp*temp temp = z( ii )*temp w = rhoinv + phi + psi + temp erretm = eight*( phi-psi ) + erretm + two*rhoinv +three*abs( temp ) + abs( tau )& *dw if( w*prew>zero .and. abs( w )>abs( prew ) / ten )swtch = .not.swtch end do loop_240 ! return with info = 1, niter = maxit and not converged info = 1_${ik}$ if( orgati ) then dlam = d( i ) + tau else dlam = d( ip1 ) + tau end if end if 250 continue return end subroutine stdlib${ii}$_${ri}$laed4 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed5( i, d, z, delta, rho, dlam ) !! This subroutine computes the I-th eigenvalue of a symmetric rank-one !! modification of a 2-by-2 diagonal matrix !! diag( D ) + RHO * Z * transpose(Z) . !! The diagonal elements in the array D are assumed to satisfy !! D(i) < D(j) for i < j . !! We also assume RHO > 0 and that the Euclidean norm of the vector !! Z is one. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: i real(sp), intent(out) :: dlam real(sp), intent(in) :: rho ! Array Arguments real(sp), intent(in) :: d(2_${ik}$), z(2_${ik}$) real(sp), intent(out) :: delta(2_${ik}$) ! ===================================================================== ! Local Scalars real(sp) :: b, c, del, tau, temp, w ! Intrinsic Functions ! Executable Statements del = d( 2_${ik}$ ) - d( 1_${ik}$ ) if( i==1_${ik}$ ) then w = one + two*rho*( z( 2_${ik}$ )*z( 2_${ik}$ )-z( 1_${ik}$ )*z( 1_${ik}$ ) ) / del if( w>zero ) then b = del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 1_${ik}$ )*z( 1_${ik}$ )*del ! b > zero, always tau = two*c / ( b+sqrt( abs( b*b-four*c ) ) ) dlam = d( 1_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / tau delta( 2_${ik}$ ) = z( 2_${ik}$ ) / ( del-tau ) else b = -del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 2_${ik}$ )*z( 2_${ik}$ )*del if( b>zero ) then tau = -two*c / ( b+sqrt( b*b+four*c ) ) else tau = ( b-sqrt( b*b+four*c ) ) / two end if dlam = d( 2_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / ( del+tau ) delta( 2_${ik}$ ) = -z( 2_${ik}$ ) / tau end if temp = sqrt( delta( 1_${ik}$ )*delta( 1_${ik}$ )+delta( 2_${ik}$ )*delta( 2_${ik}$ ) ) delta( 1_${ik}$ ) = delta( 1_${ik}$ ) / temp delta( 2_${ik}$ ) = delta( 2_${ik}$ ) / temp else ! now i=2 b = -del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 2_${ik}$ )*z( 2_${ik}$ )*del if( b>zero ) then tau = ( b+sqrt( b*b+four*c ) ) / two else tau = two*c / ( -b+sqrt( b*b+four*c ) ) end if dlam = d( 2_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / ( del+tau ) delta( 2_${ik}$ ) = -z( 2_${ik}$ ) / tau temp = sqrt( delta( 1_${ik}$ )*delta( 1_${ik}$ )+delta( 2_${ik}$ )*delta( 2_${ik}$ ) ) delta( 1_${ik}$ ) = delta( 1_${ik}$ ) / temp delta( 2_${ik}$ ) = delta( 2_${ik}$ ) / temp end if return end subroutine stdlib${ii}$_slaed5 pure module subroutine stdlib${ii}$_dlaed5( i, d, z, delta, rho, dlam ) !! This subroutine computes the I-th eigenvalue of a symmetric rank-one !! modification of a 2-by-2 diagonal matrix !! diag( D ) + RHO * Z * transpose(Z) . !! The diagonal elements in the array D are assumed to satisfy !! D(i) < D(j) for i < j . !! We also assume RHO > 0 and that the Euclidean norm of the vector !! Z is one. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: i real(dp), intent(out) :: dlam real(dp), intent(in) :: rho ! Array Arguments real(dp), intent(in) :: d(2_${ik}$), z(2_${ik}$) real(dp), intent(out) :: delta(2_${ik}$) ! ===================================================================== ! Local Scalars real(dp) :: b, c, del, tau, temp, w ! Intrinsic Functions ! Executable Statements del = d( 2_${ik}$ ) - d( 1_${ik}$ ) if( i==1_${ik}$ ) then w = one + two*rho*( z( 2_${ik}$ )*z( 2_${ik}$ )-z( 1_${ik}$ )*z( 1_${ik}$ ) ) / del if( w>zero ) then b = del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 1_${ik}$ )*z( 1_${ik}$ )*del ! b > zero, always tau = two*c / ( b+sqrt( abs( b*b-four*c ) ) ) dlam = d( 1_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / tau delta( 2_${ik}$ ) = z( 2_${ik}$ ) / ( del-tau ) else b = -del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 2_${ik}$ )*z( 2_${ik}$ )*del if( b>zero ) then tau = -two*c / ( b+sqrt( b*b+four*c ) ) else tau = ( b-sqrt( b*b+four*c ) ) / two end if dlam = d( 2_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / ( del+tau ) delta( 2_${ik}$ ) = -z( 2_${ik}$ ) / tau end if temp = sqrt( delta( 1_${ik}$ )*delta( 1_${ik}$ )+delta( 2_${ik}$ )*delta( 2_${ik}$ ) ) delta( 1_${ik}$ ) = delta( 1_${ik}$ ) / temp delta( 2_${ik}$ ) = delta( 2_${ik}$ ) / temp else ! now i=2 b = -del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 2_${ik}$ )*z( 2_${ik}$ )*del if( b>zero ) then tau = ( b+sqrt( b*b+four*c ) ) / two else tau = two*c / ( -b+sqrt( b*b+four*c ) ) end if dlam = d( 2_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / ( del+tau ) delta( 2_${ik}$ ) = -z( 2_${ik}$ ) / tau temp = sqrt( delta( 1_${ik}$ )*delta( 1_${ik}$ )+delta( 2_${ik}$ )*delta( 2_${ik}$ ) ) delta( 1_${ik}$ ) = delta( 1_${ik}$ ) / temp delta( 2_${ik}$ ) = delta( 2_${ik}$ ) / temp end if return end subroutine stdlib${ii}$_dlaed5 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed5( i, d, z, delta, rho, dlam ) !! This subroutine computes the I-th eigenvalue of a symmetric rank-one !! modification of a 2-by-2 diagonal matrix !! diag( D ) + RHO * Z * transpose(Z) . !! The diagonal elements in the array D are assumed to satisfy !! D(i) < D(j) for i < j . !! We also assume RHO > 0 and that the Euclidean norm of the vector !! Z is one. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: i real(${rk}$), intent(out) :: dlam real(${rk}$), intent(in) :: rho ! Array Arguments real(${rk}$), intent(in) :: d(2_${ik}$), z(2_${ik}$) real(${rk}$), intent(out) :: delta(2_${ik}$) ! ===================================================================== ! Local Scalars real(${rk}$) :: b, c, del, tau, temp, w ! Intrinsic Functions ! Executable Statements del = d( 2_${ik}$ ) - d( 1_${ik}$ ) if( i==1_${ik}$ ) then w = one + two*rho*( z( 2_${ik}$ )*z( 2_${ik}$ )-z( 1_${ik}$ )*z( 1_${ik}$ ) ) / del if( w>zero ) then b = del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 1_${ik}$ )*z( 1_${ik}$ )*del ! b > zero, always tau = two*c / ( b+sqrt( abs( b*b-four*c ) ) ) dlam = d( 1_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / tau delta( 2_${ik}$ ) = z( 2_${ik}$ ) / ( del-tau ) else b = -del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 2_${ik}$ )*z( 2_${ik}$ )*del if( b>zero ) then tau = -two*c / ( b+sqrt( b*b+four*c ) ) else tau = ( b-sqrt( b*b+four*c ) ) / two end if dlam = d( 2_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / ( del+tau ) delta( 2_${ik}$ ) = -z( 2_${ik}$ ) / tau end if temp = sqrt( delta( 1_${ik}$ )*delta( 1_${ik}$ )+delta( 2_${ik}$ )*delta( 2_${ik}$ ) ) delta( 1_${ik}$ ) = delta( 1_${ik}$ ) / temp delta( 2_${ik}$ ) = delta( 2_${ik}$ ) / temp else ! now i=2 b = -del + rho*( z( 1_${ik}$ )*z( 1_${ik}$ )+z( 2_${ik}$ )*z( 2_${ik}$ ) ) c = rho*z( 2_${ik}$ )*z( 2_${ik}$ )*del if( b>zero ) then tau = ( b+sqrt( b*b+four*c ) ) / two else tau = two*c / ( -b+sqrt( b*b+four*c ) ) end if dlam = d( 2_${ik}$ ) + tau delta( 1_${ik}$ ) = -z( 1_${ik}$ ) / ( del+tau ) delta( 2_${ik}$ ) = -z( 2_${ik}$ ) / tau temp = sqrt( delta( 1_${ik}$ )*delta( 1_${ik}$ )+delta( 2_${ik}$ )*delta( 2_${ik}$ ) ) delta( 1_${ik}$ ) = delta( 1_${ik}$ ) / temp delta( 2_${ik}$ ) = delta( 2_${ik}$ ) / temp end if return end subroutine stdlib${ii}$_${ri}$laed5 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed6( kniter, orgati, rho, d, z, finit, tau, info ) !! SLAED6 computes the positive or negative root (closest to the origin) !! of !! z(1) z(2) z(3) !! f(x) = rho + --------- + ---------- + --------- !! d(1)-x d(2)-x d(3)-x !! It is assumed that !! if ORGATI = .true. the root is between d(2) and d(3); !! otherwise it is between d(1) and d(2) !! This routine will be called by SLAED4 when necessary. In most cases, !! the root sought is the smallest in magnitude, though it might not be !! in some extremely rare situations. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments logical(lk), intent(in) :: orgati integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: kniter real(sp), intent(in) :: finit, rho real(sp), intent(out) :: tau ! Array Arguments real(sp), intent(in) :: d(3_${ik}$), z(3_${ik}$) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: maxit = 40_${ik}$ ! Local Arrays real(sp) :: dscale(3_${ik}$), zscale(3_${ik}$) ! Local Scalars logical(lk) :: scale integer(${ik}$) :: i, iter, niter real(sp) :: a, b, base, c, ddf, df, eps, erretm, eta, f, fc, sclfac, sclinv, small1, & small2, sminv1, sminv2, temp, temp1, temp2, temp3, temp4, lbd, ubd ! Intrinsic Functions ! Executable Statements info = 0_${ik}$ if( orgati ) then lbd = d(2_${ik}$) ubd = d(3_${ik}$) else lbd = d(1_${ik}$) ubd = d(2_${ik}$) end if if( finit < zero )then lbd = zero else ubd = zero end if niter = 1_${ik}$ tau = zero if( kniter==2_${ik}$ ) then if( orgati ) then temp = ( d( 3_${ik}$ )-d( 2_${ik}$ ) ) / two c = rho + z( 1_${ik}$ ) / ( ( d( 1_${ik}$ )-d( 2_${ik}$ ) )-temp ) a = c*( d( 2_${ik}$ )+d( 3_${ik}$ ) ) + z( 2_${ik}$ ) + z( 3_${ik}$ ) b = c*d( 2_${ik}$ )*d( 3_${ik}$ ) + z( 2_${ik}$ )*d( 3_${ik}$ ) + z( 3_${ik}$ )*d( 2_${ik}$ ) else temp = ( d( 1_${ik}$ )-d( 2_${ik}$ ) ) / two c = rho + z( 3_${ik}$ ) / ( ( d( 3_${ik}$ )-d( 2_${ik}$ ) )-temp ) a = c*( d( 1_${ik}$ )+d( 2_${ik}$ ) ) + z( 1_${ik}$ ) + z( 2_${ik}$ ) b = c*d( 1_${ik}$ )*d( 2_${ik}$ ) + z( 1_${ik}$ )*d( 2_${ik}$ ) + z( 2_${ik}$ )*d( 1_${ik}$ ) end if temp = max( abs( a ), abs( b ), abs( c ) ) a = a / temp b = b / temp c = c / temp if( c==zero ) then tau = b / a else if( a<=zero ) then tau = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else tau = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if if( tau < lbd .or. tau > ubd )tau = ( lbd+ubd )/two if( d(1_${ik}$)==tau .or. d(2_${ik}$)==tau .or. d(3_${ik}$)==tau ) then tau = zero else temp = finit + tau*z(1_${ik}$)/( d(1_${ik}$)*( d( 1_${ik}$ )-tau ) ) +tau*z(2_${ik}$)/( d(2_${ik}$)*( d( 2_${ik}$ )-tau ) )& +tau*z(3_${ik}$)/( d(3_${ik}$)*( d( 3_${ik}$ )-tau ) ) if( temp <= zero )then lbd = tau else ubd = tau end if if( abs( finit )<=abs( temp ) )tau = zero end if end if ! get machine parameters for possible scaling to avoid overflow ! modified by sven: parameters small1, sminv1, small2, ! sminv2, eps are not saved anymore between one call to the ! others but recomputed at each call eps = stdlib${ii}$_slamch( 'EPSILON' ) base = stdlib${ii}$_slamch( 'BASE' ) small1 = base**( int( log( stdlib${ii}$_slamch( 'SAFMIN' ) ) / log( base ) /three,KIND=${ik}$) ) sminv1 = one / small1 small2 = small1*small1 sminv2 = sminv1*sminv1 ! determine if scaling of inputs necessary to avoid overflow ! when computing 1/temp**3 if( orgati ) then temp = min( abs( d( 2_${ik}$ )-tau ), abs( d( 3_${ik}$ )-tau ) ) else temp = min( abs( d( 1_${ik}$ )-tau ), abs( d( 2_${ik}$ )-tau ) ) end if scale = .false. if( temp<=small1 ) then scale = .true. if( temp<=small2 ) then ! scale up by power of radix nearest 1/safmin**(2/3) sclfac = sminv2 sclinv = small2 else ! scale up by power of radix nearest 1/safmin**(1/3) sclfac = sminv1 sclinv = small1 end if ! scaling up safe because d, z, tau scaled elsewhere to be o(1) do i = 1, 3 dscale( i ) = d( i )*sclfac zscale( i ) = z( i )*sclfac end do tau = tau*sclfac lbd = lbd*sclfac ubd = ubd*sclfac else ! copy d and z to dscale and zscale do i = 1, 3 dscale( i ) = d( i ) zscale( i ) = z( i ) end do end if fc = zero df = zero ddf = zero do i = 1, 3 temp = one / ( dscale( i )-tau ) temp1 = zscale( i )*temp temp2 = temp1*temp temp3 = temp2*temp fc = fc + temp1 / dscale( i ) df = df + temp2 ddf = ddf + temp3 end do f = finit + tau*fc if( abs( f )<=zero )go to 60 if( f <= zero )then lbd = tau else ubd = tau end if ! iteration begins -- use gragg-thornton-warner cubic convergent ! scheme ! it is not hard to see that ! 1) iterations will go up monotonically ! if finit < 0; ! 2) iterations will go down monotonically ! if finit > 0. iter = niter + 1_${ik}$ loop_50: do niter = iter, maxit if( orgati ) then temp1 = dscale( 2_${ik}$ ) - tau temp2 = dscale( 3_${ik}$ ) - tau else temp1 = dscale( 1_${ik}$ ) - tau temp2 = dscale( 2_${ik}$ ) - tau end if a = ( temp1+temp2 )*f - temp1*temp2*df b = temp1*temp2*f c = f - ( temp1+temp2 )*df + temp1*temp2*ddf temp = max( abs( a ), abs( b ), abs( c ) ) a = a / temp b = b / temp c = c / temp if( c==zero ) then eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if if( f*eta>=zero ) then eta = -f / df end if tau = tau + eta if( tau < lbd .or. tau > ubd )tau = ( lbd + ubd )/two fc = zero erretm = zero df = zero ddf = zero do i = 1, 3 if ( ( dscale( i )-tau )/=zero ) then temp = one / ( dscale( i )-tau ) temp1 = zscale( i )*temp temp2 = temp1*temp temp3 = temp2*temp temp4 = temp1 / dscale( i ) fc = fc + temp4 erretm = erretm + abs( temp4 ) df = df + temp2 ddf = ddf + temp3 else go to 60 end if end do f = finit + tau*fc erretm = eight*( abs( finit )+abs( tau )*erretm ) +abs( tau )*df if( ( abs( f )<=four*eps*erretm ) .or.( (ubd-lbd)<=four*eps*abs(tau) ) )go to 60 if( f <= zero )then lbd = tau else ubd = tau end if end do loop_50 info = 1_${ik}$ 60 continue ! undo scaling if( scale )tau = tau*sclinv return end subroutine stdlib${ii}$_slaed6 pure module subroutine stdlib${ii}$_dlaed6( kniter, orgati, rho, d, z, finit, tau, info ) !! DLAED6 computes the positive or negative root (closest to the origin) !! of !! z(1) z(2) z(3) !! f(x) = rho + --------- + ---------- + --------- !! d(1)-x d(2)-x d(3)-x !! It is assumed that !! if ORGATI = .true. the root is between d(2) and d(3); !! otherwise it is between d(1) and d(2) !! This routine will be called by DLAED4 when necessary. In most cases, !! the root sought is the smallest in magnitude, though it might not be !! in some extremely rare situations. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments logical(lk), intent(in) :: orgati integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: kniter real(dp), intent(in) :: finit, rho real(dp), intent(out) :: tau ! Array Arguments real(dp), intent(in) :: d(3_${ik}$), z(3_${ik}$) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: maxit = 40_${ik}$ ! Local Arrays real(dp) :: dscale(3_${ik}$), zscale(3_${ik}$) ! Local Scalars logical(lk) :: scale integer(${ik}$) :: i, iter, niter real(dp) :: a, b, base, c, ddf, df, eps, erretm, eta, f, fc, sclfac, sclinv, small1, & small2, sminv1, sminv2, temp, temp1, temp2, temp3, temp4, lbd, ubd ! Intrinsic Functions ! Executable Statements info = 0_${ik}$ if( orgati ) then lbd = d(2_${ik}$) ubd = d(3_${ik}$) else lbd = d(1_${ik}$) ubd = d(2_${ik}$) end if if( finit < zero )then lbd = zero else ubd = zero end if niter = 1_${ik}$ tau = zero if( kniter==2_${ik}$ ) then if( orgati ) then temp = ( d( 3_${ik}$ )-d( 2_${ik}$ ) ) / two c = rho + z( 1_${ik}$ ) / ( ( d( 1_${ik}$ )-d( 2_${ik}$ ) )-temp ) a = c*( d( 2_${ik}$ )+d( 3_${ik}$ ) ) + z( 2_${ik}$ ) + z( 3_${ik}$ ) b = c*d( 2_${ik}$ )*d( 3_${ik}$ ) + z( 2_${ik}$ )*d( 3_${ik}$ ) + z( 3_${ik}$ )*d( 2_${ik}$ ) else temp = ( d( 1_${ik}$ )-d( 2_${ik}$ ) ) / two c = rho + z( 3_${ik}$ ) / ( ( d( 3_${ik}$ )-d( 2_${ik}$ ) )-temp ) a = c*( d( 1_${ik}$ )+d( 2_${ik}$ ) ) + z( 1_${ik}$ ) + z( 2_${ik}$ ) b = c*d( 1_${ik}$ )*d( 2_${ik}$ ) + z( 1_${ik}$ )*d( 2_${ik}$ ) + z( 2_${ik}$ )*d( 1_${ik}$ ) end if temp = max( abs( a ), abs( b ), abs( c ) ) a = a / temp b = b / temp c = c / temp if( c==zero ) then tau = b / a else if( a<=zero ) then tau = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else tau = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if if( tau < lbd .or. tau > ubd )tau = ( lbd+ubd )/two if( d(1_${ik}$)==tau .or. d(2_${ik}$)==tau .or. d(3_${ik}$)==tau ) then tau = zero else temp = finit + tau*z(1_${ik}$)/( d(1_${ik}$)*( d( 1_${ik}$ )-tau ) ) +tau*z(2_${ik}$)/( d(2_${ik}$)*( d( 2_${ik}$ )-tau ) )& +tau*z(3_${ik}$)/( d(3_${ik}$)*( d( 3_${ik}$ )-tau ) ) if( temp <= zero )then lbd = tau else ubd = tau end if if( abs( finit )<=abs( temp ) )tau = zero end if end if ! get machine parameters for possible scaling to avoid overflow ! modified by sven: parameters small1, sminv1, small2, ! sminv2, eps are not saved anymore between one call to the ! others but recomputed at each call eps = stdlib${ii}$_dlamch( 'EPSILON' ) base = stdlib${ii}$_dlamch( 'BASE' ) small1 = base**( int( log( stdlib${ii}$_dlamch( 'SAFMIN' ) ) / log( base ) /three,KIND=${ik}$) ) sminv1 = one / small1 small2 = small1*small1 sminv2 = sminv1*sminv1 ! determine if scaling of inputs necessary to avoid overflow ! when computing 1/temp**3 if( orgati ) then temp = min( abs( d( 2_${ik}$ )-tau ), abs( d( 3_${ik}$ )-tau ) ) else temp = min( abs( d( 1_${ik}$ )-tau ), abs( d( 2_${ik}$ )-tau ) ) end if scale = .false. if( temp<=small1 ) then scale = .true. if( temp<=small2 ) then ! scale up by power of radix nearest 1/safmin**(2/3) sclfac = sminv2 sclinv = small2 else ! scale up by power of radix nearest 1/safmin**(1/3) sclfac = sminv1 sclinv = small1 end if ! scaling up safe because d, z, tau scaled elsewhere to be o(1) do i = 1, 3 dscale( i ) = d( i )*sclfac zscale( i ) = z( i )*sclfac end do tau = tau*sclfac lbd = lbd*sclfac ubd = ubd*sclfac else ! copy d and z to dscale and zscale do i = 1, 3 dscale( i ) = d( i ) zscale( i ) = z( i ) end do end if fc = zero df = zero ddf = zero do i = 1, 3 temp = one / ( dscale( i )-tau ) temp1 = zscale( i )*temp temp2 = temp1*temp temp3 = temp2*temp fc = fc + temp1 / dscale( i ) df = df + temp2 ddf = ddf + temp3 end do f = finit + tau*fc if( abs( f )<=zero )go to 60 if( f <= zero )then lbd = tau else ubd = tau end if ! iteration begins -- use gragg-thornton-warner cubic convergent ! scheme ! it is not hard to see that ! 1) iterations will go up monotonically ! if finit < 0; ! 2) iterations will go down monotonically ! if finit > 0. iter = niter + 1_${ik}$ loop_50: do niter = iter, maxit if( orgati ) then temp1 = dscale( 2_${ik}$ ) - tau temp2 = dscale( 3_${ik}$ ) - tau else temp1 = dscale( 1_${ik}$ ) - tau temp2 = dscale( 2_${ik}$ ) - tau end if a = ( temp1+temp2 )*f - temp1*temp2*df b = temp1*temp2*f c = f - ( temp1+temp2 )*df + temp1*temp2*ddf temp = max( abs( a ), abs( b ), abs( c ) ) a = a / temp b = b / temp c = c / temp if( c==zero ) then eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if if( f*eta>=zero ) then eta = -f / df end if tau = tau + eta if( tau < lbd .or. tau > ubd )tau = ( lbd + ubd )/two fc = zero erretm = zero df = zero ddf = zero do i = 1, 3 if ( ( dscale( i )-tau )/=zero ) then temp = one / ( dscale( i )-tau ) temp1 = zscale( i )*temp temp2 = temp1*temp temp3 = temp2*temp temp4 = temp1 / dscale( i ) fc = fc + temp4 erretm = erretm + abs( temp4 ) df = df + temp2 ddf = ddf + temp3 else go to 60 end if end do f = finit + tau*fc erretm = eight*( abs( finit )+abs( tau )*erretm ) +abs( tau )*df if( ( abs( f )<=four*eps*erretm ) .or.( (ubd-lbd)<=four*eps*abs(tau) ) ) go to 60 if( f <= zero )then lbd = tau else ubd = tau end if end do loop_50 info = 1_${ik}$ 60 continue ! undo scaling if( scale )tau = tau*sclinv return end subroutine stdlib${ii}$_dlaed6 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed6( kniter, orgati, rho, d, z, finit, tau, info ) !! DLAED6: computes the positive or negative root (closest to the origin) !! of !! z(1) z(2) z(3) !! f(x) = rho + --------- + ---------- + --------- !! d(1)-x d(2)-x d(3)-x !! It is assumed that !! if ORGATI = .true. the root is between d(2) and d(3); !! otherwise it is between d(1) and d(2) !! This routine will be called by DLAED4 when necessary. In most cases, !! the root sought is the smallest in magnitude, though it might not be !! in some extremely rare situations. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments logical(lk), intent(in) :: orgati integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: kniter real(${rk}$), intent(in) :: finit, rho real(${rk}$), intent(out) :: tau ! Array Arguments real(${rk}$), intent(in) :: d(3_${ik}$), z(3_${ik}$) ! ===================================================================== ! Parameters integer(${ik}$), parameter :: maxit = 40_${ik}$ ! Local Arrays real(${rk}$) :: dscale(3_${ik}$), zscale(3_${ik}$) ! Local Scalars logical(lk) :: scale integer(${ik}$) :: i, iter, niter real(${rk}$) :: a, b, base, c, ddf, df, eps, erretm, eta, f, fc, sclfac, sclinv, small1, & small2, sminv1, sminv2, temp, temp1, temp2, temp3, temp4, lbd, ubd ! Intrinsic Functions ! Executable Statements info = 0_${ik}$ if( orgati ) then lbd = d(2_${ik}$) ubd = d(3_${ik}$) else lbd = d(1_${ik}$) ubd = d(2_${ik}$) end if if( finit < zero )then lbd = zero else ubd = zero end if niter = 1_${ik}$ tau = zero if( kniter==2_${ik}$ ) then if( orgati ) then temp = ( d( 3_${ik}$ )-d( 2_${ik}$ ) ) / two c = rho + z( 1_${ik}$ ) / ( ( d( 1_${ik}$ )-d( 2_${ik}$ ) )-temp ) a = c*( d( 2_${ik}$ )+d( 3_${ik}$ ) ) + z( 2_${ik}$ ) + z( 3_${ik}$ ) b = c*d( 2_${ik}$ )*d( 3_${ik}$ ) + z( 2_${ik}$ )*d( 3_${ik}$ ) + z( 3_${ik}$ )*d( 2_${ik}$ ) else temp = ( d( 1_${ik}$ )-d( 2_${ik}$ ) ) / two c = rho + z( 3_${ik}$ ) / ( ( d( 3_${ik}$ )-d( 2_${ik}$ ) )-temp ) a = c*( d( 1_${ik}$ )+d( 2_${ik}$ ) ) + z( 1_${ik}$ ) + z( 2_${ik}$ ) b = c*d( 1_${ik}$ )*d( 2_${ik}$ ) + z( 1_${ik}$ )*d( 2_${ik}$ ) + z( 2_${ik}$ )*d( 1_${ik}$ ) end if temp = max( abs( a ), abs( b ), abs( c ) ) a = a / temp b = b / temp c = c / temp if( c==zero ) then tau = b / a else if( a<=zero ) then tau = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else tau = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if if( tau < lbd .or. tau > ubd )tau = ( lbd+ubd )/two if( d(1_${ik}$)==tau .or. d(2_${ik}$)==tau .or. d(3_${ik}$)==tau ) then tau = zero else temp = finit + tau*z(1_${ik}$)/( d(1_${ik}$)*( d( 1_${ik}$ )-tau ) ) +tau*z(2_${ik}$)/( d(2_${ik}$)*( d( 2_${ik}$ )-tau ) )& +tau*z(3_${ik}$)/( d(3_${ik}$)*( d( 3_${ik}$ )-tau ) ) if( temp <= zero )then lbd = tau else ubd = tau end if if( abs( finit )<=abs( temp ) )tau = zero end if end if ! get machine parameters for possible scaling to avoid overflow ! modified by sven: parameters small1, sminv1, small2, ! sminv2, eps are not saved anymore between one call to the ! others but recomputed at each call eps = stdlib${ii}$_${ri}$lamch( 'EPSILON' ) base = stdlib${ii}$_${ri}$lamch( 'BASE' ) small1 = base**( int( log( stdlib${ii}$_${ri}$lamch( 'SAFMIN' ) ) / log( base ) /three,KIND=${ik}$) ) sminv1 = one / small1 small2 = small1*small1 sminv2 = sminv1*sminv1 ! determine if scaling of inputs necessary to avoid overflow ! when computing 1/temp**3 if( orgati ) then temp = min( abs( d( 2_${ik}$ )-tau ), abs( d( 3_${ik}$ )-tau ) ) else temp = min( abs( d( 1_${ik}$ )-tau ), abs( d( 2_${ik}$ )-tau ) ) end if scale = .false. if( temp<=small1 ) then scale = .true. if( temp<=small2 ) then ! scale up by power of radix nearest 1/safmin**(2/3) sclfac = sminv2 sclinv = small2 else ! scale up by power of radix nearest 1/safmin**(1/3) sclfac = sminv1 sclinv = small1 end if ! scaling up safe because d, z, tau scaled elsewhere to be o(1) do i = 1, 3 dscale( i ) = d( i )*sclfac zscale( i ) = z( i )*sclfac end do tau = tau*sclfac lbd = lbd*sclfac ubd = ubd*sclfac else ! copy d and z to dscale and zscale do i = 1, 3 dscale( i ) = d( i ) zscale( i ) = z( i ) end do end if fc = zero df = zero ddf = zero do i = 1, 3 temp = one / ( dscale( i )-tau ) temp1 = zscale( i )*temp temp2 = temp1*temp temp3 = temp2*temp fc = fc + temp1 / dscale( i ) df = df + temp2 ddf = ddf + temp3 end do f = finit + tau*fc if( abs( f )<=zero )go to 60 if( f <= zero )then lbd = tau else ubd = tau end if ! iteration begins -- use gragg-thornton-warner cubic convergent ! scheme ! it is not hard to see that ! 1) iterations will go up monotonically ! if finit < 0; ! 2) iterations will go down monotonically ! if finit > 0. iter = niter + 1_${ik}$ loop_50: do niter = iter, maxit if( orgati ) then temp1 = dscale( 2_${ik}$ ) - tau temp2 = dscale( 3_${ik}$ ) - tau else temp1 = dscale( 1_${ik}$ ) - tau temp2 = dscale( 2_${ik}$ ) - tau end if a = ( temp1+temp2 )*f - temp1*temp2*df b = temp1*temp2*f c = f - ( temp1+temp2 )*df + temp1*temp2*ddf temp = max( abs( a ), abs( b ), abs( c ) ) a = a / temp b = b / temp c = c / temp if( c==zero ) then eta = b / a else if( a<=zero ) then eta = ( a-sqrt( abs( a*a-four*b*c ) ) ) / ( two*c ) else eta = two*b / ( a+sqrt( abs( a*a-four*b*c ) ) ) end if if( f*eta>=zero ) then eta = -f / df end if tau = tau + eta if( tau < lbd .or. tau > ubd )tau = ( lbd + ubd )/two fc = zero erretm = zero df = zero ddf = zero do i = 1, 3 if ( ( dscale( i )-tau )/=zero ) then temp = one / ( dscale( i )-tau ) temp1 = zscale( i )*temp temp2 = temp1*temp temp3 = temp2*temp temp4 = temp1 / dscale( i ) fc = fc + temp4 erretm = erretm + abs( temp4 ) df = df + temp2 ddf = ddf + temp3 else go to 60 end if end do f = finit + tau*fc erretm = eight*( abs( finit )+abs( tau )*erretm ) +abs( tau )*df if( ( abs( f )<=four*eps*erretm ) .or.( (ubd-lbd)<=four*eps*abs(tau) ) ) goto 60 if( f <= zero )then lbd = tau else ubd = tau end if end do loop_50 info = 1_${ik}$ 60 continue ! undo scaling if( scale )tau = tau*sclinv return end subroutine stdlib${ii}$_${ri}$laed6 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed7( icompq, n, qsiz, tlvls, curlvl, curpbm, d, q,ldq, indxq, rho, & !! SLAED7 computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and optionally eigenvectors of a dense symmetric matrix !! that has been reduced to tridiagonal form. SLAED1 handles !! the case in which all eigenvalues and eigenvectors of a symmetric !! tridiagonal matrix are desired. !! T = Q(in) ( D(in) + RHO * Z*Z**T ) Q**T(in) = Q(out) * D(out) * Q**T(out) !! where Z = Q**Tu, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine SLAED8. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine SLAED4 (as called by SLAED9). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. cutpnt, qstore, qptr, prmptr,perm, givptr, givcol, givnum, work, iwork,info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: curlvl, curpbm, cutpnt, icompq, ldq, n, qsiz, tlvls integer(${ik}$), intent(out) :: info real(sp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: givcol(2_${ik}$,*), givptr(*), perm(*), prmptr(*), qptr(*) integer(${ik}$), intent(out) :: indxq(*), iwork(*) real(sp), intent(inout) :: d(*), givnum(2_${ik}$,*), q(ldq,*), qstore(*) real(sp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, curr, i, idlmda, indx, indxc, indxp, iq2, is, iw, iz, k, ldq2, & n1, n2, ptr ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>1_${ik}$ ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( icompq==1_${ik}$ .and. qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -9_${ik}$ else if( min( 1_${ik}$, n )>cutpnt .or. n<cutpnt ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED7', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are for bookkeeping purposes only. they are ! integer pointers which indicate the portion of the workspace ! used by a particular array in stdlib${ii}$_slaed8 and stdlib${ii}$_slaed9. if( icompq==1_${ik}$ ) then ldq2 = qsiz else ldq2 = n end if iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq2 = iw + n is = iq2 + n*ldq2 indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. ptr = 1_${ik}$ + 2_${ik}$**tlvls do i = 1, curlvl - 1 ptr = ptr + 2_${ik}$**( tlvls-i ) end do curr = ptr + curpbm call stdlib${ii}$_slaeda( n, tlvls, curlvl, curpbm, prmptr, perm, givptr,givcol, givnum, & qstore, qptr, work( iz ),work( iz+n ), info ) ! when solving the final problem, we no longer need the stored data, ! so we will overwrite the data from this level onto the previously ! used storage space. if( curlvl==tlvls ) then qptr( curr ) = 1_${ik}$ prmptr( curr ) = 1_${ik}$ givptr( curr ) = 1_${ik}$ end if ! sort and deflate eigenvalues. call stdlib${ii}$_slaed8( icompq, k, n, qsiz, d, q, ldq, indxq, rho, cutpnt,work( iz ), work(& idlmda ), work( iq2 ), ldq2,work( iw ), perm( prmptr( curr ) ), givptr( curr+1 ),& givcol( 1_${ik}$, givptr( curr ) ),givnum( 1_${ik}$, givptr( curr ) ), iwork( indxp ),iwork( indx ),& info ) prmptr( curr+1 ) = prmptr( curr ) + n givptr( curr+1 ) = givptr( curr+1 ) + givptr( curr ) ! solve secular equation. if( k/=0_${ik}$ ) then call stdlib${ii}$_slaed9( k, 1_${ik}$, k, n, d, work( is ), k, rho, work( idlmda ),work( iw ), & qstore( qptr( curr ) ), k, info ) if( info/=0 )go to 30 if( icompq==1_${ik}$ ) then call stdlib${ii}$_sgemm( 'N', 'N', qsiz, k, k, one, work( iq2 ), ldq2,qstore( qptr( & curr ) ), k, zero, q, ldq ) end if qptr( curr+1 ) = qptr( curr ) + k**2_${ik}$ ! prepare the indxq sorting permutation. n1 = k n2 = n - k call stdlib${ii}$_slamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else qptr( curr+1 ) = qptr( curr ) do i = 1, n indxq( i ) = i end do end if 30 continue return end subroutine stdlib${ii}$_slaed7 pure module subroutine stdlib${ii}$_dlaed7( icompq, n, qsiz, tlvls, curlvl, curpbm, d, q,ldq, indxq, rho, & !! DLAED7 computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and optionally eigenvectors of a dense symmetric matrix !! that has been reduced to tridiagonal form. DLAED1 handles !! the case in which all eigenvalues and eigenvectors of a symmetric !! tridiagonal matrix are desired. !! T = Q(in) ( D(in) + RHO * Z*Z**T ) Q**T(in) = Q(out) * D(out) * Q**T(out) !! where Z = Q**Tu, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine DLAED8. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine DLAED4 (as called by DLAED9). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. cutpnt, qstore, qptr, prmptr,perm, givptr, givcol, givnum, work, iwork,info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: curlvl, curpbm, cutpnt, icompq, ldq, n, qsiz, tlvls integer(${ik}$), intent(out) :: info real(dp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: givcol(2_${ik}$,*), givptr(*), perm(*), prmptr(*), qptr(*) integer(${ik}$), intent(out) :: indxq(*), iwork(*) real(dp), intent(inout) :: d(*), givnum(2_${ik}$,*), q(ldq,*), qstore(*) real(dp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, curr, i, idlmda, indx, indxc, indxp, iq2, is, iw, iz, k, ldq2, & n1, n2, ptr ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>1_${ik}$ ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( icompq==1_${ik}$ .and. qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -9_${ik}$ else if( min( 1_${ik}$, n )>cutpnt .or. n<cutpnt ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED7', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are for bookkeeping purposes only. they are ! integer pointers which indicate the portion of the workspace ! used by a particular array in stdlib${ii}$_dlaed8 and stdlib${ii}$_dlaed9. if( icompq==1_${ik}$ ) then ldq2 = qsiz else ldq2 = n end if iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq2 = iw + n is = iq2 + n*ldq2 indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. ptr = 1_${ik}$ + 2_${ik}$**tlvls do i = 1, curlvl - 1 ptr = ptr + 2_${ik}$**( tlvls-i ) end do curr = ptr + curpbm call stdlib${ii}$_dlaeda( n, tlvls, curlvl, curpbm, prmptr, perm, givptr,givcol, givnum, & qstore, qptr, work( iz ),work( iz+n ), info ) ! when solving the final problem, we no longer need the stored data, ! so we will overwrite the data from this level onto the previously ! used storage space. if( curlvl==tlvls ) then qptr( curr ) = 1_${ik}$ prmptr( curr ) = 1_${ik}$ givptr( curr ) = 1_${ik}$ end if ! sort and deflate eigenvalues. call stdlib${ii}$_dlaed8( icompq, k, n, qsiz, d, q, ldq, indxq, rho, cutpnt,work( iz ), work(& idlmda ), work( iq2 ), ldq2,work( iw ), perm( prmptr( curr ) ), givptr( curr+1 ),& givcol( 1_${ik}$, givptr( curr ) ),givnum( 1_${ik}$, givptr( curr ) ), iwork( indxp ),iwork( indx ),& info ) prmptr( curr+1 ) = prmptr( curr ) + n givptr( curr+1 ) = givptr( curr+1 ) + givptr( curr ) ! solve secular equation. if( k/=0_${ik}$ ) then call stdlib${ii}$_dlaed9( k, 1_${ik}$, k, n, d, work( is ), k, rho, work( idlmda ),work( iw ), & qstore( qptr( curr ) ), k, info ) if( info/=0 )go to 30 if( icompq==1_${ik}$ ) then call stdlib${ii}$_dgemm( 'N', 'N', qsiz, k, k, one, work( iq2 ), ldq2,qstore( qptr( & curr ) ), k, zero, q, ldq ) end if qptr( curr+1 ) = qptr( curr ) + k**2_${ik}$ ! prepare the indxq sorting permutation. n1 = k n2 = n - k call stdlib${ii}$_dlamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else qptr( curr+1 ) = qptr( curr ) do i = 1, n indxq( i ) = i end do end if 30 continue return end subroutine stdlib${ii}$_dlaed7 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed7( icompq, n, qsiz, tlvls, curlvl, curpbm, d, q,ldq, indxq, rho, & !! DLAED7: computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and optionally eigenvectors of a dense symmetric matrix !! that has been reduced to tridiagonal form. DLAED1 handles !! the case in which all eigenvalues and eigenvectors of a symmetric !! tridiagonal matrix are desired. !! T = Q(in) ( D(in) + RHO * Z*Z**T ) Q**T(in) = Q(out) * D(out) * Q**T(out) !! where Z = Q**Tu, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine DLAED8. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine DLAED4 (as called by DLAED9). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. cutpnt, qstore, qptr, prmptr,perm, givptr, givcol, givnum, work, iwork,info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: curlvl, curpbm, cutpnt, icompq, ldq, n, qsiz, tlvls integer(${ik}$), intent(out) :: info real(${rk}$), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: givcol(2_${ik}$,*), givptr(*), perm(*), prmptr(*), qptr(*) integer(${ik}$), intent(out) :: indxq(*), iwork(*) real(${rk}$), intent(inout) :: d(*), givnum(2_${ik}$,*), q(ldq,*), qstore(*) real(${rk}$), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, curr, i, idlmda, indx, indxc, indxp, iq2, is, iw, iz, k, ldq2, & n1, n2, ptr ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>1_${ik}$ ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( icompq==1_${ik}$ .and. qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -9_${ik}$ else if( min( 1_${ik}$, n )>cutpnt .or. n<cutpnt ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED7', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are for bookkeeping purposes only. they are ! integer pointers which indicate the portion of the workspace ! used by a particular array in stdlib${ii}$_${ri}$laed8 and stdlib${ii}$_${ri}$laed9. if( icompq==1_${ik}$ ) then ldq2 = qsiz else ldq2 = n end if iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq2 = iw + n is = iq2 + n*ldq2 indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. ptr = 1_${ik}$ + 2_${ik}$**tlvls do i = 1, curlvl - 1 ptr = ptr + 2_${ik}$**( tlvls-i ) end do curr = ptr + curpbm call stdlib${ii}$_${ri}$laeda( n, tlvls, curlvl, curpbm, prmptr, perm, givptr,givcol, givnum, & qstore, qptr, work( iz ),work( iz+n ), info ) ! when solving the final problem, we no longer need the stored data, ! so we will overwrite the data from this level onto the previously ! used storage space. if( curlvl==tlvls ) then qptr( curr ) = 1_${ik}$ prmptr( curr ) = 1_${ik}$ givptr( curr ) = 1_${ik}$ end if ! sort and deflate eigenvalues. call stdlib${ii}$_${ri}$laed8( icompq, k, n, qsiz, d, q, ldq, indxq, rho, cutpnt,work( iz ), work(& idlmda ), work( iq2 ), ldq2,work( iw ), perm( prmptr( curr ) ), givptr( curr+1 ),& givcol( 1_${ik}$, givptr( curr ) ),givnum( 1_${ik}$, givptr( curr ) ), iwork( indxp ),iwork( indx ),& info ) prmptr( curr+1 ) = prmptr( curr ) + n givptr( curr+1 ) = givptr( curr+1 ) + givptr( curr ) ! solve secular equation. if( k/=0_${ik}$ ) then call stdlib${ii}$_${ri}$laed9( k, 1_${ik}$, k, n, d, work( is ), k, rho, work( idlmda ),work( iw ), & qstore( qptr( curr ) ), k, info ) if( info/=0 )go to 30 if( icompq==1_${ik}$ ) then call stdlib${ii}$_${ri}$gemm( 'N', 'N', qsiz, k, k, one, work( iq2 ), ldq2,qstore( qptr( & curr ) ), k, zero, q, ldq ) end if qptr( curr+1 ) = qptr( curr ) + k**2_${ik}$ ! prepare the indxq sorting permutation. n1 = k n2 = n - k call stdlib${ii}$_${ri}$lamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else qptr( curr+1 ) = qptr( curr ) do i = 1, n indxq( i ) = i end do end if 30 continue return end subroutine stdlib${ii}$_${ri}$laed7 #:endif #:endfor pure module subroutine stdlib${ii}$_claed7( n, cutpnt, qsiz, tlvls, curlvl, curpbm, d, q,ldq, rho, indxq, & !! CLAED7 computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and optionally eigenvectors of a dense or banded !! Hermitian matrix that has been reduced to tridiagonal form. !! T = Q(in) ( D(in) + RHO * Z*Z**H ) Q**H(in) = Q(out) * D(out) * Q**H(out) !! where Z = Q**Hu, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine SLAED2. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine SLAED4 (as called by SLAED3). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. qstore, qptr, prmptr, perm,givptr, givcol, givnum, work, rwork, iwork,info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: curlvl, curpbm, cutpnt, ldq, n, qsiz, tlvls integer(${ik}$), intent(out) :: info real(sp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: givcol(2_${ik}$,*), givptr(*), perm(*), prmptr(*), qptr(*) integer(${ik}$), intent(out) :: indxq(*), iwork(*) real(sp), intent(inout) :: d(*), givnum(2_${ik}$,*), qstore(*) real(sp), intent(out) :: rwork(*) complex(sp), intent(inout) :: q(ldq,*) complex(sp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, curr, i, idlmda, indx, indxc, indxp, iq, iw, iz, k, n1, n2, & ptr ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ ! if( icompq<0 .or. icompq>1 ) then ! info = -1 ! else if( n<0 ) then if( n<0_${ik}$ ) then info = -1_${ik}$ else if( min( 1_${ik}$, n )>cutpnt .or. n<cutpnt ) then info = -2_${ik}$ else if( qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'CLAED7', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are for bookkeeping purposes only. they are ! integer pointers which indicate the portion of the workspace ! used by a particular array in stdlib${ii}$_slaed2 and stdlib${ii}$_slaed3. iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq = iw + n indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. ptr = 1_${ik}$ + 2_${ik}$**tlvls do i = 1, curlvl - 1 ptr = ptr + 2_${ik}$**( tlvls-i ) end do curr = ptr + curpbm call stdlib${ii}$_slaeda( n, tlvls, curlvl, curpbm, prmptr, perm, givptr,givcol, givnum, & qstore, qptr, rwork( iz ),rwork( iz+n ), info ) ! when solving the final problem, we no longer need the stored data, ! so we will overwrite the data from this level onto the previously ! used storage space. if( curlvl==tlvls ) then qptr( curr ) = 1_${ik}$ prmptr( curr ) = 1_${ik}$ givptr( curr ) = 1_${ik}$ end if ! sort and deflate eigenvalues. call stdlib${ii}$_claed8( k, n, qsiz, q, ldq, d, rho, cutpnt, rwork( iz ),rwork( idlmda ), & work, qsiz, rwork( iw ),iwork( indxp ), iwork( indx ), indxq,perm( prmptr( curr ) ), & givptr( curr+1 ),givcol( 1_${ik}$, givptr( curr ) ),givnum( 1_${ik}$, givptr( curr ) ), info ) prmptr( curr+1 ) = prmptr( curr ) + n givptr( curr+1 ) = givptr( curr+1 ) + givptr( curr ) ! solve secular equation. if( k/=0_${ik}$ ) then call stdlib${ii}$_slaed9( k, 1_${ik}$, k, n, d, rwork( iq ), k, rho,rwork( idlmda ), rwork( iw ),& qstore( qptr( curr ) ), k, info ) call stdlib${ii}$_clacrm( qsiz, k, work, qsiz, qstore( qptr( curr ) ), k, q,ldq, rwork( & iq ) ) qptr( curr+1 ) = qptr( curr ) + k**2_${ik}$ if( info/=0_${ik}$ ) then return end if ! prepare the indxq sorting premutation. n1 = k n2 = n - k call stdlib${ii}$_slamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else qptr( curr+1 ) = qptr( curr ) do i = 1, n indxq( i ) = i end do end if return end subroutine stdlib${ii}$_claed7 pure module subroutine stdlib${ii}$_zlaed7( n, cutpnt, qsiz, tlvls, curlvl, curpbm, d, q,ldq, rho, indxq, & !! ZLAED7 computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and optionally eigenvectors of a dense or banded !! Hermitian matrix that has been reduced to tridiagonal form. !! T = Q(in) ( D(in) + RHO * Z*Z**H ) Q**H(in) = Q(out) * D(out) * Q**H(out) !! where Z = Q**Hu, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine DLAED2. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine DLAED4 (as called by SLAED3). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. qstore, qptr, prmptr, perm,givptr, givcol, givnum, work, rwork, iwork,info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: curlvl, curpbm, cutpnt, ldq, n, qsiz, tlvls integer(${ik}$), intent(out) :: info real(dp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: givcol(2_${ik}$,*), givptr(*), perm(*), prmptr(*), qptr(*) integer(${ik}$), intent(out) :: indxq(*), iwork(*) real(dp), intent(inout) :: d(*), givnum(2_${ik}$,*), qstore(*) real(dp), intent(out) :: rwork(*) complex(dp), intent(inout) :: q(ldq,*) complex(dp), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, curr, i, idlmda, indx, indxc, indxp, iq, iw, iz, k, n1, n2, & ptr ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ ! if( icompq<0 .or. icompq>1 ) then ! info = -1 ! else if( n<0 ) then if( n<0_${ik}$ ) then info = -1_${ik}$ else if( min( 1_${ik}$, n )>cutpnt .or. n<cutpnt ) then info = -2_${ik}$ else if( qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZLAED7', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are for bookkeeping purposes only. they are ! integer pointers which indicate the portion of the workspace ! used by a particular array in stdlib${ii}$_dlaed2 and stdlib${ii}$_slaed3. iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq = iw + n indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. ptr = 1_${ik}$ + 2_${ik}$**tlvls do i = 1, curlvl - 1 ptr = ptr + 2_${ik}$**( tlvls-i ) end do curr = ptr + curpbm call stdlib${ii}$_dlaeda( n, tlvls, curlvl, curpbm, prmptr, perm, givptr,givcol, givnum, & qstore, qptr, rwork( iz ),rwork( iz+n ), info ) ! when solving the final problem, we no longer need the stored data, ! so we will overwrite the data from this level onto the previously ! used storage space. if( curlvl==tlvls ) then qptr( curr ) = 1_${ik}$ prmptr( curr ) = 1_${ik}$ givptr( curr ) = 1_${ik}$ end if ! sort and deflate eigenvalues. call stdlib${ii}$_zlaed8( k, n, qsiz, q, ldq, d, rho, cutpnt, rwork( iz ),rwork( idlmda ), & work, qsiz, rwork( iw ),iwork( indxp ), iwork( indx ), indxq,perm( prmptr( curr ) ), & givptr( curr+1 ),givcol( 1_${ik}$, givptr( curr ) ),givnum( 1_${ik}$, givptr( curr ) ), info ) prmptr( curr+1 ) = prmptr( curr ) + n givptr( curr+1 ) = givptr( curr+1 ) + givptr( curr ) ! solve secular equation. if( k/=0_${ik}$ ) then call stdlib${ii}$_dlaed9( k, 1_${ik}$, k, n, d, rwork( iq ), k, rho,rwork( idlmda ), rwork( iw ),& qstore( qptr( curr ) ), k, info ) call stdlib${ii}$_zlacrm( qsiz, k, work, qsiz, qstore( qptr( curr ) ), k, q,ldq, rwork( & iq ) ) qptr( curr+1 ) = qptr( curr ) + k**2_${ik}$ if( info/=0_${ik}$ ) then return end if ! prepare the indxq sorting premutation. n1 = k n2 = n - k call stdlib${ii}$_dlamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else qptr( curr+1 ) = qptr( curr ) do i = 1, n indxq( i ) = i end do end if return end subroutine stdlib${ii}$_zlaed7 #:for ck,ct,ci in CMPLX_KINDS_TYPES #:if not ck in ["sp","dp"] pure module subroutine stdlib${ii}$_${ci}$laed7( n, cutpnt, qsiz, tlvls, curlvl, curpbm, d, q,ldq, rho, indxq, & !! ZLAED7: computes the updated eigensystem of a diagonal !! matrix after modification by a rank-one symmetric matrix. This !! routine is used only for the eigenproblem which requires all !! eigenvalues and optionally eigenvectors of a dense or banded !! Hermitian matrix that has been reduced to tridiagonal form. !! T = Q(in) ( D(in) + RHO * Z*Z**H ) Q**H(in) = Q(out) * D(out) * Q**H(out) !! where Z = Q**Hu, u is a vector of length N with ones in the !! CUTPNT and CUTPNT + 1 th elements and zeros elsewhere. !! The eigenvectors of the original matrix are stored in Q, and the !! eigenvalues are in D. The algorithm consists of three stages: !! The first stage consists of deflating the size of the problem !! when there are multiple eigenvalues or if there is a zero in !! the Z vector. For each such occurrence the dimension of the !! secular equation problem is reduced by one. This stage is !! performed by the routine DLAED2. !! The second stage consists of calculating the updated !! eigenvalues. This is done by finding the roots of the secular !! equation via the routine DLAED4 (as called by SLAED3). !! This routine also calculates the eigenvectors of the current !! problem. !! The final stage consists of computing the updated eigenvectors !! directly using the updated eigenvalues. The eigenvectors for !! the current problem are multiplied with the eigenvectors from !! the overall problem. qstore, qptr, prmptr, perm,givptr, givcol, givnum, work, rwork, iwork,info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${ck}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: curlvl, curpbm, cutpnt, ldq, n, qsiz, tlvls integer(${ik}$), intent(out) :: info real(${ck}$), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(inout) :: givcol(2_${ik}$,*), givptr(*), perm(*), prmptr(*), qptr(*) integer(${ik}$), intent(out) :: indxq(*), iwork(*) real(${ck}$), intent(inout) :: d(*), givnum(2_${ik}$,*), qstore(*) real(${ck}$), intent(out) :: rwork(*) complex(${ck}$), intent(inout) :: q(ldq,*) complex(${ck}$), intent(out) :: work(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: coltyp, curr, i, idlmda, indx, indxc, indxp, iq, iw, iz, k, n1, n2, & ptr ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ ! if( icompq<0 .or. icompq>1 ) then ! info = -1 ! else if( n<0 ) then if( n<0_${ik}$ ) then info = -1_${ik}$ else if( min( 1_${ik}$, n )>cutpnt .or. n<cutpnt ) then info = -2_${ik}$ else if( qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZLAED7', -info ) return end if ! quick return if possible if( n==0 )return ! the following values are for bookkeeping purposes only. they are ! integer pointers which indicate the portion of the workspace ! used by a particular array in stdlib${ii}$_${c2ri(ci)}$laed2 and stdlib${ii}$_dlaed3. iz = 1_${ik}$ idlmda = iz + n iw = idlmda + n iq = iw + n indx = 1_${ik}$ indxc = indx + n coltyp = indxc + n indxp = coltyp + n ! form the z-vector which consists of the last row of q_1 and the ! first row of q_2. ptr = 1_${ik}$ + 2_${ik}$**tlvls do i = 1, curlvl - 1 ptr = ptr + 2_${ik}$**( tlvls-i ) end do curr = ptr + curpbm call stdlib${ii}$_${c2ri(ci)}$laeda( n, tlvls, curlvl, curpbm, prmptr, perm, givptr,givcol, givnum, & qstore, qptr, rwork( iz ),rwork( iz+n ), info ) ! when solving the final problem, we no longer need the stored data, ! so we will overwrite the data from this level onto the previously ! used storage space. if( curlvl==tlvls ) then qptr( curr ) = 1_${ik}$ prmptr( curr ) = 1_${ik}$ givptr( curr ) = 1_${ik}$ end if ! sort and deflate eigenvalues. call stdlib${ii}$_${ci}$laed8( k, n, qsiz, q, ldq, d, rho, cutpnt, rwork( iz ),rwork( idlmda ), & work, qsiz, rwork( iw ),iwork( indxp ), iwork( indx ), indxq,perm( prmptr( curr ) ), & givptr( curr+1 ),givcol( 1_${ik}$, givptr( curr ) ),givnum( 1_${ik}$, givptr( curr ) ), info ) prmptr( curr+1 ) = prmptr( curr ) + n givptr( curr+1 ) = givptr( curr+1 ) + givptr( curr ) ! solve secular equation. if( k/=0_${ik}$ ) then call stdlib${ii}$_${c2ri(ci)}$laed9( k, 1_${ik}$, k, n, d, rwork( iq ), k, rho,rwork( idlmda ), rwork( iw ),& qstore( qptr( curr ) ), k, info ) call stdlib${ii}$_${ci}$lacrm( qsiz, k, work, qsiz, qstore( qptr( curr ) ), k, q,ldq, rwork( & iq ) ) qptr( curr+1 ) = qptr( curr ) + k**2_${ik}$ if( info/=0_${ik}$ ) then return end if ! prepare the indxq sorting premutation. n1 = k n2 = n - k call stdlib${ii}$_${c2ri(ci)}$lamrg( n1, n2, d, 1_${ik}$, -1_${ik}$, indxq ) else qptr( curr+1 ) = qptr( curr ) do i = 1, n indxq( i ) = i end do end if return end subroutine stdlib${ii}$_${ci}$laed7 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed8( icompq, k, n, qsiz, d, q, ldq, indxq, rho,cutpnt, z, dlamda, & !! SLAED8 merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny element in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. q2, ldq2, w, perm, givptr,givcol, givnum, indxp, indx, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, icompq, ldq, ldq2, n, qsiz integer(${ik}$), intent(out) :: givptr, info, k real(sp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: givcol(2_${ik}$,*), indx(*), indxp(*), perm(*) integer(${ik}$), intent(inout) :: indxq(*) real(sp), intent(inout) :: d(*), q(ldq,*), z(*) real(sp), intent(out) :: dlamda(*), givnum(2_${ik}$,*), q2(ldq2,*), w(*) ! ===================================================================== ! Parameters real(sp), parameter :: mone = -1.0_sp ! Local Scalars integer(${ik}$) :: i, imax, j, jlam, jmax, jp, k2, n1, n1p1, n2 real(sp) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>1_${ik}$ ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( icompq==1_${ik}$ .and. qsiz<n ) then info = -4_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -7_${ik}$ else if( cutpnt<min( 1_${ik}$, n ) .or. cutpnt>n ) then info = -10_${ik}$ else if( ldq2<max( 1_${ik}$, n ) ) then info = -14_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED8', -info ) return end if ! need to initialize givptr to o here in case of quick exit ! to prevent an unspecified code behavior (usually sigfault) ! when iwork array on entry to *stedc is not zeroed ! (or at least some iwork entries which used in *laed7 for givptr). givptr = 0_${ik}$ ! quick return if possible if( n==0 )return n1 = cutpnt n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_sscal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1 t = one / sqrt( two ) do j = 1, n indx( j ) = j end do call stdlib${ii}$_sscal( n, t, z, 1_${ik}$ ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = cutpnt + 1, n indxq( i ) = indxq( i ) + cutpnt end do do i = 1, n dlamda( i ) = d( indxq( i ) ) w( i ) = z( indxq( i ) ) end do i = 1_${ik}$ j = cutpnt + 1_${ik}$ call stdlib${ii}$_slamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indx ) do i = 1, n d( i ) = dlamda( indx( i ) ) z( i ) = w( indx( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_isamax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_isamax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_slamch( 'EPSILON' ) tol = eight*eps*abs( d( jmax ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ if( icompq==0_${ik}$ ) then do j = 1, n perm( j ) = indxq( indx( j ) ) end do else do j = 1, n perm( j ) = indxq( indx( j ) ) call stdlib${ii}$_scopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do call stdlib${ii}$_slacpy( 'A', qsiz, n, q2( 1_${ik}$, 1_${ik}$ ), ldq2, q( 1_${ik}$, 1_${ik}$ ),ldq ) end if return end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j if( j==n )go to 110 else jlam = j go to 80 end if end do 80 continue j = j + 1_${ik}$ if( j>n )go to 100 if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j else ! check if eigenvalues are close enough to allow deflation. s = z( jlam ) c = z( j ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_slapy2( c, s ) t = d( j ) - d( jlam ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( j ) = tau z( jlam ) = zero ! record the appropriate givens rotation givptr = givptr + 1_${ik}$ givcol( 1_${ik}$, givptr ) = indxq( indx( jlam ) ) givcol( 2_${ik}$, givptr ) = indxq( indx( j ) ) givnum( 1_${ik}$, givptr ) = c givnum( 2_${ik}$, givptr ) = s if( icompq==1_${ik}$ ) then call stdlib${ii}$_srot( qsiz, q( 1_${ik}$, indxq( indx( jlam ) ) ), 1_${ik}$,q( 1_${ik}$, indxq( indx( j & ) ) ), 1_${ik}$, c, s ) end if t = d( jlam )*c*c + d( j )*s*s d( j ) = d( jlam )*s*s + d( j )*c*c d( jlam ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 90 continue if( k2+i<=n ) then if( d( jlam )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = jlam i = i + 1_${ik}$ go to 90 else indxp( k2+i-1 ) = jlam end if else indxp( k2+i-1 ) = jlam end if jlam = j else k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam jlam = j end if end if go to 80 100 continue ! record the last eigenvalue. k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam 110 continue ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. if( icompq==0_${ik}$ ) then do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) end do else do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) call stdlib${ii}$_scopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do end if ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then if( icompq==0_${ik}$ ) then call stdlib${ii}$_scopy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) else call stdlib${ii}$_scopy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) call stdlib${ii}$_slacpy( 'A', qsiz, n-k, q2( 1_${ik}$, k+1 ), ldq2,q( 1_${ik}$, k+1 ), ldq ) end if end if return end subroutine stdlib${ii}$_slaed8 pure module subroutine stdlib${ii}$_dlaed8( icompq, k, n, qsiz, d, q, ldq, indxq, rho,cutpnt, z, dlamda, & !! DLAED8 merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny element in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. q2, ldq2, w, perm, givptr,givcol, givnum, indxp, indx, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, icompq, ldq, ldq2, n, qsiz integer(${ik}$), intent(out) :: givptr, info, k real(dp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: givcol(2_${ik}$,*), indx(*), indxp(*), perm(*) integer(${ik}$), intent(inout) :: indxq(*) real(dp), intent(inout) :: d(*), q(ldq,*), z(*) real(dp), intent(out) :: dlamda(*), givnum(2_${ik}$,*), q2(ldq2,*), w(*) ! ===================================================================== ! Parameters real(dp), parameter :: mone = -1.0_dp ! Local Scalars integer(${ik}$) :: i, imax, j, jlam, jmax, jp, k2, n1, n1p1, n2 real(dp) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>1_${ik}$ ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( icompq==1_${ik}$ .and. qsiz<n ) then info = -4_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -7_${ik}$ else if( cutpnt<min( 1_${ik}$, n ) .or. cutpnt>n ) then info = -10_${ik}$ else if( ldq2<max( 1_${ik}$, n ) ) then info = -14_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED8', -info ) return end if ! need to initialize givptr to o here in case of quick exit ! to prevent an unspecified code behavior (usually sigfault) ! when iwork array on entry to *stedc is not zeroed ! (or at least some iwork entries which used in *laed7 for givptr). givptr = 0_${ik}$ ! quick return if possible if( n==0 )return n1 = cutpnt n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_dscal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1 t = one / sqrt( two ) do j = 1, n indx( j ) = j end do call stdlib${ii}$_dscal( n, t, z, 1_${ik}$ ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = cutpnt + 1, n indxq( i ) = indxq( i ) + cutpnt end do do i = 1, n dlamda( i ) = d( indxq( i ) ) w( i ) = z( indxq( i ) ) end do i = 1_${ik}$ j = cutpnt + 1_${ik}$ call stdlib${ii}$_dlamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indx ) do i = 1, n d( i ) = dlamda( indx( i ) ) z( i ) = w( indx( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_idamax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_idamax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_dlamch( 'EPSILON' ) tol = eight*eps*abs( d( jmax ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ if( icompq==0_${ik}$ ) then do j = 1, n perm( j ) = indxq( indx( j ) ) end do else do j = 1, n perm( j ) = indxq( indx( j ) ) call stdlib${ii}$_dcopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do call stdlib${ii}$_dlacpy( 'A', qsiz, n, q2( 1_${ik}$, 1_${ik}$ ), ldq2, q( 1_${ik}$, 1_${ik}$ ),ldq ) end if return end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j if( j==n )go to 110 else jlam = j go to 80 end if end do 80 continue j = j + 1_${ik}$ if( j>n )go to 100 if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j else ! check if eigenvalues are close enough to allow deflation. s = z( jlam ) c = z( j ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_dlapy2( c, s ) t = d( j ) - d( jlam ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( j ) = tau z( jlam ) = zero ! record the appropriate givens rotation givptr = givptr + 1_${ik}$ givcol( 1_${ik}$, givptr ) = indxq( indx( jlam ) ) givcol( 2_${ik}$, givptr ) = indxq( indx( j ) ) givnum( 1_${ik}$, givptr ) = c givnum( 2_${ik}$, givptr ) = s if( icompq==1_${ik}$ ) then call stdlib${ii}$_drot( qsiz, q( 1_${ik}$, indxq( indx( jlam ) ) ), 1_${ik}$,q( 1_${ik}$, indxq( indx( j & ) ) ), 1_${ik}$, c, s ) end if t = d( jlam )*c*c + d( j )*s*s d( j ) = d( jlam )*s*s + d( j )*c*c d( jlam ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 90 continue if( k2+i<=n ) then if( d( jlam )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = jlam i = i + 1_${ik}$ go to 90 else indxp( k2+i-1 ) = jlam end if else indxp( k2+i-1 ) = jlam end if jlam = j else k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam jlam = j end if end if go to 80 100 continue ! record the last eigenvalue. k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam 110 continue ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. if( icompq==0_${ik}$ ) then do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) end do else do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) call stdlib${ii}$_dcopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do end if ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then if( icompq==0_${ik}$ ) then call stdlib${ii}$_dcopy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) else call stdlib${ii}$_dcopy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) call stdlib${ii}$_dlacpy( 'A', qsiz, n-k, q2( 1_${ik}$, k+1 ), ldq2,q( 1_${ik}$, k+1 ), ldq ) end if end if return end subroutine stdlib${ii}$_dlaed8 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed8( icompq, k, n, qsiz, d, q, ldq, indxq, rho,cutpnt, z, dlamda, & !! DLAED8: merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny element in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. q2, ldq2, w, perm, givptr,givcol, givnum, indxp, indx, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, icompq, ldq, ldq2, n, qsiz integer(${ik}$), intent(out) :: givptr, info, k real(${rk}$), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: givcol(2_${ik}$,*), indx(*), indxp(*), perm(*) integer(${ik}$), intent(inout) :: indxq(*) real(${rk}$), intent(inout) :: d(*), q(ldq,*), z(*) real(${rk}$), intent(out) :: dlamda(*), givnum(2_${ik}$,*), q2(ldq2,*), w(*) ! ===================================================================== ! Parameters real(${rk}$), parameter :: mone = -1.0_${rk}$ ! Local Scalars integer(${ik}$) :: i, imax, j, jlam, jmax, jp, k2, n1, n1p1, n2 real(${rk}$) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( icompq<0_${ik}$ .or. icompq>1_${ik}$ ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( icompq==1_${ik}$ .and. qsiz<n ) then info = -4_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -7_${ik}$ else if( cutpnt<min( 1_${ik}$, n ) .or. cutpnt>n ) then info = -10_${ik}$ else if( ldq2<max( 1_${ik}$, n ) ) then info = -14_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED8', -info ) return end if ! need to initialize givptr to o here in case of quick exit ! to prevent an unspecified code behavior (usually sigfault) ! when iwork array on entry to *stedc is not zeroed ! (or at least some iwork entries which used in *laed7 for givptr). givptr = 0_${ik}$ ! quick return if possible if( n==0 )return n1 = cutpnt n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_${ri}$scal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1 t = one / sqrt( two ) do j = 1, n indx( j ) = j end do call stdlib${ii}$_${ri}$scal( n, t, z, 1_${ik}$ ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = cutpnt + 1, n indxq( i ) = indxq( i ) + cutpnt end do do i = 1, n dlamda( i ) = d( indxq( i ) ) w( i ) = z( indxq( i ) ) end do i = 1_${ik}$ j = cutpnt + 1_${ik}$ call stdlib${ii}$_${ri}$lamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indx ) do i = 1, n d( i ) = dlamda( indx( i ) ) z( i ) = w( indx( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_i${ri}$amax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_i${ri}$amax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_${ri}$lamch( 'EPSILON' ) tol = eight*eps*abs( d( jmax ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ if( icompq==0_${ik}$ ) then do j = 1, n perm( j ) = indxq( indx( j ) ) end do else do j = 1, n perm( j ) = indxq( indx( j ) ) call stdlib${ii}$_${ri}$copy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do call stdlib${ii}$_${ri}$lacpy( 'A', qsiz, n, q2( 1_${ik}$, 1_${ik}$ ), ldq2, q( 1_${ik}$, 1_${ik}$ ),ldq ) end if return end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j if( j==n )go to 110 else jlam = j go to 80 end if end do 80 continue j = j + 1_${ik}$ if( j>n )go to 100 if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j else ! check if eigenvalues are close enough to allow deflation. s = z( jlam ) c = z( j ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_${ri}$lapy2( c, s ) t = d( j ) - d( jlam ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( j ) = tau z( jlam ) = zero ! record the appropriate givens rotation givptr = givptr + 1_${ik}$ givcol( 1_${ik}$, givptr ) = indxq( indx( jlam ) ) givcol( 2_${ik}$, givptr ) = indxq( indx( j ) ) givnum( 1_${ik}$, givptr ) = c givnum( 2_${ik}$, givptr ) = s if( icompq==1_${ik}$ ) then call stdlib${ii}$_${ri}$rot( qsiz, q( 1_${ik}$, indxq( indx( jlam ) ) ), 1_${ik}$,q( 1_${ik}$, indxq( indx( j & ) ) ), 1_${ik}$, c, s ) end if t = d( jlam )*c*c + d( j )*s*s d( j ) = d( jlam )*s*s + d( j )*c*c d( jlam ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 90 continue if( k2+i<=n ) then if( d( jlam )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = jlam i = i + 1_${ik}$ go to 90 else indxp( k2+i-1 ) = jlam end if else indxp( k2+i-1 ) = jlam end if jlam = j else k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam jlam = j end if end if go to 80 100 continue ! record the last eigenvalue. k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam 110 continue ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. if( icompq==0_${ik}$ ) then do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) end do else do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) call stdlib${ii}$_${ri}$copy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do end if ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then if( icompq==0_${ik}$ ) then call stdlib${ii}$_${ri}$copy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) else call stdlib${ii}$_${ri}$copy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) call stdlib${ii}$_${ri}$lacpy( 'A', qsiz, n-k, q2( 1_${ik}$, k+1 ), ldq2,q( 1_${ik}$, k+1 ), ldq ) end if end if return end subroutine stdlib${ii}$_${ri}$laed8 #:endif #:endfor pure module subroutine stdlib${ii}$_claed8( k, n, qsiz, q, ldq, d, rho, cutpnt, z, dlamda,q2, ldq2, w, & !! CLAED8 merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny element in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. indxp, indx, indxq, perm, givptr,givcol, givnum, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, ldq, ldq2, n, qsiz integer(${ik}$), intent(out) :: givptr, info, k real(sp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: givcol(2_${ik}$,*), indx(*), indxp(*), perm(*) integer(${ik}$), intent(inout) :: indxq(*) real(sp), intent(inout) :: d(*), z(*) real(sp), intent(out) :: dlamda(*), givnum(2_${ik}$,*), w(*) complex(sp), intent(inout) :: q(ldq,*) complex(sp), intent(out) :: q2(ldq2,*) ! ===================================================================== ! Parameters real(sp), parameter :: mone = -1.0_sp ! Local Scalars integer(${ik}$) :: i, imax, j, jlam, jmax, jp, k2, n1, n1p1, n2 real(sp) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -2_${ik}$ else if( qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -5_${ik}$ else if( cutpnt<min( 1_${ik}$, n ) .or. cutpnt>n ) then info = -8_${ik}$ else if( ldq2<max( 1_${ik}$, n ) ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'CLAED8', -info ) return end if ! need to initialize givptr to o here in case of quick exit ! to prevent an unspecified code behavior (usually sigfault) ! when iwork array on entry to *stedc is not zeroed ! (or at least some iwork entries which used in *laed7 for givptr). givptr = 0_${ik}$ ! quick return if possible if( n==0 )return n1 = cutpnt n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_sscal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1 t = one / sqrt( two ) do j = 1, n indx( j ) = j end do call stdlib${ii}$_sscal( n, t, z, 1_${ik}$ ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = cutpnt + 1, n indxq( i ) = indxq( i ) + cutpnt end do do i = 1, n dlamda( i ) = d( indxq( i ) ) w( i ) = z( indxq( i ) ) end do i = 1_${ik}$ j = cutpnt + 1_${ik}$ call stdlib${ii}$_slamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indx ) do i = 1, n d( i ) = dlamda( indx( i ) ) z( i ) = w( indx( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_isamax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_isamax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_slamch( 'EPSILON' ) tol = eight*eps*abs( d( jmax ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! -- except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ do j = 1, n perm( j ) = indxq( indx( j ) ) call stdlib${ii}$_ccopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do call stdlib${ii}$_clacpy( 'A', qsiz, n, q2( 1_${ik}$, 1_${ik}$ ), ldq2, q( 1_${ik}$, 1_${ik}$ ), ldq ) return end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j if( j==n )go to 100 else jlam = j go to 70 end if end do 70 continue j = j + 1_${ik}$ if( j>n )go to 90 if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j else ! check if eigenvalues are close enough to allow deflation. s = z( jlam ) c = z( j ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_slapy2( c, s ) t = d( j ) - d( jlam ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( j ) = tau z( jlam ) = zero ! record the appropriate givens rotation givptr = givptr + 1_${ik}$ givcol( 1_${ik}$, givptr ) = indxq( indx( jlam ) ) givcol( 2_${ik}$, givptr ) = indxq( indx( j ) ) givnum( 1_${ik}$, givptr ) = c givnum( 2_${ik}$, givptr ) = s call stdlib${ii}$_csrot( qsiz, q( 1_${ik}$, indxq( indx( jlam ) ) ), 1_${ik}$,q( 1_${ik}$, indxq( indx( j ) & ) ), 1_${ik}$, c, s ) t = d( jlam )*c*c + d( j )*s*s d( j ) = d( jlam )*s*s + d( j )*c*c d( jlam ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 80 continue if( k2+i<=n ) then if( d( jlam )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = jlam i = i + 1_${ik}$ go to 80 else indxp( k2+i-1 ) = jlam end if else indxp( k2+i-1 ) = jlam end if jlam = j else k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam jlam = j end if end if go to 70 90 continue ! record the last eigenvalue. k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam 100 continue ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) call stdlib${ii}$_ccopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then call stdlib${ii}$_scopy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) call stdlib${ii}$_clacpy( 'A', qsiz, n-k, q2( 1_${ik}$, k+1 ), ldq2, q( 1_${ik}$, k+1 ),ldq ) end if return end subroutine stdlib${ii}$_claed8 pure module subroutine stdlib${ii}$_zlaed8( k, n, qsiz, q, ldq, d, rho, cutpnt, z, dlamda,q2, ldq2, w, & !! ZLAED8 merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny element in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. indxp, indx, indxq, perm, givptr,givcol, givnum, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, ldq, ldq2, n, qsiz integer(${ik}$), intent(out) :: givptr, info, k real(dp), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: givcol(2_${ik}$,*), indx(*), indxp(*), perm(*) integer(${ik}$), intent(inout) :: indxq(*) real(dp), intent(inout) :: d(*), z(*) real(dp), intent(out) :: dlamda(*), givnum(2_${ik}$,*), w(*) complex(dp), intent(inout) :: q(ldq,*) complex(dp), intent(out) :: q2(ldq2,*) ! ===================================================================== ! Parameters real(dp), parameter :: mone = -1.0_dp ! Local Scalars integer(${ik}$) :: i, imax, j, jlam, jmax, jp, k2, n1, n1p1, n2 real(dp) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -2_${ik}$ else if( qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -5_${ik}$ else if( cutpnt<min( 1_${ik}$, n ) .or. cutpnt>n ) then info = -8_${ik}$ else if( ldq2<max( 1_${ik}$, n ) ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZLAED8', -info ) return end if ! need to initialize givptr to o here in case of quick exit ! to prevent an unspecified code behavior (usually sigfault) ! when iwork array on entry to *stedc is not zeroed ! (or at least some iwork entries which used in *laed7 for givptr). givptr = 0_${ik}$ ! quick return if possible if( n==0 )return n1 = cutpnt n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_dscal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1 t = one / sqrt( two ) do j = 1, n indx( j ) = j end do call stdlib${ii}$_dscal( n, t, z, 1_${ik}$ ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = cutpnt + 1, n indxq( i ) = indxq( i ) + cutpnt end do do i = 1, n dlamda( i ) = d( indxq( i ) ) w( i ) = z( indxq( i ) ) end do i = 1_${ik}$ j = cutpnt + 1_${ik}$ call stdlib${ii}$_dlamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indx ) do i = 1, n d( i ) = dlamda( indx( i ) ) z( i ) = w( indx( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_idamax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_idamax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_dlamch( 'EPSILON' ) tol = eight*eps*abs( d( jmax ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! -- except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ do j = 1, n perm( j ) = indxq( indx( j ) ) call stdlib${ii}$_zcopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do call stdlib${ii}$_zlacpy( 'A', qsiz, n, q2( 1_${ik}$, 1_${ik}$ ), ldq2, q( 1_${ik}$, 1_${ik}$ ), ldq ) return end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j if( j==n )go to 100 else jlam = j go to 70 end if end do 70 continue j = j + 1_${ik}$ if( j>n )go to 90 if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j else ! check if eigenvalues are close enough to allow deflation. s = z( jlam ) c = z( j ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_dlapy2( c, s ) t = d( j ) - d( jlam ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( j ) = tau z( jlam ) = zero ! record the appropriate givens rotation givptr = givptr + 1_${ik}$ givcol( 1_${ik}$, givptr ) = indxq( indx( jlam ) ) givcol( 2_${ik}$, givptr ) = indxq( indx( j ) ) givnum( 1_${ik}$, givptr ) = c givnum( 2_${ik}$, givptr ) = s call stdlib${ii}$_zdrot( qsiz, q( 1_${ik}$, indxq( indx( jlam ) ) ), 1_${ik}$,q( 1_${ik}$, indxq( indx( j ) & ) ), 1_${ik}$, c, s ) t = d( jlam )*c*c + d( j )*s*s d( j ) = d( jlam )*s*s + d( j )*c*c d( jlam ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 80 continue if( k2+i<=n ) then if( d( jlam )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = jlam i = i + 1_${ik}$ go to 80 else indxp( k2+i-1 ) = jlam end if else indxp( k2+i-1 ) = jlam end if jlam = j else k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam jlam = j end if end if go to 70 90 continue ! record the last eigenvalue. k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam 100 continue ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) call stdlib${ii}$_zcopy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then call stdlib${ii}$_dcopy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) call stdlib${ii}$_zlacpy( 'A', qsiz, n-k, q2( 1_${ik}$, k+1 ), ldq2, q( 1_${ik}$, k+1 ),ldq ) end if return end subroutine stdlib${ii}$_zlaed8 #:for ck,ct,ci in CMPLX_KINDS_TYPES #:if not ck in ["sp","dp"] pure module subroutine stdlib${ii}$_${ci}$laed8( k, n, qsiz, q, ldq, d, rho, cutpnt, z, dlamda,q2, ldq2, w, & !! ZLAED8: merges the two sets of eigenvalues together into a single !! sorted set. Then it tries to deflate the size of the problem. !! There are two ways in which deflation can occur: when two or more !! eigenvalues are close together or if there is a tiny element in the !! Z vector. For each such occurrence the order of the related secular !! equation problem is reduced by one. indxp, indx, indxq, perm, givptr,givcol, givnum, info ) ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${ck}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(in) :: cutpnt, ldq, ldq2, n, qsiz integer(${ik}$), intent(out) :: givptr, info, k real(${ck}$), intent(inout) :: rho ! Array Arguments integer(${ik}$), intent(out) :: givcol(2_${ik}$,*), indx(*), indxp(*), perm(*) integer(${ik}$), intent(inout) :: indxq(*) real(${ck}$), intent(inout) :: d(*), z(*) real(${ck}$), intent(out) :: dlamda(*), givnum(2_${ik}$,*), w(*) complex(${ck}$), intent(inout) :: q(ldq,*) complex(${ck}$), intent(out) :: q2(ldq2,*) ! ===================================================================== ! Parameters real(${ck}$), parameter :: mone = -one ! Local Scalars integer(${ik}$) :: i, imax, j, jlam, jmax, jp, k2, n1, n1p1, n2 real(${ck}$) :: c, eps, s, t, tau, tol ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( n<0_${ik}$ ) then info = -2_${ik}$ else if( qsiz<n ) then info = -3_${ik}$ else if( ldq<max( 1_${ik}$, n ) ) then info = -5_${ik}$ else if( cutpnt<min( 1_${ik}$, n ) .or. cutpnt>n ) then info = -8_${ik}$ else if( ldq2<max( 1_${ik}$, n ) ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZLAED8', -info ) return end if ! need to initialize givptr to o here in case of quick exit ! to prevent an unspecified code behavior (usually sigfault) ! when iwork array on entry to *stedc is not zeroed ! (or at least some iwork entries which used in *laed7 for givptr). givptr = 0_${ik}$ ! quick return if possible if( n==0 )return n1 = cutpnt n2 = n - n1 n1p1 = n1 + 1_${ik}$ if( rho<zero ) then call stdlib${ii}$_${c2ri(ci)}$scal( n2, mone, z( n1p1 ), 1_${ik}$ ) end if ! normalize z so that norm(z) = 1 t = one / sqrt( two ) do j = 1, n indx( j ) = j end do call stdlib${ii}$_${c2ri(ci)}$scal( n, t, z, 1_${ik}$ ) rho = abs( two*rho ) ! sort the eigenvalues into increasing order do i = cutpnt + 1, n indxq( i ) = indxq( i ) + cutpnt end do do i = 1, n dlamda( i ) = d( indxq( i ) ) w( i ) = z( indxq( i ) ) end do i = 1_${ik}$ j = cutpnt + 1_${ik}$ call stdlib${ii}$_${c2ri(ci)}$lamrg( n1, n2, dlamda, 1_${ik}$, 1_${ik}$, indx ) do i = 1, n d( i ) = dlamda( indx( i ) ) z( i ) = w( indx( i ) ) end do ! calculate the allowable deflation tolerance imax = stdlib${ii}$_i${c2ri(ci)}$amax( n, z, 1_${ik}$ ) jmax = stdlib${ii}$_i${c2ri(ci)}$amax( n, d, 1_${ik}$ ) eps = stdlib${ii}$_${c2ri(ci)}$lamch( 'EPSILON' ) tol = eight*eps*abs( d( jmax ) ) ! if the rank-1 modifier is small enough, no more needs to be done ! -- except to reorganize q so that its columns correspond with the ! elements in d. if( rho*abs( z( imax ) )<=tol ) then k = 0_${ik}$ do j = 1, n perm( j ) = indxq( indx( j ) ) call stdlib${ii}$_${ci}$copy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do call stdlib${ii}$_${ci}$lacpy( 'A', qsiz, n, q2( 1_${ik}$, 1_${ik}$ ), ldq2, q( 1_${ik}$, 1_${ik}$ ), ldq ) return end if ! if there are multiple eigenvalues then the problem deflates. here ! the number of equal eigenvalues are found. as each equal ! eigenvalue is found, an elementary reflector is computed to rotate ! the corresponding eigensubspace so that the corresponding ! components of z are zero in this new basis. k = 0_${ik}$ k2 = n + 1_${ik}$ do j = 1, n if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j if( j==n )go to 100 else jlam = j go to 70 end if end do 70 continue j = j + 1_${ik}$ if( j>n )go to 90 if( rho*abs( z( j ) )<=tol ) then ! deflate due to small z component. k2 = k2 - 1_${ik}$ indxp( k2 ) = j else ! check if eigenvalues are close enough to allow deflation. s = z( jlam ) c = z( j ) ! find sqrt(a**2+b**2) without overflow or ! destructive underflow. tau = stdlib${ii}$_${c2ri(ci)}$lapy2( c, s ) t = d( j ) - d( jlam ) c = c / tau s = -s / tau if( abs( t*c*s )<=tol ) then ! deflation is possible. z( j ) = tau z( jlam ) = zero ! record the appropriate givens rotation givptr = givptr + 1_${ik}$ givcol( 1_${ik}$, givptr ) = indxq( indx( jlam ) ) givcol( 2_${ik}$, givptr ) = indxq( indx( j ) ) givnum( 1_${ik}$, givptr ) = c givnum( 2_${ik}$, givptr ) = s call stdlib${ii}$_${ci}$drot( qsiz, q( 1_${ik}$, indxq( indx( jlam ) ) ), 1_${ik}$,q( 1_${ik}$, indxq( indx( j ) & ) ), 1_${ik}$, c, s ) t = d( jlam )*c*c + d( j )*s*s d( j ) = d( jlam )*s*s + d( j )*c*c d( jlam ) = t k2 = k2 - 1_${ik}$ i = 1_${ik}$ 80 continue if( k2+i<=n ) then if( d( jlam )<d( indxp( k2+i ) ) ) then indxp( k2+i-1 ) = indxp( k2+i ) indxp( k2+i ) = jlam i = i + 1_${ik}$ go to 80 else indxp( k2+i-1 ) = jlam end if else indxp( k2+i-1 ) = jlam end if jlam = j else k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam jlam = j end if end if go to 70 90 continue ! record the last eigenvalue. k = k + 1_${ik}$ w( k ) = z( jlam ) dlamda( k ) = d( jlam ) indxp( k ) = jlam 100 continue ! sort the eigenvalues and corresponding eigenvectors into dlamda ! and q2 respectively. the eigenvalues/vectors which were not ! deflated go into the first k slots of dlamda and q2 respectively, ! while those which were deflated go into the last n - k slots. do j = 1, n jp = indxp( j ) dlamda( j ) = d( jp ) perm( j ) = indxq( indx( jp ) ) call stdlib${ii}$_${ci}$copy( qsiz, q( 1_${ik}$, perm( j ) ), 1_${ik}$, q2( 1_${ik}$, j ), 1_${ik}$ ) end do ! the deflated eigenvalues and their corresponding vectors go back ! into the last n - k slots of d and q respectively. if( k<n ) then call stdlib${ii}$_${c2ri(ci)}$copy( n-k, dlamda( k+1 ), 1_${ik}$, d( k+1 ), 1_${ik}$ ) call stdlib${ii}$_${ci}$lacpy( 'A', qsiz, n-k, q2( 1_${ik}$, k+1 ), ldq2, q( 1_${ik}$, k+1 ),ldq ) end if return end subroutine stdlib${ii}$_${ci}$laed8 #:endif #:endfor pure module subroutine stdlib${ii}$_slaed9( k, kstart, kstop, n, d, q, ldq, rho, dlamda, w,s, lds, info ) !! SLAED9 finds the roots of the secular equation, as defined by the !! values in D, Z, and RHO, between KSTART and KSTOP. It makes the !! appropriate calls to SLAED4 and then stores the new matrix of !! eigenvectors for use in calculating the next level of Z vectors. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_sp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: k, kstart, kstop, ldq, lds, n real(sp), intent(in) :: rho ! Array Arguments real(sp), intent(out) :: d(*), q(ldq,*), s(lds,*) real(sp), intent(inout) :: dlamda(*), w(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: i, j real(sp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( k<0_${ik}$ ) then info = -1_${ik}$ else if( kstart<1_${ik}$ .or. kstart>max( 1_${ik}$, k ) ) then info = -2_${ik}$ else if( max( 1_${ik}$, kstop )<kstart .or. kstop>max( 1_${ik}$, k ) )then info = -3_${ik}$ else if( n<k ) then info = -4_${ik}$ else if( ldq<max( 1_${ik}$, k ) ) then info = -7_${ik}$ else if( lds<max( 1_${ik}$, k ) ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SLAED9', -info ) return end if ! quick return if possible if( k==0 )return ! modify values dlamda(i) to make sure all dlamda(i)-dlamda(j) can ! be computed with high relative accuracy (barring over/underflow). ! this is a problem on machines without a guard digit in ! add/subtract (cray xmp, cray ymp, cray c 90 and cray 2). ! the following code replaces dlamda(i) by 2*dlamda(i)-dlamda(i), ! which on any of these machines zeros out the bottommost ! bit of dlamda(i) if it is 1; this makes the subsequent ! subtractions dlamda(i)-dlamda(j) unproblematic when cancellation ! occurs. on binary machines with a guard digit (almost all ! machines) it does not change dlamda(i) at all. on hexadecimal ! and decimal machines with a guard digit, it slightly ! changes the bottommost bits of dlamda(i). it does not account ! for hexadecimal or decimal machines without guard digits ! (we know of none). we use a subroutine call to compute ! 2*dlambda(i) to prevent optimizing compilers from eliminating ! this code. do i = 1, n dlamda( i ) = stdlib${ii}$_slamc3( dlamda( i ), dlamda( i ) ) - dlamda( i ) end do do j = kstart, kstop call stdlib${ii}$_slaed4( k, j, dlamda, w, q( 1_${ik}$, j ), rho, d( j ), info ) ! if the zero finder fails, the computation is terminated. if( info/=0 )go to 120 end do if( k==1_${ik}$ .or. k==2_${ik}$ ) then do i = 1, k do j = 1, k s( j, i ) = q( j, i ) end do end do go to 120 end if ! compute updated w. call stdlib${ii}$_scopy( k, w, 1_${ik}$, s, 1_${ik}$ ) ! initialize w(i) = q(i,i) call stdlib${ii}$_scopy( k, q, ldq+1, w, 1_${ik}$ ) do j = 1, k do i = 1, j - 1 w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do do i = j + 1, k w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do end do do i = 1, k w( i ) = sign( sqrt( -w( i ) ), s( i, 1_${ik}$ ) ) end do ! compute eigenvectors of the modified rank-1 modification. do j = 1, k do i = 1, k q( i, j ) = w( i ) / q( i, j ) end do temp = stdlib${ii}$_snrm2( k, q( 1_${ik}$, j ), 1_${ik}$ ) do i = 1, k s( i, j ) = q( i, j ) / temp end do end do 120 continue return end subroutine stdlib${ii}$_slaed9 pure module subroutine stdlib${ii}$_dlaed9( k, kstart, kstop, n, d, q, ldq, rho, dlamda, w,s, lds, info ) !! DLAED9 finds the roots of the secular equation, as defined by the !! values in D, Z, and RHO, between KSTART and KSTOP. It makes the !! appropriate calls to DLAED4 and then stores the new matrix of !! eigenvectors for use in calculating the next level of Z vectors. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_dp, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: k, kstart, kstop, ldq, lds, n real(dp), intent(in) :: rho ! Array Arguments real(dp), intent(out) :: d(*), q(ldq,*), s(lds,*) real(dp), intent(inout) :: dlamda(*), w(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: i, j real(dp) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( k<0_${ik}$ ) then info = -1_${ik}$ else if( kstart<1_${ik}$ .or. kstart>max( 1_${ik}$, k ) ) then info = -2_${ik}$ else if( max( 1_${ik}$, kstop )<kstart .or. kstop>max( 1_${ik}$, k ) )then info = -3_${ik}$ else if( n<k ) then info = -4_${ik}$ else if( ldq<max( 1_${ik}$, k ) ) then info = -7_${ik}$ else if( lds<max( 1_${ik}$, k ) ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED9', -info ) return end if ! quick return if possible if( k==0 )return ! modify values dlamda(i) to make sure all dlamda(i)-dlamda(j) can ! be computed with high relative accuracy (barring over/underflow). ! this is a problem on machines without a guard digit in ! add/subtract (cray xmp, cray ymp, cray c 90 and cray 2). ! the following code replaces dlamda(i) by 2*dlamda(i)-dlamda(i), ! which on any of these machines zeros out the bottommost ! bit of dlamda(i) if it is 1; this makes the subsequent ! subtractions dlamda(i)-dlamda(j) unproblematic when cancellation ! occurs. on binary machines with a guard digit (almost all ! machines) it does not change dlamda(i) at all. on hexadecimal ! and decimal machines with a guard digit, it slightly ! changes the bottommost bits of dlamda(i). it does not account ! for hexadecimal or decimal machines without guard digits ! (we know of none). we use a subroutine call to compute ! 2*dlambda(i) to prevent optimizing compilers from eliminating ! this code. do i = 1, n dlamda( i ) = stdlib${ii}$_dlamc3( dlamda( i ), dlamda( i ) ) - dlamda( i ) end do do j = kstart, kstop call stdlib${ii}$_dlaed4( k, j, dlamda, w, q( 1_${ik}$, j ), rho, d( j ), info ) ! if the zero finder fails, the computation is terminated. if( info/=0 )go to 120 end do if( k==1_${ik}$ .or. k==2_${ik}$ ) then do i = 1, k do j = 1, k s( j, i ) = q( j, i ) end do end do go to 120 end if ! compute updated w. call stdlib${ii}$_dcopy( k, w, 1_${ik}$, s, 1_${ik}$ ) ! initialize w(i) = q(i,i) call stdlib${ii}$_dcopy( k, q, ldq+1, w, 1_${ik}$ ) do j = 1, k do i = 1, j - 1 w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do do i = j + 1, k w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do end do do i = 1, k w( i ) = sign( sqrt( -w( i ) ), s( i, 1_${ik}$ ) ) end do ! compute eigenvectors of the modified rank-1 modification. do j = 1, k do i = 1, k q( i, j ) = w( i ) / q( i, j ) end do temp = stdlib${ii}$_dnrm2( k, q( 1_${ik}$, j ), 1_${ik}$ ) do i = 1, k s( i, j ) = q( i, j ) / temp end do end do 120 continue return end subroutine stdlib${ii}$_dlaed9 #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$laed9( k, kstart, kstop, n, d, q, ldq, rho, dlamda, w,s, lds, info ) !! DLAED9: finds the roots of the secular equation, as defined by the !! values in D, Z, and RHO, between KSTART and KSTOP. It makes the !! appropriate calls to DLAED4 and then stores the new matrix of !! eigenvectors for use in calculating the next level of Z vectors. ! -- lapack computational routine -- ! -- lapack is a software package provided by univ. of tennessee, -- ! -- univ. of california berkeley, univ. of colorado denver and nag ltd..-- use stdlib_blas_constants_${rk}$, only: negone, zero, half, one, two, three, four, eight, ten, czero, chalf, cone, cnegone ! Scalar Arguments integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: k, kstart, kstop, ldq, lds, n real(${rk}$), intent(in) :: rho ! Array Arguments real(${rk}$), intent(out) :: d(*), q(ldq,*), s(lds,*) real(${rk}$), intent(inout) :: dlamda(*), w(*) ! ===================================================================== ! Local Scalars integer(${ik}$) :: i, j real(${rk}$) :: temp ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ if( k<0_${ik}$ ) then info = -1_${ik}$ else if( kstart<1_${ik}$ .or. kstart>max( 1_${ik}$, k ) ) then info = -2_${ik}$ else if( max( 1_${ik}$, kstop )<kstart .or. kstop>max( 1_${ik}$, k ) )then info = -3_${ik}$ else if( n<k ) then info = -4_${ik}$ else if( ldq<max( 1_${ik}$, k ) ) then info = -7_${ik}$ else if( lds<max( 1_${ik}$, k ) ) then info = -12_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DLAED9', -info ) return end if ! quick return if possible if( k==0 )return ! modify values dlamda(i) to make sure all dlamda(i)-dlamda(j) can ! be computed with high relative accuracy (barring over/underflow). ! this is a problem on machines without a guard digit in ! add/subtract (cray xmp, cray ymp, cray c 90 and cray 2). ! the following code replaces dlamda(i) by 2*dlamda(i)-dlamda(i), ! which on any of these machines zeros out the bottommost ! bit of dlamda(i) if it is 1; this makes the subsequent ! subtractions dlamda(i)-dlamda(j) unproblematic when cancellation ! occurs. on binary machines with a guard digit (almost all ! machines) it does not change dlamda(i) at all. on hexadecimal ! and decimal machines with a guard digit, it slightly ! changes the bottommost bits of dlamda(i). it does not account ! for hexadecimal or decimal machines without guard digits ! (we know of none). we use a subroutine call to compute ! 2*dlambda(i) to prevent optimizing compilers from eliminating ! this code. do i = 1, n dlamda( i ) = stdlib${ii}$_${ri}$lamc3( dlamda( i ), dlamda( i ) ) - dlamda( i ) end do do j = kstart, kstop call stdlib${ii}$_${ri}$laed4( k, j, dlamda, w, q( 1_${ik}$, j ), rho, d( j ), info ) ! if the zero finder fails, the computation is terminated. if( info/=0 )go to 120 end do if( k==1_${ik}$ .or. k==2_${ik}$ ) then do i = 1, k do j = 1, k s( j, i ) = q( j, i ) end do end do go to 120 end if ! compute updated w. call stdlib${ii}$_${ri}$copy( k, w, 1_${ik}$, s, 1_${ik}$ ) ! initialize w(i) = q(i,i) call stdlib${ii}$_${ri}$copy( k, q, ldq+1, w, 1_${ik}$ ) do j = 1, k do i = 1, j - 1 w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do do i = j + 1, k w( i ) = w( i )*( q( i, j ) / ( dlamda( i )-dlamda( j ) ) ) end do end do do i = 1, k w( i ) = sign( sqrt( -w( i ) ), s( i, 1_${ik}$ ) ) end do ! compute eigenvectors of the modified rank-1 modification. do j = 1, k do i = 1, k q( i, j ) = w( i ) / q( i, j ) end do temp = stdlib${ii}$_${ri}$nrm2( k, q( 1_${ik}$, j ), 1_${ik}$ ) do i = 1, k s( i, j ) = q( i, j ) / temp end do end do 120 continue return end subroutine stdlib${ii}$_${ri}$laed9 #:endif #:endfor #:endfor end submodule stdlib_lapack_eigv_tridiag