stdlib_lapack_eigv_tridiag3.fypp Source File


Source Code

#:include "common.fypp" 
submodule(stdlib_lapack_eig_svd_lsq) stdlib_lapack_eigv_tridiag3
  implicit none


  contains
#:for ik,it,ii in LINALG_INT_KINDS_TYPES

     pure module subroutine stdlib${ii}$_sstev( jobz, n, d, e, z, ldz, work, info )
     !! SSTEV computes all eigenvalues and, optionally, eigenvectors of a
     !! real symmetric tridiagonal matrix A.
        ! -- lapack driver 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 
           character, intent(in) :: jobz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: wantz
           integer(${ik}$) :: imax, iscale
           real(sp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tnrm
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEV ', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_slamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = sqrt( bignum )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           tnrm = stdlib${ii}$_slanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_sscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_sscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
           end if
           ! for eigenvalues only, call stdlib${ii}$_ssterf.  for eigenvalues and
           ! eigenvectors, call stdlib${ii}$_ssteqr.
           if( .not.wantz ) then
              call stdlib${ii}$_ssterf( n, d, e, info )
           else
              call stdlib${ii}$_ssteqr( 'I', n, d, e, z, ldz, work, info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = n
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_sscal( imax, one / sigma, d, 1_${ik}$ )
           end if
           return
     end subroutine stdlib${ii}$_sstev

     pure module subroutine stdlib${ii}$_dstev( jobz, n, d, e, z, ldz, work, info )
     !! DSTEV computes all eigenvalues and, optionally, eigenvectors of a
     !! real symmetric tridiagonal matrix A.
        ! -- lapack driver 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 
           character, intent(in) :: jobz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: wantz
           integer(${ik}$) :: imax, iscale
           real(dp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tnrm
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEV ', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_dlamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = sqrt( bignum )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           tnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_dscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_dscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
           end if
           ! for eigenvalues only, call stdlib${ii}$_dsterf.  for eigenvalues and
           ! eigenvectors, call stdlib${ii}$_dsteqr.
           if( .not.wantz ) then
              call stdlib${ii}$_dsterf( n, d, e, info )
           else
              call stdlib${ii}$_dsteqr( 'I', n, d, e, z, ldz, work, info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = n
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_dscal( imax, one / sigma, d, 1_${ik}$ )
           end if
           return
     end subroutine stdlib${ii}$_dstev

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stev( jobz, n, d, e, z, ldz, work, info )
     !! DSTEV: computes all eigenvalues and, optionally, eigenvectors of a
     !! real symmetric tridiagonal matrix A.
        ! -- lapack driver 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 
           character, intent(in) :: jobz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(${rk}$), intent(inout) :: d(*), e(*)
           real(${rk}$), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: wantz
           integer(${ik}$) :: imax, iscale
           real(${rk}$) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tnrm
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEV ', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_${ri}$lamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_${ri}$lamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = sqrt( bignum )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           tnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_${ri}$scal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_${ri}$scal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
           end if
           ! for eigenvalues only, call stdlib${ii}$_${ri}$sterf.  for eigenvalues and
           ! eigenvectors, call stdlib${ii}$_${ri}$steqr.
           if( .not.wantz ) then
              call stdlib${ii}$_${ri}$sterf( n, d, e, info )
           else
              call stdlib${ii}$_${ri}$steqr( 'I', n, d, e, z, ldz, work, info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = n
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_${ri}$scal( imax, one / sigma, d, 1_${ik}$ )
           end if
           return
     end subroutine stdlib${ii}$_${ri}$stev

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstevd( jobz, n, d, e, z, ldz, work, lwork, iwork,liwork, info )
     !! SSTEVD computes all eigenvalues and, optionally, eigenvectors of a
     !! real symmetric tridiagonal matrix. If eigenvectors are desired, it
     !! uses a divide and conquer algorithm.
     !! The divide and conquer algorithm 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 driver 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 
           character, intent(in) :: jobz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery, wantz
           integer(${ik}$) :: iscale, liwmin, lwmin
           real(sp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tnrm
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           lquery = ( lwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           info = 0_${ik}$
           liwmin = 1_${ik}$
           lwmin = 1_${ik}$
           if( n>1_${ik}$ .and. wantz ) then
              lwmin = 1_${ik}$ + 4_${ik}$*n + n**2_${ik}$
              liwmin = 3_${ik}$ + 5_${ik}$*n
           end if
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -8_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -10_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEVD', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_slamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = sqrt( bignum )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           tnrm = stdlib${ii}$_slanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_sscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_sscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
           end if
           ! for eigenvalues only, call stdlib${ii}$_ssterf.  for eigenvalues and
           ! eigenvectors, call stdlib${ii}$_sstedc.
           if( .not.wantz ) then
              call stdlib${ii}$_ssterf( n, d, e, info )
           else
              call stdlib${ii}$_sstedc( 'I', n, d, e, z, ldz, work, lwork, iwork, liwork,info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           if( iscale==1_${ik}$ )call stdlib${ii}$_sscal( n, one / sigma, d, 1_${ik}$ )
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_sstevd

     pure module subroutine stdlib${ii}$_dstevd( jobz, n, d, e, z, ldz, work, lwork, iwork,liwork, info )
     !! DSTEVD computes all eigenvalues and, optionally, eigenvectors of a
     !! real symmetric tridiagonal matrix. If eigenvectors are desired, it
     !! uses a divide and conquer algorithm.
     !! The divide and conquer algorithm 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 driver 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 
           character, intent(in) :: jobz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery, wantz
           integer(${ik}$) :: iscale, liwmin, lwmin
           real(dp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tnrm
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           lquery = ( lwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           info = 0_${ik}$
           liwmin = 1_${ik}$
           lwmin = 1_${ik}$
           if( n>1_${ik}$ .and. wantz ) then
              lwmin = 1_${ik}$ + 4_${ik}$*n + n**2_${ik}$
              liwmin = 3_${ik}$ + 5_${ik}$*n
           end if
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -8_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -10_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEVD', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_dlamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = sqrt( bignum )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           tnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_dscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_dscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
           end if
           ! for eigenvalues only, call stdlib${ii}$_dsterf.  for eigenvalues and
           ! eigenvectors, call stdlib${ii}$_dstedc.
           if( .not.wantz ) then
              call stdlib${ii}$_dsterf( n, d, e, info )
           else
              call stdlib${ii}$_dstedc( 'I', n, d, e, z, ldz, work, lwork, iwork, liwork,info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           if( iscale==1_${ik}$ )call stdlib${ii}$_dscal( n, one / sigma, d, 1_${ik}$ )
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_dstevd

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stevd( jobz, n, d, e, z, ldz, work, lwork, iwork,liwork, info )
     !! DSTEVD: computes all eigenvalues and, optionally, eigenvectors of a
     !! real symmetric tridiagonal matrix. If eigenvectors are desired, it
     !! uses a divide and conquer algorithm.
     !! The divide and conquer algorithm 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 driver 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 
           character, intent(in) :: jobz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(${rk}$), intent(inout) :: d(*), e(*)
           real(${rk}$), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery, wantz
           integer(${ik}$) :: iscale, liwmin, lwmin
           real(${rk}$) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tnrm
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           lquery = ( lwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           info = 0_${ik}$
           liwmin = 1_${ik}$
           lwmin = 1_${ik}$
           if( n>1_${ik}$ .and. wantz ) then
              lwmin = 1_${ik}$ + 4_${ik}$*n + n**2_${ik}$
              liwmin = 3_${ik}$ + 5_${ik}$*n
           end if
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -8_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -10_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEVD', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_${ri}$lamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_${ri}$lamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = sqrt( bignum )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           tnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_${ri}$scal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_${ri}$scal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
           end if
           ! for eigenvalues only, call stdlib${ii}$_${ri}$sterf.  for eigenvalues and
           ! eigenvectors, call stdlib${ii}$_${ri}$stedc.
           if( .not.wantz ) then
              call stdlib${ii}$_${ri}$sterf( n, d, e, info )
           else
              call stdlib${ii}$_${ri}$stedc( 'I', n, d, e, z, ldz, work, lwork, iwork, liwork,info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           if( iscale==1_${ik}$ )call stdlib${ii}$_${ri}$scal( n, one / sigma, d, 1_${ik}$ )
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_${ri}$stevd

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstevr( jobz, range, n, d, e, vl, vu, il, iu, abstol,m, w, z, ldz, &
     !! SSTEVR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T.  Eigenvalues and
     !! eigenvectors can be selected by specifying either a range of values
     !! or a range of indices for the desired eigenvalues.
     !! Whenever possible, SSTEVR calls SSTEMR to compute the
     !! eigenspectrum using Relatively Robust Representations.  SSTEMR
     !! computes eigenvalues by the dqds algorithm, while orthogonal
     !! eigenvectors are computed from various "good" L D L^T representations
     !! (also known as Relatively Robust Representations). Gram-Schmidt
     !! orthogonalization is avoided as far as possible. More specifically,
     !! the various steps of the algorithm are as follows. For the i-th
     !! unreduced block of T,
     !! (a) Compute T - sigma_i = L_i D_i L_i^T, such that L_i D_i L_i^T
     !! is a relatively robust representation,
     !! (b) Compute the eigenvalues, lambda_j, of L_i D_i L_i^T to high
     !! relative accuracy by the dqds algorithm,
     !! (c) If there is a cluster of close eigenvalues, "choose" sigma_i
     !! close to the cluster, and go to step (a),
     !! (d) Given the approximate eigenvalue lambda_j of L_i D_i L_i^T,
     !! compute the corresponding eigenvector by forming a
     !! rank-revealing twisted factorization.
     !! The desired accuracy of the output can be specified by the input
     !! parameter ABSTOL.
     !! For more details, see "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem", by Inderjit Dhillon,
     !! Computer Science Division Technical Report No. UCB//CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Note 1 : SSTEVR calls SSTEMR when the full spectrum is requested
     !! on machines which conform to the ieee-754 floating point standard.
     !! SSTEVR calls SSTEBZ and SSTEIN on non-ieee machines and
     !! when partial spectrum requests are made.
     !! Normal execution of SSTEMR may create NaNs and infinities and
     !! hence may abort due to a floating point exception in environments
     !! which do not handle NaNs and infinities in the ieee standard default
     !! manner.
               isuppz, work, lwork, iwork,liwork, info )
        ! -- lapack driver 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(sp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, test, lquery, valeig, wantz, tryrac
           character :: order
           integer(${ik}$) :: i, ieeeok, imax, indibl, indifl, indisp, indiwo, iscale, j, jj, liwmin,&
                      lwmin, nsplit
           real(sp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tmp1, tnrm, vll, &
                     vuu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           ieeeok = stdlib${ii}$_ilaenv( 10_${ik}$, 'SSTEVR', 'N', 1_${ik}$, 2_${ik}$, 3_${ik}$, 4_${ik}$ )
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ) .or. ( liwork==-1_${ik}$ ) )
           lwmin = max( 1_${ik}$, 20_${ik}$*n )
           liwmin = max(1_${ik}$, 10_${ik}$*n )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else
              if( valeig ) then
                 if( n>0_${ik}$ .and. vu<=vl )info = -7_${ik}$
              else if( indeig ) then
                 if( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) then
                    info = -8_${ik}$
                 else if( iu<min( n, il ) .or. iu>n ) then
                    info = -9_${ik}$
                 end if
              end if
           end if
           if( info==0_${ik}$ ) then
              if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
                 info = -14_${ik}$
              end if
           end if
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -17_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -19_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEVR', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( vl<d( 1_${ik}$ ) .and. vu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_slamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           if( valeig ) then
              vll = vl
              vuu = vu
           end if
           tnrm = stdlib${ii}$_slanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_sscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_sscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
              if( valeig ) then
                 vll = vl*sigma
                 vuu = vu*sigma
              end if
           end if
           ! initialize indices into workspaces.  note: these indices are used only
           ! if stdlib${ii}$_ssterf or stdlib${ii}$_sstemr fail.
           ! iwork(indibl:indibl+m-1) corresponds to iblock in stdlib${ii}$_sstebz and
           ! stores the block indices of each of the m<=n eigenvalues.
           indibl = 1_${ik}$
           ! iwork(indisp:indisp+nsplit-1) corresponds to isplit in stdlib${ii}$_sstebz and
           ! stores the starting and finishing indices of each block.
           indisp = indibl + n
           ! iwork(indifl:indifl+n-1) stores the indices of eigenvectors
           ! that corresponding to eigenvectors that fail to converge in
           ! stdlib${ii}$_sstein.  this information is discarded; if any fail, the driver
           ! returns info > 0.
           indifl = indisp + n
           ! indiwo is the offset of the remaining integer workspace.
           indiwo = indisp + n
           ! if all eigenvalues are desired, then
           ! call stdlib${ii}$_ssterf or stdlib${ii}$_sstemr.  if this fails for some eigenvalue, then
           ! try stdlib${ii}$_sstebz.
           test = .false.
           if( indeig ) then
              if( il==1_${ik}$ .and. iu==n ) then
                 test = .true.
              end if
           end if
           if( ( alleig .or. test ) .and. ieeeok==1_${ik}$ ) then
              call stdlib${ii}$_scopy( n-1, e( 1_${ik}$ ), 1_${ik}$, work( 1_${ik}$ ), 1_${ik}$ )
              if( .not.wantz ) then
                 call stdlib${ii}$_scopy( n, d, 1_${ik}$, w, 1_${ik}$ )
                 call stdlib${ii}$_ssterf( n, w, work, info )
              else
                 call stdlib${ii}$_scopy( n, d, 1_${ik}$, work( n+1 ), 1_${ik}$ )
                 if (abstol <= two*n*eps) then
                    tryrac = .true.
                 else
                    tryrac = .false.
                 end if
                 call stdlib${ii}$_sstemr( jobz, 'A', n, work( n+1 ), work, vl, vu, il,iu, m, w, z, ldz,&
                            n, isuppz, tryrac,work( 2_${ik}$*n+1 ), lwork-2*n, iwork, liwork, info )
              end if
              if( info==0_${ik}$ ) then
                 m = n
                 go to 10
              end if
              info = 0_${ik}$
           end if
           ! otherwise, call stdlib${ii}$_sstebz and, if eigenvectors are desired, stdlib${ii}$_sstein.
           if( wantz ) then
              order = 'B'
           else
              order = 'E'
           end if
           call stdlib${ii}$_sstebz( range, order, n, vll, vuu, il, iu, abstol, d, e, m,nsplit, w, &
                     iwork( indibl ), iwork( indisp ), work,iwork( indiwo ), info )
           if( wantz ) then
              call stdlib${ii}$_sstein( n, d, e, m, w, iwork( indibl ), iwork( indisp ),z, ldz, work, &
                        iwork( indiwo ), iwork( indifl ),info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           10 continue
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = m
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_sscal( imax, one / sigma, w, 1_${ik}$ )
           end if
           ! if eigenvalues are not in order, then sort them, along with
           ! eigenvectors.
           if( wantz ) then
              do j = 1, m - 1
                 i = 0_${ik}$
                 tmp1 = w( j )
                 do jj = j + 1, m
                    if( w( jj )<tmp1 ) then
                       i = jj
                       tmp1 = w( jj )
                    end if
                 end do
                 if( i/=0_${ik}$ ) then
                    w( i ) = w( j )
                    w( j ) = tmp1
                    call stdlib${ii}$_sswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                 end if
              end do
           end if
            ! causes problems with tests 19
            ! if (wantz .and. indeig ) z( 1,1) = z(1,1) / 1.002_sp + .002
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_sstevr

     pure module subroutine stdlib${ii}$_dstevr( jobz, range, n, d, e, vl, vu, il, iu, abstol,m, w, z, ldz, &
     !! DSTEVR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T.  Eigenvalues and
     !! eigenvectors can be selected by specifying either a range of values
     !! or a range of indices for the desired eigenvalues.
     !! Whenever possible, DSTEVR calls DSTEMR to compute the
     !! eigenspectrum using Relatively Robust Representations.  DSTEMR
     !! computes eigenvalues by the dqds algorithm, while orthogonal
     !! eigenvectors are computed from various "good" L D L^T representations
     !! (also known as Relatively Robust Representations). Gram-Schmidt
     !! orthogonalization is avoided as far as possible. More specifically,
     !! the various steps of the algorithm are as follows. For the i-th
     !! unreduced block of T,
     !! (a) Compute T - sigma_i = L_i D_i L_i^T, such that L_i D_i L_i^T
     !! is a relatively robust representation,
     !! (b) Compute the eigenvalues, lambda_j, of L_i D_i L_i^T to high
     !! relative accuracy by the dqds algorithm,
     !! (c) If there is a cluster of close eigenvalues, "choose" sigma_i
     !! close to the cluster, and go to step (a),
     !! (d) Given the approximate eigenvalue lambda_j of L_i D_i L_i^T,
     !! compute the corresponding eigenvector by forming a
     !! rank-revealing twisted factorization.
     !! The desired accuracy of the output can be specified by the input
     !! parameter ABSTOL.
     !! For more details, see "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem", by Inderjit Dhillon,
     !! Computer Science Division Technical Report No. UCB//CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Note 1 : DSTEVR calls DSTEMR when the full spectrum is requested
     !! on machines which conform to the ieee-754 floating point standard.
     !! DSTEVR calls DSTEBZ and DSTEIN on non-ieee machines and
     !! when partial spectrum requests are made.
     !! Normal execution of DSTEMR may create NaNs and infinities and
     !! hence may abort due to a floating point exception in environments
     !! which do not handle NaNs and infinities in the ieee standard default
     !! manner.
               isuppz, work, lwork, iwork,liwork, info )
        ! -- lapack driver 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(dp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, test, lquery, valeig, wantz, tryrac
           character :: order
           integer(${ik}$) :: i, ieeeok, imax, indibl, indifl, indisp, indiwo, iscale, itmp1, j, jj, &
                     liwmin, lwmin, nsplit
           real(dp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tmp1, tnrm, vll, &
                     vuu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           ieeeok = stdlib${ii}$_ilaenv( 10_${ik}$, 'DSTEVR', 'N', 1_${ik}$, 2_${ik}$, 3_${ik}$, 4_${ik}$ )
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ) .or. ( liwork==-1_${ik}$ ) )
           lwmin = max( 1_${ik}$, 20_${ik}$*n )
           liwmin = max( 1_${ik}$, 10_${ik}$*n )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else
              if( valeig ) then
                 if( n>0_${ik}$ .and. vu<=vl )info = -7_${ik}$
              else if( indeig ) then
                 if( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) then
                    info = -8_${ik}$
                 else if( iu<min( n, il ) .or. iu>n ) then
                    info = -9_${ik}$
                 end if
              end if
           end if
           if( info==0_${ik}$ ) then
              if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
                 info = -14_${ik}$
              end if
           end if
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -17_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -19_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEVR', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( vl<d( 1_${ik}$ ) .and. vu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_dlamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           if( valeig ) then
              vll = vl
              vuu = vu
           end if
           tnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_dscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_dscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
              if( valeig ) then
                 vll = vl*sigma
                 vuu = vu*sigma
              end if
           end if
           ! initialize indices into workspaces.  note: these indices are used only
           ! if stdlib${ii}$_dsterf or stdlib${ii}$_dstemr fail.
           ! iwork(indibl:indibl+m-1) corresponds to iblock in stdlib${ii}$_dstebz and
           ! stores the block indices of each of the m<=n eigenvalues.
           indibl = 1_${ik}$
           ! iwork(indisp:indisp+nsplit-1) corresponds to isplit in stdlib${ii}$_dstebz and
           ! stores the starting and finishing indices of each block.
           indisp = indibl + n
           ! iwork(indifl:indifl+n-1) stores the indices of eigenvectors
           ! that corresponding to eigenvectors that fail to converge in
           ! stdlib${ii}$_dstein.  this information is discarded; if any fail, the driver
           ! returns info > 0.
           indifl = indisp + n
           ! indiwo is the offset of the remaining integer workspace.
           indiwo = indisp + n
           ! if all eigenvalues are desired, then
           ! call stdlib${ii}$_dsterf or stdlib${ii}$_dstemr.  if this fails for some eigenvalue, then
           ! try stdlib${ii}$_dstebz.
           test = .false.
           if( indeig ) then
              if( il==1_${ik}$ .and. iu==n ) then
                 test = .true.
              end if
           end if
           if( ( alleig .or. test ) .and. ieeeok==1_${ik}$ ) then
              call stdlib${ii}$_dcopy( n-1, e( 1_${ik}$ ), 1_${ik}$, work( 1_${ik}$ ), 1_${ik}$ )
              if( .not.wantz ) then
                 call stdlib${ii}$_dcopy( n, d, 1_${ik}$, w, 1_${ik}$ )
                 call stdlib${ii}$_dsterf( n, w, work, info )
              else
                 call stdlib${ii}$_dcopy( n, d, 1_${ik}$, work( n+1 ), 1_${ik}$ )
                 if (abstol <= two*n*eps) then
                    tryrac = .true.
                 else
                    tryrac = .false.
                 end if
                 call stdlib${ii}$_dstemr( jobz, 'A', n, work( n+1 ), work, vl, vu, il,iu, m, w, z, ldz,&
                            n, isuppz, tryrac,work( 2_${ik}$*n+1 ), lwork-2*n, iwork, liwork, info )
              end if
              if( info==0_${ik}$ ) then
                 m = n
                 go to 10
              end if
              info = 0_${ik}$
           end if
           ! otherwise, call stdlib${ii}$_dstebz and, if eigenvectors are desired, stdlib${ii}$_dstein.
           if( wantz ) then
              order = 'B'
           else
              order = 'E'
           end if
           call stdlib${ii}$_dstebz( range, order, n, vll, vuu, il, iu, abstol, d, e, m,nsplit, w, &
                     iwork( indibl ), iwork( indisp ), work,iwork( indiwo ), info )
           if( wantz ) then
              call stdlib${ii}$_dstein( n, d, e, m, w, iwork( indibl ), iwork( indisp ),z, ldz, work, &
                        iwork( indiwo ), iwork( indifl ),info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           10 continue
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = m
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_dscal( imax, one / sigma, w, 1_${ik}$ )
           end if
           ! if eigenvalues are not in order, then sort them, along with
           ! eigenvectors.
           if( wantz ) then
              do j = 1, m - 1
                 i = 0_${ik}$
                 tmp1 = w( j )
                 do jj = j + 1, m
                    if( w( jj )<tmp1 ) then
                       i = jj
                       tmp1 = w( jj )
                    end if
                 end do
                 if( i/=0_${ik}$ ) then
                    itmp1 = iwork( i )
                    w( i ) = w( j )
                    iwork( i ) = iwork( j )
                    w( j ) = tmp1
                    iwork( j ) = itmp1
                    call stdlib${ii}$_dswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                 end if
              end do
           end if
            ! causes problems with tests 19
            ! if (wantz .and. indeig ) z( 1,1) = z(1,1) / 1.002_dp + .002
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_dstevr

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stevr( jobz, range, n, d, e, vl, vu, il, iu, abstol,m, w, z, ldz, &
     !! DSTEVR: computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T.  Eigenvalues and
     !! eigenvectors can be selected by specifying either a range of values
     !! or a range of indices for the desired eigenvalues.
     !! Whenever possible, DSTEVR calls DSTEMR to compute the
     !! eigenspectrum using Relatively Robust Representations.  DSTEMR
     !! computes eigenvalues by the dqds algorithm, while orthogonal
     !! eigenvectors are computed from various "good" L D L^T representations
     !! (also known as Relatively Robust Representations). Gram-Schmidt
     !! orthogonalization is avoided as far as possible. More specifically,
     !! the various steps of the algorithm are as follows. For the i-th
     !! unreduced block of T,
     !! (a) Compute T - sigma_i = L_i D_i L_i^T, such that L_i D_i L_i^T
     !! is a relatively robust representation,
     !! (b) Compute the eigenvalues, lambda_j, of L_i D_i L_i^T to high
     !! relative accuracy by the dqds algorithm,
     !! (c) If there is a cluster of close eigenvalues, "choose" sigma_i
     !! close to the cluster, and go to step (a),
     !! (d) Given the approximate eigenvalue lambda_j of L_i D_i L_i^T,
     !! compute the corresponding eigenvector by forming a
     !! rank-revealing twisted factorization.
     !! The desired accuracy of the output can be specified by the input
     !! parameter ABSTOL.
     !! For more details, see "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem", by Inderjit Dhillon,
     !! Computer Science Division Technical Report No. UCB//CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Note 1 : DSTEVR calls DSTEMR when the full spectrum is requested
     !! on machines which conform to the ieee-754 floating point standard.
     !! DSTEVR calls DSTEBZ and DSTEIN on non-ieee machines and
     !! when partial spectrum requests are made.
     !! Normal execution of DSTEMR may create NaNs and infinities and
     !! hence may abort due to a floating point exception in environments
     !! which do not handle NaNs and infinities in the ieee standard default
     !! manner.
               isuppz, work, lwork, iwork,liwork, info )
        ! -- lapack driver 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(${rk}$), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(${rk}$), intent(inout) :: d(*), e(*)
           real(${rk}$), intent(out) :: w(*), work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, test, lquery, valeig, wantz, tryrac
           character :: order
           integer(${ik}$) :: i, ieeeok, imax, indibl, indifl, indisp, indiwo, iscale, itmp1, j, jj, &
                     liwmin, lwmin, nsplit
           real(${rk}$) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tmp1, tnrm, vll, &
                     vuu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           ieeeok = stdlib${ii}$_ilaenv( 10_${ik}$, 'DSTEVR', 'N', 1_${ik}$, 2_${ik}$, 3_${ik}$, 4_${ik}$ )
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ) .or. ( liwork==-1_${ik}$ ) )
           lwmin = max( 1_${ik}$, 20_${ik}$*n )
           liwmin = max( 1_${ik}$, 10_${ik}$*n )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else
              if( valeig ) then
                 if( n>0_${ik}$ .and. vu<=vl )info = -7_${ik}$
              else if( indeig ) then
                 if( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) then
                    info = -8_${ik}$
                 else if( iu<min( n, il ) .or. iu>n ) then
                    info = -9_${ik}$
                 end if
              end if
           end if
           if( info==0_${ik}$ ) then
              if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
                 info = -14_${ik}$
              end if
           end if
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -17_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -19_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEVR', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( vl<d( 1_${ik}$ ) .and. vu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_${ri}$lamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_${ri}$lamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           if( valeig ) then
              vll = vl
              vuu = vu
           end if
           tnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_${ri}$scal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_${ri}$scal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
              if( valeig ) then
                 vll = vl*sigma
                 vuu = vu*sigma
              end if
           end if
           ! initialize indices into workspaces.  note: these indices are used only
           ! if stdlib${ii}$_${ri}$sterf or stdlib${ii}$_${ri}$stemr fail.
           ! iwork(indibl:indibl+m-1) corresponds to iblock in stdlib${ii}$_${ri}$stebz and
           ! stores the block indices of each of the m<=n eigenvalues.
           indibl = 1_${ik}$
           ! iwork(indisp:indisp+nsplit-1) corresponds to isplit in stdlib${ii}$_${ri}$stebz and
           ! stores the starting and finishing indices of each block.
           indisp = indibl + n
           ! iwork(indifl:indifl+n-1) stores the indices of eigenvectors
           ! that corresponding to eigenvectors that fail to converge in
           ! stdlib${ii}$_${ri}$stein.  this information is discarded; if any fail, the driver
           ! returns info > 0.
           indifl = indisp + n
           ! indiwo is the offset of the remaining integer workspace.
           indiwo = indisp + n
           ! if all eigenvalues are desired, then
           ! call stdlib${ii}$_${ri}$sterf or stdlib${ii}$_${ri}$stemr.  if this fails for some eigenvalue, then
           ! try stdlib${ii}$_${ri}$stebz.
           test = .false.
           if( indeig ) then
              if( il==1_${ik}$ .and. iu==n ) then
                 test = .true.
              end if
           end if
           if( ( alleig .or. test ) .and. ieeeok==1_${ik}$ ) then
              call stdlib${ii}$_${ri}$copy( n-1, e( 1_${ik}$ ), 1_${ik}$, work( 1_${ik}$ ), 1_${ik}$ )
              if( .not.wantz ) then
                 call stdlib${ii}$_${ri}$copy( n, d, 1_${ik}$, w, 1_${ik}$ )
                 call stdlib${ii}$_${ri}$sterf( n, w, work, info )
              else
                 call stdlib${ii}$_${ri}$copy( n, d, 1_${ik}$, work( n+1 ), 1_${ik}$ )
                 if (abstol <= two*n*eps) then
                    tryrac = .true.
                 else
                    tryrac = .false.
                 end if
                 call stdlib${ii}$_${ri}$stemr( jobz, 'A', n, work( n+1 ), work, vl, vu, il,iu, m, w, z, ldz,&
                            n, isuppz, tryrac,work( 2_${ik}$*n+1 ), lwork-2*n, iwork, liwork, info )
              end if
              if( info==0_${ik}$ ) then
                 m = n
                 go to 10
              end if
              info = 0_${ik}$
           end if
           ! otherwise, call stdlib${ii}$_${ri}$stebz and, if eigenvectors are desired, stdlib${ii}$_${ri}$stein.
           if( wantz ) then
              order = 'B'
           else
              order = 'E'
           end if
           call stdlib${ii}$_${ri}$stebz( range, order, n, vll, vuu, il, iu, abstol, d, e, m,nsplit, w, &
                     iwork( indibl ), iwork( indisp ), work,iwork( indiwo ), info )
           if( wantz ) then
              call stdlib${ii}$_${ri}$stein( n, d, e, m, w, iwork( indibl ), iwork( indisp ),z, ldz, work, &
                        iwork( indiwo ), iwork( indifl ),info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           10 continue
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = m
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_${ri}$scal( imax, one / sigma, w, 1_${ik}$ )
           end if
           ! if eigenvalues are not in order, then sort them, along with
           ! eigenvectors.
           if( wantz ) then
              do j = 1, m - 1
                 i = 0_${ik}$
                 tmp1 = w( j )
                 do jj = j + 1, m
                    if( w( jj )<tmp1 ) then
                       i = jj
                       tmp1 = w( jj )
                    end if
                 end do
                 if( i/=0_${ik}$ ) then
                    itmp1 = iwork( i )
                    w( i ) = w( j )
                    iwork( i ) = iwork( j )
                    w( j ) = tmp1
                    iwork( j ) = itmp1
                    call stdlib${ii}$_${ri}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                 end if
              end do
           end if
            ! causes problems with tests 19
            ! if (wantz .and. indeig ) z( 1,1) = z(1,1) / 1.002_${rk}$ + .002
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_${ri}$stevr

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstevx( jobz, range, n, d, e, vl, vu, il, iu, abstol,m, w, z, ldz, &
     !! SSTEVX computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix A.  Eigenvalues and
     !! eigenvectors can be selected by specifying either a range of values
     !! or a range of indices for the desired eigenvalues.
               work, iwork, ifail, info )
        ! -- lapack driver 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, n
           integer(${ik}$), intent(out) :: info, m
           real(sp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, test, valeig, wantz
           character :: order
           integer(${ik}$) :: i, imax, indibl, indisp, indiwo, indwrk, iscale, itmp1, j, jj, &
                     nsplit
           real(sp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tmp1, tnrm, vll, &
                     vuu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else
              if( valeig ) then
                 if( n>0_${ik}$ .and. vu<=vl )info = -7_${ik}$
              else if( indeig ) then
                 if( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) then
                    info = -8_${ik}$
                 else if( iu<min( n, il ) .or. iu>n ) then
                    info = -9_${ik}$
                 end if
              end if
           end if
           if( info==0_${ik}$ ) then
              if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) )info = -14_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEVX', -info )
              return
           end if
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( vl<d( 1_${ik}$ ) .and. vu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_slamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           if ( valeig ) then
              vll = vl
              vuu = vu
           else
              vll = zero
              vuu = zero
           endif
           tnrm = stdlib${ii}$_slanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_sscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_sscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
              if( valeig ) then
                 vll = vl*sigma
                 vuu = vu*sigma
              end if
           end if
           ! if all eigenvalues are desired and abstol is less than zero, then
           ! call stdlib${ii}$_ssterf or stdlib${ii}$_ssteqr.  if this fails for some eigenvalue, then
           ! try stdlib${ii}$_sstebz.
           test = .false.
           if( indeig ) then
              if( il==1_${ik}$ .and. iu==n ) then
                 test = .true.
              end if
           end if
           if( ( alleig .or. test ) .and. ( abstol<=zero ) ) then
              call stdlib${ii}$_scopy( n, d, 1_${ik}$, w, 1_${ik}$ )
              call stdlib${ii}$_scopy( n-1, e( 1_${ik}$ ), 1_${ik}$, work( 1_${ik}$ ), 1_${ik}$ )
              indwrk = n + 1_${ik}$
              if( .not.wantz ) then
                 call stdlib${ii}$_ssterf( n, w, work, info )
              else
                 call stdlib${ii}$_ssteqr( 'I', n, w, work, z, ldz, work( indwrk ), info )
                 if( info==0_${ik}$ ) then
                    do i = 1, n
                       ifail( i ) = 0_${ik}$
                    end do
                 end if
              end if
              if( info==0_${ik}$ ) then
                 m = n
                 go to 20
              end if
              info = 0_${ik}$
           end if
           ! otherwise, call stdlib${ii}$_sstebz and, if eigenvectors are desired, stdlib${ii}$_sstein.
           if( wantz ) then
              order = 'B'
           else
              order = 'E'
           end if
           indwrk = 1_${ik}$
           indibl = 1_${ik}$
           indisp = indibl + n
           indiwo = indisp + n
           call stdlib${ii}$_sstebz( range, order, n, vll, vuu, il, iu, abstol, d, e, m,nsplit, w, &
                     iwork( indibl ), iwork( indisp ),work( indwrk ), iwork( indiwo ), info )
           if( wantz ) then
              call stdlib${ii}$_sstein( n, d, e, m, w, iwork( indibl ), iwork( indisp ),z, ldz, work( &
                        indwrk ), iwork( indiwo ), ifail,info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           20 continue
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = m
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_sscal( imax, one / sigma, w, 1_${ik}$ )
           end if
           ! if eigenvalues are not in order, then sort them, along with
           ! eigenvectors.
           if( wantz ) then
              do j = 1, m - 1
                 i = 0_${ik}$
                 tmp1 = w( j )
                 do jj = j + 1, m
                    if( w( jj )<tmp1 ) then
                       i = jj
                       tmp1 = w( jj )
                    end if
                 end do
                 if( i/=0_${ik}$ ) then
                    itmp1 = iwork( indibl+i-1 )
                    w( i ) = w( j )
                    iwork( indibl+i-1 ) = iwork( indibl+j-1 )
                    w( j ) = tmp1
                    iwork( indibl+j-1 ) = itmp1
                    call stdlib${ii}$_sswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                    if( info/=0_${ik}$ ) then
                       itmp1 = ifail( i )
                       ifail( i ) = ifail( j )
                       ifail( j ) = itmp1
                    end if
                 end if
              end do
           end if
           return
     end subroutine stdlib${ii}$_sstevx

     pure module subroutine stdlib${ii}$_dstevx( jobz, range, n, d, e, vl, vu, il, iu, abstol,m, w, z, ldz, &
     !! DSTEVX computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix A.  Eigenvalues and
     !! eigenvectors can be selected by specifying either a range of values
     !! or a range of indices for the desired eigenvalues.
               work, iwork, ifail, info )
        ! -- lapack driver 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, n
           integer(${ik}$), intent(out) :: info, m
           real(dp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, test, valeig, wantz
           character :: order
           integer(${ik}$) :: i, imax, indibl, indisp, indiwo, indwrk, iscale, itmp1, j, jj, &
                     nsplit
           real(dp) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tmp1, tnrm, vll, &
                     vuu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else
              if( valeig ) then
                 if( n>0_${ik}$ .and. vu<=vl )info = -7_${ik}$
              else if( indeig ) then
                 if( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) then
                    info = -8_${ik}$
                 else if( iu<min( n, il ) .or. iu>n ) then
                    info = -9_${ik}$
                 end if
              end if
           end if
           if( info==0_${ik}$ ) then
              if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) )info = -14_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEVX', -info )
              return
           end if
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( vl<d( 1_${ik}$ ) .and. vu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_dlamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           if( valeig ) then
              vll = vl
              vuu = vu
           else
              vll = zero
              vuu = zero
           end if
           tnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_dscal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_dscal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
              if( valeig ) then
                 vll = vl*sigma
                 vuu = vu*sigma
              end if
           end if
           ! if all eigenvalues are desired and abstol is less than zero, then
           ! call stdlib${ii}$_dsterf or stdlib${ii}$_ssteqr.  if this fails for some eigenvalue, then
           ! try stdlib${ii}$_dstebz.
           test = .false.
           if( indeig ) then
              if( il==1_${ik}$ .and. iu==n ) then
                 test = .true.
              end if
           end if
           if( ( alleig .or. test ) .and. ( abstol<=zero ) ) then
              call stdlib${ii}$_dcopy( n, d, 1_${ik}$, w, 1_${ik}$ )
              call stdlib${ii}$_dcopy( n-1, e( 1_${ik}$ ), 1_${ik}$, work( 1_${ik}$ ), 1_${ik}$ )
              indwrk = n + 1_${ik}$
              if( .not.wantz ) then
                 call stdlib${ii}$_dsterf( n, w, work, info )
              else
                 call stdlib${ii}$_dsteqr( 'I', n, w, work, z, ldz, work( indwrk ), info )
                 if( info==0_${ik}$ ) then
                    do i = 1, n
                       ifail( i ) = 0_${ik}$
                    end do
                 end if
              end if
              if( info==0_${ik}$ ) then
                 m = n
                 go to 20
              end if
              info = 0_${ik}$
           end if
           ! otherwise, call stdlib${ii}$_dstebz and, if eigenvectors are desired, stdlib${ii}$_sstein.
           if( wantz ) then
              order = 'B'
           else
              order = 'E'
           end if
           indwrk = 1_${ik}$
           indibl = 1_${ik}$
           indisp = indibl + n
           indiwo = indisp + n
           call stdlib${ii}$_dstebz( range, order, n, vll, vuu, il, iu, abstol, d, e, m,nsplit, w, &
                     iwork( indibl ), iwork( indisp ),work( indwrk ), iwork( indiwo ), info )
           if( wantz ) then
              call stdlib${ii}$_dstein( n, d, e, m, w, iwork( indibl ), iwork( indisp ),z, ldz, work( &
                        indwrk ), iwork( indiwo ), ifail,info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           20 continue
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = m
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_dscal( imax, one / sigma, w, 1_${ik}$ )
           end if
           ! if eigenvalues are not in order, then sort them, along with
           ! eigenvectors.
           if( wantz ) then
              do j = 1, m - 1
                 i = 0_${ik}$
                 tmp1 = w( j )
                 do jj = j + 1, m
                    if( w( jj )<tmp1 ) then
                       i = jj
                       tmp1 = w( jj )
                    end if
                 end do
                 if( i/=0_${ik}$ ) then
                    itmp1 = iwork( indibl+i-1 )
                    w( i ) = w( j )
                    iwork( indibl+i-1 ) = iwork( indibl+j-1 )
                    w( j ) = tmp1
                    iwork( indibl+j-1 ) = itmp1
                    call stdlib${ii}$_dswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                    if( info/=0_${ik}$ ) then
                       itmp1 = ifail( i )
                       ifail( i ) = ifail( j )
                       ifail( j ) = itmp1
                    end if
                 end if
              end do
           end if
           return
     end subroutine stdlib${ii}$_dstevx

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stevx( jobz, range, n, d, e, vl, vu, il, iu, abstol,m, w, z, ldz, &
     !! DSTEVX: computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix A.  Eigenvalues and
     !! eigenvectors can be selected by specifying either a range of values
     !! or a range of indices for the desired eigenvalues.
               work, iwork, ifail, info )
        ! -- lapack driver 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, n
           integer(${ik}$), intent(out) :: info, m
           real(${rk}$), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(${rk}$), intent(inout) :: d(*), e(*)
           real(${rk}$), intent(out) :: w(*), work(*), z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, test, valeig, wantz
           character :: order
           integer(${ik}$) :: i, imax, indibl, indisp, indiwo, indwrk, iscale, itmp1, j, jj, &
                     nsplit
           real(${rk}$) :: bignum, eps, rmax, rmin, safmin, sigma, smlnum, tmp1, tnrm, vll, &
                     vuu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else
              if( valeig ) then
                 if( n>0_${ik}$ .and. vu<=vl )info = -7_${ik}$
              else if( indeig ) then
                 if( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) then
                    info = -8_${ik}$
                 else if( iu<min( n, il ) .or. iu>n ) then
                    info = -9_${ik}$
                 end if
              end if
           end if
           if( info==0_${ik}$ ) then
              if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) )info = -14_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEVX', -info )
              return
           end if
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( vl<d( 1_${ik}$ ) .and. vu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_${ri}$lamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_${ri}$lamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           ! scale matrix to allowable range, if necessary.
           iscale = 0_${ik}$
           if( valeig ) then
              vll = vl
              vuu = vu
           else
              vll = zero
              vuu = zero
           end if
           tnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e )
           if( tnrm>zero .and. tnrm<rmin ) then
              iscale = 1_${ik}$
              sigma = rmin / tnrm
           else if( tnrm>rmax ) then
              iscale = 1_${ik}$
              sigma = rmax / tnrm
           end if
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_${ri}$scal( n, sigma, d, 1_${ik}$ )
              call stdlib${ii}$_${ri}$scal( n-1, sigma, e( 1_${ik}$ ), 1_${ik}$ )
              if( valeig ) then
                 vll = vl*sigma
                 vuu = vu*sigma
              end if
           end if
           ! if all eigenvalues are desired and abstol is less than zero, then
           ! call stdlib${ii}$_${ri}$sterf or stdlib${ii}$_dsteqr.  if this fails for some eigenvalue, then
           ! try stdlib${ii}$_${ri}$stebz.
           test = .false.
           if( indeig ) then
              if( il==1_${ik}$ .and. iu==n ) then
                 test = .true.
              end if
           end if
           if( ( alleig .or. test ) .and. ( abstol<=zero ) ) then
              call stdlib${ii}$_${ri}$copy( n, d, 1_${ik}$, w, 1_${ik}$ )
              call stdlib${ii}$_${ri}$copy( n-1, e( 1_${ik}$ ), 1_${ik}$, work( 1_${ik}$ ), 1_${ik}$ )
              indwrk = n + 1_${ik}$
              if( .not.wantz ) then
                 call stdlib${ii}$_${ri}$sterf( n, w, work, info )
              else
                 call stdlib${ii}$_${ri}$steqr( 'I', n, w, work, z, ldz, work( indwrk ), info )
                 if( info==0_${ik}$ ) then
                    do i = 1, n
                       ifail( i ) = 0_${ik}$
                    end do
                 end if
              end if
              if( info==0_${ik}$ ) then
                 m = n
                 go to 20
              end if
              info = 0_${ik}$
           end if
           ! otherwise, call stdlib${ii}$_${ri}$stebz and, if eigenvectors are desired, stdlib${ii}$_dstein.
           if( wantz ) then
              order = 'B'
           else
              order = 'E'
           end if
           indwrk = 1_${ik}$
           indibl = 1_${ik}$
           indisp = indibl + n
           indiwo = indisp + n
           call stdlib${ii}$_${ri}$stebz( range, order, n, vll, vuu, il, iu, abstol, d, e, m,nsplit, w, &
                     iwork( indibl ), iwork( indisp ),work( indwrk ), iwork( indiwo ), info )
           if( wantz ) then
              call stdlib${ii}$_${ri}$stein( n, d, e, m, w, iwork( indibl ), iwork( indisp ),z, ldz, work( &
                        indwrk ), iwork( indiwo ), ifail,info )
           end if
           ! if matrix was scaled, then rescale eigenvalues appropriately.
           20 continue
           if( iscale==1_${ik}$ ) then
              if( info==0_${ik}$ ) then
                 imax = m
              else
                 imax = info - 1_${ik}$
              end if
              call stdlib${ii}$_${ri}$scal( imax, one / sigma, w, 1_${ik}$ )
           end if
           ! if eigenvalues are not in order, then sort them, along with
           ! eigenvectors.
           if( wantz ) then
              do j = 1, m - 1
                 i = 0_${ik}$
                 tmp1 = w( j )
                 do jj = j + 1, m
                    if( w( jj )<tmp1 ) then
                       i = jj
                       tmp1 = w( jj )
                    end if
                 end do
                 if( i/=0_${ik}$ ) then
                    itmp1 = iwork( indibl+i-1 )
                    w( i ) = w( j )
                    iwork( indibl+i-1 ) = iwork( indibl+j-1 )
                    w( j ) = tmp1
                    iwork( indibl+j-1 ) = itmp1
                    call stdlib${ii}$_${ri}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                    if( info/=0_${ik}$ ) then
                       itmp1 = ifail( i )
                       ifail( i ) = ifail( j )
                       ifail( j ) = itmp1
                    end if
                 end if
              end do
           end if
           return
     end subroutine stdlib${ii}$_${ri}$stevx

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_spteqr( compz, n, d, e, z, ldz, work, info )
     !! SPTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric positive definite tridiagonal matrix by first factoring the
     !! matrix using SPTTRF, and then calling SBDSQR to compute the singular
     !! values of the bidiagonal factor.
     !! This routine computes the eigenvalues of the positive definite
     !! tridiagonal matrix to high relative accuracy.  This means that if the
     !! eigenvalues range over many orders of magnitude in size, then the
     !! small eigenvalues and corresponding eigenvectors will be computed
     !! more accurately than, for example, with the standard QR method.
     !! The eigenvectors of a full or band symmetric positive definite matrix
     !! can also be found if SSYTRD, SSPTRD, or SSBTRD has been used to
     !! reduce this matrix to tridiagonal form. (The reduction to tridiagonal
     !! form, however, may preclude the possibility of obtaining high
     !! relative accuracy in the small eigenvalues of the original matrix, if
     !! these eigenvalues range over many orders of magnitude.)
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(sp), intent(inout) :: d(*), e(*), z(ldz,*)
           real(sp), intent(out) :: work(*)
        ! =====================================================================
           
           ! Local Arrays 
           real(sp) :: c(1_${ik}$,1_${ik}$), vt(1_${ik}$,1_${ik}$)
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, nru
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SPTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz>0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           if( icompz==2_${ik}$ )call stdlib${ii}$_slaset( 'FULL', n, n, zero, one, z, ldz )
           ! call stdlib${ii}$_spttrf to factor the matrix.
           call stdlib${ii}$_spttrf( n, d, e, info )
           if( info/=0 )return
           do i = 1, n
              d( i ) = sqrt( d( i ) )
           end do
           do i = 1, n - 1
              e( i ) = e( i )*d( i )
           end do
           ! call stdlib${ii}$_sbdsqr to compute the singular values/vectors of the
           ! bidiagonal factor.
           if( icompz>0_${ik}$ ) then
              nru = n
           else
              nru = 0_${ik}$
           end if
           call stdlib${ii}$_sbdsqr( 'LOWER', n, 0_${ik}$, nru, 0_${ik}$, d, e, vt, 1_${ik}$, z, ldz, c, 1_${ik}$,work, info )
                     
           ! square the singular values.
           if( info==0_${ik}$ ) then
              do i = 1, n
                 d( i ) = d( i )*d( i )
              end do
           else
              info = n + info
           end if
           return
     end subroutine stdlib${ii}$_spteqr

     pure module subroutine stdlib${ii}$_dpteqr( compz, n, d, e, z, ldz, work, info )
     !! DPTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric positive definite tridiagonal matrix by first factoring the
     !! matrix using DPTTRF, and then calling DBDSQR to compute the singular
     !! values of the bidiagonal factor.
     !! This routine computes the eigenvalues of the positive definite
     !! tridiagonal matrix to high relative accuracy.  This means that if the
     !! eigenvalues range over many orders of magnitude in size, then the
     !! small eigenvalues and corresponding eigenvectors will be computed
     !! more accurately than, for example, with the standard QR method.
     !! The eigenvectors of a full or band symmetric positive definite matrix
     !! can also be found if DSYTRD, DSPTRD, or DSBTRD has been used to
     !! reduce this matrix to tridiagonal form. (The reduction to tridiagonal
     !! form, however, may preclude the possibility of obtaining high
     !! relative accuracy in the small eigenvalues of the original matrix, if
     !! these eigenvalues range over many orders of magnitude.)
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(dp), intent(inout) :: d(*), e(*), z(ldz,*)
           real(dp), intent(out) :: work(*)
        ! =====================================================================
           
           ! Local Arrays 
           real(dp) :: c(1_${ik}$,1_${ik}$), vt(1_${ik}$,1_${ik}$)
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, nru
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DPTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz>0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           if( icompz==2_${ik}$ )call stdlib${ii}$_dlaset( 'FULL', n, n, zero, one, z, ldz )
           ! call stdlib${ii}$_dpttrf to factor the matrix.
           call stdlib${ii}$_dpttrf( n, d, e, info )
           if( info/=0 )return
           do i = 1, n
              d( i ) = sqrt( d( i ) )
           end do
           do i = 1, n - 1
              e( i ) = e( i )*d( i )
           end do
           ! call stdlib${ii}$_dbdsqr to compute the singular values/vectors of the
           ! bidiagonal factor.
           if( icompz>0_${ik}$ ) then
              nru = n
           else
              nru = 0_${ik}$
           end if
           call stdlib${ii}$_dbdsqr( 'LOWER', n, 0_${ik}$, nru, 0_${ik}$, d, e, vt, 1_${ik}$, z, ldz, c, 1_${ik}$,work, info )
                     
           ! square the singular values.
           if( info==0_${ik}$ ) then
              do i = 1, n
                 d( i ) = d( i )*d( i )
              end do
           else
              info = n + info
           end if
           return
     end subroutine stdlib${ii}$_dpteqr

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$pteqr( compz, n, d, e, z, ldz, work, info )
     !! DPTEQR: computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric positive definite tridiagonal matrix by first factoring the
     !! matrix using DPTTRF, and then calling DBDSQR to compute the singular
     !! values of the bidiagonal factor.
     !! This routine computes the eigenvalues of the positive definite
     !! tridiagonal matrix to high relative accuracy.  This means that if the
     !! eigenvalues range over many orders of magnitude in size, then the
     !! small eigenvalues and corresponding eigenvectors will be computed
     !! more accurately than, for example, with the standard QR method.
     !! The eigenvectors of a full or band symmetric positive definite matrix
     !! can also be found if DSYTRD, DSPTRD, or DSBTRD has been used to
     !! reduce this matrix to tridiagonal form. (The reduction to tridiagonal
     !! form, however, may preclude the possibility of obtaining high
     !! relative accuracy in the small eigenvalues of the original matrix, if
     !! these eigenvalues range over many orders of magnitude.)
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(${rk}$), intent(inout) :: d(*), e(*), z(ldz,*)
           real(${rk}$), intent(out) :: work(*)
        ! =====================================================================
           
           ! Local Arrays 
           real(${rk}$) :: c(1_${ik}$,1_${ik}$), vt(1_${ik}$,1_${ik}$)
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, nru
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DPTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz>0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           if( icompz==2_${ik}$ )call stdlib${ii}$_${ri}$laset( 'FULL', n, n, zero, one, z, ldz )
           ! call stdlib${ii}$_${ri}$pttrf to factor the matrix.
           call stdlib${ii}$_${ri}$pttrf( n, d, e, info )
           if( info/=0 )return
           do i = 1, n
              d( i ) = sqrt( d( i ) )
           end do
           do i = 1, n - 1
              e( i ) = e( i )*d( i )
           end do
           ! call stdlib${ii}$_${ri}$bdsqr to compute the singular values/vectors of the
           ! bidiagonal factor.
           if( icompz>0_${ik}$ ) then
              nru = n
           else
              nru = 0_${ik}$
           end if
           call stdlib${ii}$_${ri}$bdsqr( 'LOWER', n, 0_${ik}$, nru, 0_${ik}$, d, e, vt, 1_${ik}$, z, ldz, c, 1_${ik}$,work, info )
                     
           ! square the singular values.
           if( info==0_${ik}$ ) then
              do i = 1, n
                 d( i ) = d( i )*d( i )
              end do
           else
              info = n + info
           end if
           return
     end subroutine stdlib${ii}$_${ri}$pteqr

#:endif
#:endfor

     pure module subroutine stdlib${ii}$_cpteqr( compz, n, d, e, z, ldz, work, info )
     !! CPTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric positive definite tridiagonal matrix by first factoring the
     !! matrix using SPTTRF and then calling CBDSQR to compute the singular
     !! values of the bidiagonal factor.
     !! This routine computes the eigenvalues of the positive definite
     !! tridiagonal matrix to high relative accuracy.  This means that if the
     !! eigenvalues range over many orders of magnitude in size, then the
     !! small eigenvalues and corresponding eigenvectors will be computed
     !! more accurately than, for example, with the standard QR method.
     !! The eigenvectors of a full or band positive definite Hermitian matrix
     !! can also be found if CHETRD, CHPTRD, or CHBTRD has been used to
     !! reduce this matrix to tridiagonal form.  (The reduction to
     !! tridiagonal form, however, may preclude the possibility of obtaining
     !! high relative accuracy in the small eigenvalues of the original
     !! matrix, if these eigenvalues range over many orders of magnitude.)
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: work(*)
           complex(sp), intent(inout) :: z(ldz,*)
        ! ====================================================================
           
           ! Local Arrays 
           complex(sp) :: c(1_${ik}$,1_${ik}$), vt(1_${ik}$,1_${ik}$)
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, nru
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'CPTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz>0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           if( icompz==2_${ik}$ )call stdlib${ii}$_claset( 'FULL', n, n, czero, cone, z, ldz )
           ! call stdlib${ii}$_spttrf to factor the matrix.
           call stdlib${ii}$_spttrf( n, d, e, info )
           if( info/=0 )return
           do i = 1, n
              d( i ) = sqrt( d( i ) )
           end do
           do i = 1, n - 1
              e( i ) = e( i )*d( i )
           end do
           ! call stdlib${ii}$_cbdsqr to compute the singular values/vectors of the
           ! bidiagonal factor.
           if( icompz>0_${ik}$ ) then
              nru = n
           else
              nru = 0_${ik}$
           end if
           call stdlib${ii}$_cbdsqr( 'LOWER', n, 0_${ik}$, nru, 0_${ik}$, d, e, vt, 1_${ik}$, z, ldz, c, 1_${ik}$,work, info )
                     
           ! square the singular values.
           if( info==0_${ik}$ ) then
              do i = 1, n
                 d( i ) = d( i )*d( i )
              end do
           else
              info = n + info
           end if
           return
     end subroutine stdlib${ii}$_cpteqr

     pure module subroutine stdlib${ii}$_zpteqr( compz, n, d, e, z, ldz, work, info )
     !! ZPTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric positive definite tridiagonal matrix by first factoring the
     !! matrix using DPTTRF and then calling ZBDSQR to compute the singular
     !! values of the bidiagonal factor.
     !! This routine computes the eigenvalues of the positive definite
     !! tridiagonal matrix to high relative accuracy.  This means that if the
     !! eigenvalues range over many orders of magnitude in size, then the
     !! small eigenvalues and corresponding eigenvectors will be computed
     !! more accurately than, for example, with the standard QR method.
     !! The eigenvectors of a full or band positive definite Hermitian matrix
     !! can also be found if ZHETRD, ZHPTRD, or ZHBTRD has been used to
     !! reduce this matrix to tridiagonal form.  (The reduction to
     !! tridiagonal form, however, may preclude the possibility of obtaining
     !! high relative accuracy in the small eigenvalues of the original
     !! matrix, if these eigenvalues range over many orders of magnitude.)
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: work(*)
           complex(dp), intent(inout) :: z(ldz,*)
        ! ====================================================================
           
           ! Local Arrays 
           complex(dp) :: c(1_${ik}$,1_${ik}$), vt(1_${ik}$,1_${ik}$)
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, nru
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZPTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz>0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           if( icompz==2_${ik}$ )call stdlib${ii}$_zlaset( 'FULL', n, n, czero, cone, z, ldz )
           ! call stdlib${ii}$_dpttrf to factor the matrix.
           call stdlib${ii}$_dpttrf( n, d, e, info )
           if( info/=0 )return
           do i = 1, n
              d( i ) = sqrt( d( i ) )
           end do
           do i = 1, n - 1
              e( i ) = e( i )*d( i )
           end do
           ! call stdlib${ii}$_zbdsqr to compute the singular values/vectors of the
           ! bidiagonal factor.
           if( icompz>0_${ik}$ ) then
              nru = n
           else
              nru = 0_${ik}$
           end if
           call stdlib${ii}$_zbdsqr( 'LOWER', n, 0_${ik}$, nru, 0_${ik}$, d, e, vt, 1_${ik}$, z, ldz, c, 1_${ik}$,work, info )
                     
           ! square the singular values.
           if( info==0_${ik}$ ) then
              do i = 1, n
                 d( i ) = d( i )*d( i )
              end do
           else
              info = n + info
           end if
           return
     end subroutine stdlib${ii}$_zpteqr

#:for ck,ct,ci in CMPLX_KINDS_TYPES
#:if not ck in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ci}$pteqr( compz, n, d, e, z, ldz, work, info )
     !! ZPTEQR: computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric positive definite tridiagonal matrix by first factoring the
     !! matrix using DPTTRF and then calling ZBDSQR to compute the singular
     !! values of the bidiagonal factor.
     !! This routine computes the eigenvalues of the positive definite
     !! tridiagonal matrix to high relative accuracy.  This means that if the
     !! eigenvalues range over many orders of magnitude in size, then the
     !! small eigenvalues and corresponding eigenvectors will be computed
     !! more accurately than, for example, with the standard QR method.
     !! The eigenvectors of a full or band positive definite Hermitian matrix
     !! can also be found if ZHETRD, ZHPTRD, or ZHBTRD has been used to
     !! reduce this matrix to tridiagonal form.  (The reduction to
     !! tridiagonal form, however, may preclude the possibility of obtaining
     !! high relative accuracy in the small eigenvalues of the original
     !! matrix, if these eigenvalues range over many orders of magnitude.)
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(${ck}$), intent(inout) :: d(*), e(*)
           real(${ck}$), intent(out) :: work(*)
           complex(${ck}$), intent(inout) :: z(ldz,*)
        ! ====================================================================
           
           ! Local Arrays 
           complex(${ck}$) :: c(1_${ik}$,1_${ik}$), vt(1_${ik}$,1_${ik}$)
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, nru
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZPTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz>0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           if( icompz==2_${ik}$ )call stdlib${ii}$_${ci}$laset( 'FULL', n, n, czero, cone, z, ldz )
           ! call stdlib${ii}$_${c2ri(ci)}$pttrf to factor the matrix.
           call stdlib${ii}$_${c2ri(ci)}$pttrf( n, d, e, info )
           if( info/=0 )return
           do i = 1, n
              d( i ) = sqrt( d( i ) )
           end do
           do i = 1, n - 1
              e( i ) = e( i )*d( i )
           end do
           ! call stdlib${ii}$_${ci}$bdsqr to compute the singular values/vectors of the
           ! bidiagonal factor.
           if( icompz>0_${ik}$ ) then
              nru = n
           else
              nru = 0_${ik}$
           end if
           call stdlib${ii}$_${ci}$bdsqr( 'LOWER', n, 0_${ik}$, nru, 0_${ik}$, d, e, vt, 1_${ik}$, z, ldz, c, 1_${ik}$,work, info )
                     
           ! square the singular values.
           if( info==0_${ik}$ ) then
              do i = 1, n
                 d( i ) = d( i )*d( i )
              end do
           else
              info = n + info
           end if
           return
     end subroutine stdlib${ii}$_${ci}$pteqr

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstebz( range, order, n, vl, vu, il, iu, abstol, d, e,m, nsplit, w, &
     !! SSTEBZ computes the eigenvalues of a symmetric tridiagonal
     !! matrix T.  The user may ask for all eigenvalues, all eigenvalues
     !! in the half-open interval (VL, VU], or the IL-th through IU-th
     !! eigenvalues.
     !! To avoid overflow, the matrix must be scaled so that its
     !! largest element is no greater than overflow**(1/2) * underflow**(1/4) in absolute value, and for greatest
     !! accuracy, it should not be much smaller than that.
     !! See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal
     !! Matrix", Report CS41, Computer Science Dept., Stanford
     !! University, July 21, 1966.
               iblock, isplit, 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 
           character, intent(in) :: order, range
           integer(${ik}$), intent(in) :: il, iu, n
           integer(${ik}$), intent(out) :: info, m, nsplit
           real(sp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iblock(*), isplit(*), iwork(*)
           real(sp), intent(in) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*)
        ! =====================================================================
           ! Parameters 
           real(sp), parameter :: fudge = 2.1_sp
           real(sp), parameter :: relfac = two
           
           
           ! Local Scalars 
           logical(lk) :: ncnvrg, toofew
           integer(${ik}$) :: ib, ibegin, idiscl, idiscu, ie, iend, iinfo, im, in, ioff, iorder, &
                     iout, irange, itmax, itmp1, iw, iwoff, j, jb, jdisc, je, nb, nwl, nwu
           real(sp) :: atoli, bnorm, gl, gu, pivmin, rtoli, safemn, tmp1, tmp2, tnorm, ulp, wkill,&
                      wl, wlu, wu, wul
           ! Local Arrays 
           integer(${ik}$) :: idumma(1_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           info = 0_${ik}$
           ! decode range
           if( stdlib_lsame( range, 'A' ) ) then
              irange = 1_${ik}$
           else if( stdlib_lsame( range, 'V' ) ) then
              irange = 2_${ik}$
           else if( stdlib_lsame( range, 'I' ) ) then
              irange = 3_${ik}$
           else
              irange = 0_${ik}$
           end if
           ! decode order
           if( stdlib_lsame( order, 'B' ) ) then
              iorder = 2_${ik}$
           else if( stdlib_lsame( order, 'E' ) ) then
              iorder = 1_${ik}$
           else
              iorder = 0_${ik}$
           end if
           ! check for errors
           if( irange<=0_${ik}$ ) then
              info = -1_${ik}$
           else if( iorder<=0_${ik}$ ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( irange==2_${ik}$ ) then
              if( vl>=vu ) info = -5_${ik}$
           else if( irange==3_${ik}$ .and. ( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) )then
              info = -6_${ik}$
           else if( irange==3_${ik}$ .and. ( iu<min( n, il ) .or. iu>n ) )then
              info = -7_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEBZ', -info )
              return
           end if
           ! initialize error flags
           info = 0_${ik}$
           ncnvrg = .false.
           toofew = .false.
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           ! simplifications:
           if( irange==3_${ik}$ .and. il==1_${ik}$ .and. iu==n )irange = 1_${ik}$
           ! get machine constants
           ! nb is the minimum vector length for vector bisection, or 0
           ! if only scalar is to be done.
           safemn = stdlib${ii}$_slamch( 'S' )
           ulp = stdlib${ii}$_slamch( 'P' )
           rtoli = ulp*relfac
           nb = stdlib${ii}$_ilaenv( 1_${ik}$, 'SSTEBZ', ' ', n, -1_${ik}$, -1_${ik}$, -1_${ik}$ )
           if( nb<=1_${ik}$ )nb = 0_${ik}$
           ! special case when n=1
           if( n==1_${ik}$ ) then
              nsplit = 1_${ik}$
              isplit( 1_${ik}$ ) = 1_${ik}$
              if( irange==2_${ik}$ .and. ( vl>=d( 1_${ik}$ ) .or. vu<d( 1_${ik}$ ) ) ) then
                 m = 0_${ik}$
              else
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
                 iblock( 1_${ik}$ ) = 1_${ik}$
                 m = 1_${ik}$
              end if
              return
           end if
           ! compute splitting points
           nsplit = 1_${ik}$
           work( n ) = zero
           pivmin = one
           do j = 2, n
              tmp1 = e( j-1 )**2_${ik}$
              if( abs( d( j )*d( j-1 ) )*ulp**2_${ik}$+safemn>tmp1 ) then
                 isplit( nsplit ) = j - 1_${ik}$
                 nsplit = nsplit + 1_${ik}$
                 work( j-1 ) = zero
              else
                 work( j-1 ) = tmp1
                 pivmin = max( pivmin, tmp1 )
              end if
           end do
           isplit( nsplit ) = n
           pivmin = pivmin*safemn
           ! compute interval and atoli
           if( irange==3_${ik}$ ) then
              ! range='i': compute the interval containing eigenvalues
                         ! il through iu.
              ! compute gershgorin interval for entire (split) matrix
              ! and use it as the initial interval
              gu = d( 1_${ik}$ )
              gl = d( 1_${ik}$ )
              tmp1 = zero
              do j = 1, n - 1
                 tmp2 = sqrt( work( j ) )
                 gu = max( gu, d( j )+tmp1+tmp2 )
                 gl = min( gl, d( j )-tmp1-tmp2 )
                 tmp1 = tmp2
              end do
              gu = max( gu, d( n )+tmp1 )
              gl = min( gl, d( n )-tmp1 )
              tnorm = max( abs( gl ), abs( gu ) )
              gl = gl - fudge*tnorm*ulp*n - fudge*two*pivmin
              gu = gu + fudge*tnorm*ulp*n + fudge*pivmin
              ! compute iteration parameters
              itmax = int( ( log( tnorm+pivmin )-log( pivmin ) ) /log( two ),KIND=${ik}$) + 2_${ik}$
              if( abstol<=zero ) then
                 atoli = ulp*tnorm
              else
                 atoli = abstol
              end if
              work( n+1 ) = gl
              work( n+2 ) = gl
              work( n+3 ) = gu
              work( n+4 ) = gu
              work( n+5 ) = gl
              work( n+6 ) = gu
              iwork( 1_${ik}$ ) = -1_${ik}$
              iwork( 2_${ik}$ ) = -1_${ik}$
              iwork( 3_${ik}$ ) = n + 1_${ik}$
              iwork( 4_${ik}$ ) = n + 1_${ik}$
              iwork( 5_${ik}$ ) = il - 1_${ik}$
              iwork( 6_${ik}$ ) = iu
              call stdlib${ii}$_slaebz( 3_${ik}$, itmax, n, 2_${ik}$, 2_${ik}$, nb, atoli, rtoli, pivmin, d, e,work, iwork( &
                        5_${ik}$ ), work( n+1 ), work( n+5 ), iout,iwork, w, iblock, iinfo )
              if( iwork( 6_${ik}$ )==iu ) then
                 wl = work( n+1 )
                 wlu = work( n+3 )
                 nwl = iwork( 1_${ik}$ )
                 wu = work( n+4 )
                 wul = work( n+2 )
                 nwu = iwork( 4_${ik}$ )
              else
                 wl = work( n+2 )
                 wlu = work( n+4 )
                 nwl = iwork( 2_${ik}$ )
                 wu = work( n+3 )
                 wul = work( n+1 )
                 nwu = iwork( 3_${ik}$ )
              end if
              if( nwl<0_${ik}$ .or. nwl>=n .or. nwu<1_${ik}$ .or. nwu>n ) then
                 info = 4_${ik}$
                 return
              end if
           else
              ! range='a' or 'v' -- set atoli
              tnorm = max( abs( d( 1_${ik}$ ) )+abs( e( 1_${ik}$ ) ),abs( d( n ) )+abs( e( n-1 ) ) )
              do j = 2, n - 1
                 tnorm = max( tnorm, abs( d( j ) )+abs( e( j-1 ) )+abs( e( j ) ) )
              end do
              if( abstol<=zero ) then
                 atoli = ulp*tnorm
              else
                 atoli = abstol
              end if
              if( irange==2_${ik}$ ) then
                 wl = vl
                 wu = vu
              else
                 wl = zero
                 wu = zero
              end if
           end if
           ! find eigenvalues -- loop over blocks and recompute nwl and nwu.
           ! nwl accumulates the number of eigenvalues .le. wl,
           ! nwu accumulates the number of eigenvalues .le. wu
           m = 0_${ik}$
           iend = 0_${ik}$
           info = 0_${ik}$
           nwl = 0_${ik}$
           nwu = 0_${ik}$
           loop_70: do jb = 1, nsplit
              ioff = iend
              ibegin = ioff + 1_${ik}$
              iend = isplit( jb )
              in = iend - ioff
              if( in==1_${ik}$ ) then
                 ! special case -- in=1
                 if( irange==1_${ik}$ .or. wl>=d( ibegin )-pivmin )nwl = nwl + 1_${ik}$
                 if( irange==1_${ik}$ .or. wu>=d( ibegin )-pivmin )nwu = nwu + 1_${ik}$
                 if( irange==1_${ik}$ .or. ( wl<d( ibegin )-pivmin .and. wu>=d( ibegin )-pivmin ) ) &
                           then
                    m = m + 1_${ik}$
                    w( m ) = d( ibegin )
                    iblock( m ) = jb
                 end if
              else
                 ! general case -- in > 1
                 ! compute gershgorin interval
                 ! and use it as the initial interval
                 gu = d( ibegin )
                 gl = d( ibegin )
                 tmp1 = zero
                 do j = ibegin, iend - 1
                    tmp2 = abs( e( j ) )
                    gu = max( gu, d( j )+tmp1+tmp2 )
                    gl = min( gl, d( j )-tmp1-tmp2 )
                    tmp1 = tmp2
                 end do
                 gu = max( gu, d( iend )+tmp1 )
                 gl = min( gl, d( iend )-tmp1 )
                 bnorm = max( abs( gl ), abs( gu ) )
                 gl = gl - fudge*bnorm*ulp*in - fudge*pivmin
                 gu = gu + fudge*bnorm*ulp*in + fudge*pivmin
                 ! compute atoli for the current submatrix
                 if( abstol<=zero ) then
                    atoli = ulp*max( abs( gl ), abs( gu ) )
                 else
                    atoli = abstol
                 end if
                 if( irange>1_${ik}$ ) then
                    if( gu<wl ) then
                       nwl = nwl + in
                       nwu = nwu + in
                       cycle loop_70
                    end if
                    gl = max( gl, wl )
                    gu = min( gu, wu )
                    if( gl>=gu )cycle loop_70
                 end if
                 ! set up initial interval
                 work( n+1 ) = gl
                 work( n+in+1 ) = gu
                 call stdlib${ii}$_slaebz( 1_${ik}$, 0_${ik}$, in, in, 1_${ik}$, nb, atoli, rtoli, pivmin,d( ibegin ), e( &
                 ibegin ), work( ibegin ),idumma, work( n+1 ), work( n+2*in+1 ), im,iwork, w( m+1 &
                           ), iblock( m+1 ), iinfo )
                 nwl = nwl + iwork( 1_${ik}$ )
                 nwu = nwu + iwork( in+1 )
                 iwoff = m - iwork( 1_${ik}$ )
                 ! compute eigenvalues
                 itmax = int( ( log( gu-gl+pivmin )-log( pivmin ) ) /log( two ),KIND=${ik}$) + &
                           2_${ik}$
                 call stdlib${ii}$_slaebz( 2_${ik}$, itmax, in, in, 1_${ik}$, nb, atoli, rtoli, pivmin,d( ibegin ), e(&
                  ibegin ), work( ibegin ),idumma, work( n+1 ), work( n+2*in+1 ), iout,iwork, w( &
                            m+1 ), iblock( m+1 ), iinfo )
                 ! copy eigenvalues into w and iblock
                 ! use -jb for block number for unconverged eigenvalues.
                 do j = 1, iout
                    tmp1 = half*( work( j+n )+work( j+in+n ) )
                    ! flag non-convergence.
                    if( j>iout-iinfo ) then
                       ncnvrg = .true.
                       ib = -jb
                    else
                       ib = jb
                    end if
                    do je = iwork( j ) + 1 + iwoff,iwork( j+in ) + iwoff
                       w( je ) = tmp1
                       iblock( je ) = ib
                    end do
                 end do
                 m = m + im
              end if
           end do loop_70
           ! if range='i', then (wl,wu) contains eigenvalues nwl+1,...,nwu
           ! if nwl+1 < il or nwu > iu, discard extra eigenvalues.
           if( irange==3_${ik}$ ) then
              im = 0_${ik}$
              idiscl = il - 1_${ik}$ - nwl
              idiscu = nwu - iu
              if( idiscl>0_${ik}$ .or. idiscu>0_${ik}$ ) then
                 do je = 1, m
                    if( w( je )<=wlu .and. idiscl>0_${ik}$ ) then
                       idiscl = idiscl - 1_${ik}$
                    else if( w( je )>=wul .and. idiscu>0_${ik}$ ) then
                       idiscu = idiscu - 1_${ik}$
                    else
                       im = im + 1_${ik}$
                       w( im ) = w( je )
                       iblock( im ) = iblock( je )
                    end if
                 end do
                 m = im
              end if
              if( idiscl>0_${ik}$ .or. idiscu>0_${ik}$ ) then
                 ! code to deal with effects of bad arithmetic:
                 ! some low eigenvalues to be discarded are not in (wl,wlu],
                 ! or high eigenvalues to be discarded are not in (wul,wu]
                 ! so just kill off the smallest idiscl/largest idiscu
                 ! eigenvalues, by simply finding the smallest/largest
                 ! eigenvalue(s).
                 ! (if n(w) is monotone non-decreasing, this should never
                     ! happen.)
                 if( idiscl>0_${ik}$ ) then
                    wkill = wu
                    do jdisc = 1, idiscl
                       iw = 0_${ik}$
                       do je = 1, m
                          if( iblock( je )/=0_${ik}$ .and.( w( je )<wkill .or. iw==0_${ik}$ ) ) then
                             iw = je
                             wkill = w( je )
                          end if
                       end do
                       iblock( iw ) = 0_${ik}$
                    end do
                 end if
                 if( idiscu>0_${ik}$ ) then
                    wkill = wl
                    do jdisc = 1, idiscu
                       iw = 0_${ik}$
                       do je = 1, m
                          if( iblock( je )/=0_${ik}$ .and.( w( je )>wkill .or. iw==0_${ik}$ ) ) then
                             iw = je
                             wkill = w( je )
                          end if
                       end do
                       iblock( iw ) = 0_${ik}$
                    end do
                 end if
                 im = 0_${ik}$
                 do je = 1, m
                    if( iblock( je )/=0_${ik}$ ) then
                       im = im + 1_${ik}$
                       w( im ) = w( je )
                       iblock( im ) = iblock( je )
                    end if
                 end do
                 m = im
              end if
              if( idiscl<0_${ik}$ .or. idiscu<0_${ik}$ ) then
                 toofew = .true.
              end if
           end if
           ! if order='b', do nothing -- the eigenvalues are already sorted
              ! by block.
           ! if order='e', sort the eigenvalues from smallest to largest
           if( iorder==1_${ik}$ .and. nsplit>1_${ik}$ ) then
              do je = 1, m - 1
                 ie = 0_${ik}$
                 tmp1 = w( je )
                 do j = je + 1, m
                    if( w( j )<tmp1 ) then
                       ie = j
                       tmp1 = w( j )
                    end if
                 end do
                 if( ie/=0_${ik}$ ) then
                    itmp1 = iblock( ie )
                    w( ie ) = w( je )
                    iblock( ie ) = iblock( je )
                    w( je ) = tmp1
                    iblock( je ) = itmp1
                 end if
              end do
           end if
           info = 0_${ik}$
           if( ncnvrg )info = info + 1_${ik}$
           if( toofew )info = info + 2_${ik}$
           return
     end subroutine stdlib${ii}$_sstebz

     pure module subroutine stdlib${ii}$_dstebz( range, order, n, vl, vu, il, iu, abstol, d, e,m, nsplit, w, &
     !! DSTEBZ computes the eigenvalues of a symmetric tridiagonal
     !! matrix T.  The user may ask for all eigenvalues, all eigenvalues
     !! in the half-open interval (VL, VU], or the IL-th through IU-th
     !! eigenvalues.
     !! To avoid overflow, the matrix must be scaled so that its
     !! largest element is no greater than overflow**(1/2) * underflow**(1/4) in absolute value, and for greatest
     !! accuracy, it should not be much smaller than that.
     !! See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal
     !! Matrix", Report CS41, Computer Science Dept., Stanford
     !! University, July 21, 1966.
               iblock, isplit, 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 
           character, intent(in) :: order, range
           integer(${ik}$), intent(in) :: il, iu, n
           integer(${ik}$), intent(out) :: info, m, nsplit
           real(dp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iblock(*), isplit(*), iwork(*)
           real(dp), intent(in) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*)
        ! =====================================================================
           ! Parameters 
           real(dp), parameter :: fudge = 2.1_dp
           real(dp), parameter :: relfac = two
           
           
           ! Local Scalars 
           logical(lk) :: ncnvrg, toofew
           integer(${ik}$) :: ib, ibegin, idiscl, idiscu, ie, iend, iinfo, im, in, ioff, iorder, &
                     iout, irange, itmax, itmp1, iw, iwoff, j, jb, jdisc, je, nb, nwl, nwu
           real(dp) :: atoli, bnorm, gl, gu, pivmin, rtoli, safemn, tmp1, tmp2, tnorm, ulp, wkill,&
                      wl, wlu, wu, wul
           ! Local Arrays 
           integer(${ik}$) :: idumma(1_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           info = 0_${ik}$
           ! decode range
           if( stdlib_lsame( range, 'A' ) ) then
              irange = 1_${ik}$
           else if( stdlib_lsame( range, 'V' ) ) then
              irange = 2_${ik}$
           else if( stdlib_lsame( range, 'I' ) ) then
              irange = 3_${ik}$
           else
              irange = 0_${ik}$
           end if
           ! decode order
           if( stdlib_lsame( order, 'B' ) ) then
              iorder = 2_${ik}$
           else if( stdlib_lsame( order, 'E' ) ) then
              iorder = 1_${ik}$
           else
              iorder = 0_${ik}$
           end if
           ! check for errors
           if( irange<=0_${ik}$ ) then
              info = -1_${ik}$
           else if( iorder<=0_${ik}$ ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( irange==2_${ik}$ ) then
              if( vl>=vu )info = -5_${ik}$
           else if( irange==3_${ik}$ .and. ( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) )then
              info = -6_${ik}$
           else if( irange==3_${ik}$ .and. ( iu<min( n, il ) .or. iu>n ) )then
              info = -7_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEBZ', -info )
              return
           end if
           ! initialize error flags
           info = 0_${ik}$
           ncnvrg = .false.
           toofew = .false.
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           ! simplifications:
           if( irange==3_${ik}$ .and. il==1_${ik}$ .and. iu==n )irange = 1_${ik}$
           ! get machine constants
           ! nb is the minimum vector length for vector bisection, or 0
           ! if only scalar is to be done.
           safemn = stdlib${ii}$_dlamch( 'S' )
           ulp = stdlib${ii}$_dlamch( 'P' )
           rtoli = ulp*relfac
           nb = stdlib${ii}$_ilaenv( 1_${ik}$, 'DSTEBZ', ' ', n, -1_${ik}$, -1_${ik}$, -1_${ik}$ )
           if( nb<=1_${ik}$ )nb = 0_${ik}$
           ! special case when n=1
           if( n==1_${ik}$ ) then
              nsplit = 1_${ik}$
              isplit( 1_${ik}$ ) = 1_${ik}$
              if( irange==2_${ik}$ .and. ( vl>=d( 1_${ik}$ ) .or. vu<d( 1_${ik}$ ) ) ) then
                 m = 0_${ik}$
              else
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
                 iblock( 1_${ik}$ ) = 1_${ik}$
                 m = 1_${ik}$
              end if
              return
           end if
           ! compute splitting points
           nsplit = 1_${ik}$
           work( n ) = zero
           pivmin = one
           do j = 2, n
              tmp1 = e( j-1 )**2_${ik}$
              if( abs( d( j )*d( j-1 ) )*ulp**2_${ik}$+safemn>tmp1 ) then
                 isplit( nsplit ) = j - 1_${ik}$
                 nsplit = nsplit + 1_${ik}$
                 work( j-1 ) = zero
              else
                 work( j-1 ) = tmp1
                 pivmin = max( pivmin, tmp1 )
              end if
           end do
           isplit( nsplit ) = n
           pivmin = pivmin*safemn
           ! compute interval and atoli
           if( irange==3_${ik}$ ) then
              ! range='i': compute the interval containing eigenvalues
                         ! il through iu.
              ! compute gershgorin interval for entire (split) matrix
              ! and use it as the initial interval
              gu = d( 1_${ik}$ )
              gl = d( 1_${ik}$ )
              tmp1 = zero
              do j = 1, n - 1
                 tmp2 = sqrt( work( j ) )
                 gu = max( gu, d( j )+tmp1+tmp2 )
                 gl = min( gl, d( j )-tmp1-tmp2 )
                 tmp1 = tmp2
              end do
              gu = max( gu, d( n )+tmp1 )
              gl = min( gl, d( n )-tmp1 )
              tnorm = max( abs( gl ), abs( gu ) )
              gl = gl - fudge*tnorm*ulp*n - fudge*two*pivmin
              gu = gu + fudge*tnorm*ulp*n + fudge*pivmin
              ! compute iteration parameters
              itmax = int( ( log( tnorm+pivmin )-log( pivmin ) ) /log( two ),KIND=${ik}$) + 2_${ik}$
              if( abstol<=zero ) then
                 atoli = ulp*tnorm
              else
                 atoli = abstol
              end if
              work( n+1 ) = gl
              work( n+2 ) = gl
              work( n+3 ) = gu
              work( n+4 ) = gu
              work( n+5 ) = gl
              work( n+6 ) = gu
              iwork( 1_${ik}$ ) = -1_${ik}$
              iwork( 2_${ik}$ ) = -1_${ik}$
              iwork( 3_${ik}$ ) = n + 1_${ik}$
              iwork( 4_${ik}$ ) = n + 1_${ik}$
              iwork( 5_${ik}$ ) = il - 1_${ik}$
              iwork( 6_${ik}$ ) = iu
              call stdlib${ii}$_dlaebz( 3_${ik}$, itmax, n, 2_${ik}$, 2_${ik}$, nb, atoli, rtoli, pivmin, d, e,work, iwork( &
                        5_${ik}$ ), work( n+1 ), work( n+5 ), iout,iwork, w, iblock, iinfo )
              if( iwork( 6_${ik}$ )==iu ) then
                 wl = work( n+1 )
                 wlu = work( n+3 )
                 nwl = iwork( 1_${ik}$ )
                 wu = work( n+4 )
                 wul = work( n+2 )
                 nwu = iwork( 4_${ik}$ )
              else
                 wl = work( n+2 )
                 wlu = work( n+4 )
                 nwl = iwork( 2_${ik}$ )
                 wu = work( n+3 )
                 wul = work( n+1 )
                 nwu = iwork( 3_${ik}$ )
              end if
              if( nwl<0_${ik}$ .or. nwl>=n .or. nwu<1_${ik}$ .or. nwu>n ) then
                 info = 4_${ik}$
                 return
              end if
           else
              ! range='a' or 'v' -- set atoli
              tnorm = max( abs( d( 1_${ik}$ ) )+abs( e( 1_${ik}$ ) ),abs( d( n ) )+abs( e( n-1 ) ) )
              do j = 2, n - 1
                 tnorm = max( tnorm, abs( d( j ) )+abs( e( j-1 ) )+abs( e( j ) ) )
              end do
              if( abstol<=zero ) then
                 atoli = ulp*tnorm
              else
                 atoli = abstol
              end if
              if( irange==2_${ik}$ ) then
                 wl = vl
                 wu = vu
              else
                 wl = zero
                 wu = zero
              end if
           end if
           ! find eigenvalues -- loop over blocks and recompute nwl and nwu.
           ! nwl accumulates the number of eigenvalues .le. wl,
           ! nwu accumulates the number of eigenvalues .le. wu
           m = 0_${ik}$
           iend = 0_${ik}$
           info = 0_${ik}$
           nwl = 0_${ik}$
           nwu = 0_${ik}$
           loop_70: do jb = 1, nsplit
              ioff = iend
              ibegin = ioff + 1_${ik}$
              iend = isplit( jb )
              in = iend - ioff
              if( in==1_${ik}$ ) then
                 ! special case -- in=1
                 if( irange==1_${ik}$ .or. wl>=d( ibegin )-pivmin )nwl = nwl + 1_${ik}$
                 if( irange==1_${ik}$ .or. wu>=d( ibegin )-pivmin )nwu = nwu + 1_${ik}$
                 if( irange==1_${ik}$ .or. ( wl<d( ibegin )-pivmin .and. wu>=d( ibegin )-pivmin ) ) &
                           then
                    m = m + 1_${ik}$
                    w( m ) = d( ibegin )
                    iblock( m ) = jb
                 end if
              else
                 ! general case -- in > 1
                 ! compute gershgorin interval
                 ! and use it as the initial interval
                 gu = d( ibegin )
                 gl = d( ibegin )
                 tmp1 = zero
                 do j = ibegin, iend - 1
                    tmp2 = abs( e( j ) )
                    gu = max( gu, d( j )+tmp1+tmp2 )
                    gl = min( gl, d( j )-tmp1-tmp2 )
                    tmp1 = tmp2
                 end do
                 gu = max( gu, d( iend )+tmp1 )
                 gl = min( gl, d( iend )-tmp1 )
                 bnorm = max( abs( gl ), abs( gu ) )
                 gl = gl - fudge*bnorm*ulp*in - fudge*pivmin
                 gu = gu + fudge*bnorm*ulp*in + fudge*pivmin
                 ! compute atoli for the current submatrix
                 if( abstol<=zero ) then
                    atoli = ulp*max( abs( gl ), abs( gu ) )
                 else
                    atoli = abstol
                 end if
                 if( irange>1_${ik}$ ) then
                    if( gu<wl ) then
                       nwl = nwl + in
                       nwu = nwu + in
                       cycle loop_70
                    end if
                    gl = max( gl, wl )
                    gu = min( gu, wu )
                    if( gl>=gu )cycle loop_70
                 end if
                 ! set up initial interval
                 work( n+1 ) = gl
                 work( n+in+1 ) = gu
                 call stdlib${ii}$_dlaebz( 1_${ik}$, 0_${ik}$, in, in, 1_${ik}$, nb, atoli, rtoli, pivmin,d( ibegin ), e( &
                 ibegin ), work( ibegin ),idumma, work( n+1 ), work( n+2*in+1 ), im,iwork, w( m+1 &
                           ), iblock( m+1 ), iinfo )
                 nwl = nwl + iwork( 1_${ik}$ )
                 nwu = nwu + iwork( in+1 )
                 iwoff = m - iwork( 1_${ik}$ )
                 ! compute eigenvalues
                 itmax = int( ( log( gu-gl+pivmin )-log( pivmin ) ) /log( two ),KIND=${ik}$) + &
                           2_${ik}$
                 call stdlib${ii}$_dlaebz( 2_${ik}$, itmax, in, in, 1_${ik}$, nb, atoli, rtoli, pivmin,d( ibegin ), e(&
                  ibegin ), work( ibegin ),idumma, work( n+1 ), work( n+2*in+1 ), iout,iwork, w( &
                            m+1 ), iblock( m+1 ), iinfo )
                 ! copy eigenvalues into w and iblock
                 ! use -jb for block number for unconverged eigenvalues.
                 do j = 1, iout
                    tmp1 = half*( work( j+n )+work( j+in+n ) )
                    ! flag non-convergence.
                    if( j>iout-iinfo ) then
                       ncnvrg = .true.
                       ib = -jb
                    else
                       ib = jb
                    end if
                    do je = iwork( j ) + 1 + iwoff,iwork( j+in ) + iwoff
                       w( je ) = tmp1
                       iblock( je ) = ib
                    end do
                 end do
                 m = m + im
              end if
           end do loop_70
           ! if range='i', then (wl,wu) contains eigenvalues nwl+1,...,nwu
           ! if nwl+1 < il or nwu > iu, discard extra eigenvalues.
           if( irange==3_${ik}$ ) then
              im = 0_${ik}$
              idiscl = il - 1_${ik}$ - nwl
              idiscu = nwu - iu
              if( idiscl>0_${ik}$ .or. idiscu>0_${ik}$ ) then
                 do je = 1, m
                    if( w( je )<=wlu .and. idiscl>0_${ik}$ ) then
                       idiscl = idiscl - 1_${ik}$
                    else if( w( je )>=wul .and. idiscu>0_${ik}$ ) then
                       idiscu = idiscu - 1_${ik}$
                    else
                       im = im + 1_${ik}$
                       w( im ) = w( je )
                       iblock( im ) = iblock( je )
                    end if
                 end do
                 m = im
              end if
              if( idiscl>0_${ik}$ .or. idiscu>0_${ik}$ ) then
                 ! code to deal with effects of bad arithmetic:
                 ! some low eigenvalues to be discarded are not in (wl,wlu],
                 ! or high eigenvalues to be discarded are not in (wul,wu]
                 ! so just kill off the smallest idiscl/largest idiscu
                 ! eigenvalues, by simply finding the smallest/largest
                 ! eigenvalue(s).
                 ! (if n(w) is monotone non-decreasing, this should never
                     ! happen.)
                 if( idiscl>0_${ik}$ ) then
                    wkill = wu
                    do jdisc = 1, idiscl
                       iw = 0_${ik}$
                       do je = 1, m
                          if( iblock( je )/=0_${ik}$ .and.( w( je )<wkill .or. iw==0_${ik}$ ) ) then
                             iw = je
                             wkill = w( je )
                          end if
                       end do
                       iblock( iw ) = 0_${ik}$
                    end do
                 end if
                 if( idiscu>0_${ik}$ ) then
                    wkill = wl
                    do jdisc = 1, idiscu
                       iw = 0_${ik}$
                       do je = 1, m
                          if( iblock( je )/=0_${ik}$ .and.( w( je )>wkill .or. iw==0_${ik}$ ) ) then
                             iw = je
                             wkill = w( je )
                          end if
                       end do
                       iblock( iw ) = 0_${ik}$
                    end do
                 end if
                 im = 0_${ik}$
                 do je = 1, m
                    if( iblock( je )/=0_${ik}$ ) then
                       im = im + 1_${ik}$
                       w( im ) = w( je )
                       iblock( im ) = iblock( je )
                    end if
                 end do
                 m = im
              end if
              if( idiscl<0_${ik}$ .or. idiscu<0_${ik}$ ) then
                 toofew = .true.
              end if
           end if
           ! if order='b', do nothing -- the eigenvalues are already sorted
              ! by block.
           ! if order='e', sort the eigenvalues from smallest to largest
           if( iorder==1_${ik}$ .and. nsplit>1_${ik}$ ) then
              do je = 1, m - 1
                 ie = 0_${ik}$
                 tmp1 = w( je )
                 do j = je + 1, m
                    if( w( j )<tmp1 ) then
                       ie = j
                       tmp1 = w( j )
                    end if
                 end do
                 if( ie/=0_${ik}$ ) then
                    itmp1 = iblock( ie )
                    w( ie ) = w( je )
                    iblock( ie ) = iblock( je )
                    w( je ) = tmp1
                    iblock( je ) = itmp1
                 end if
              end do
           end if
           info = 0_${ik}$
           if( ncnvrg )info = info + 1_${ik}$
           if( toofew )info = info + 2_${ik}$
           return
     end subroutine stdlib${ii}$_dstebz

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stebz( range, order, n, vl, vu, il, iu, abstol, d, e,m, nsplit, w, &
     !! DSTEBZ: computes the eigenvalues of a symmetric tridiagonal
     !! matrix T.  The user may ask for all eigenvalues, all eigenvalues
     !! in the half-open interval (VL, VU], or the IL-th through IU-th
     !! eigenvalues.
     !! To avoid overflow, the matrix must be scaled so that its
     !! largest element is no greater than overflow**(1/2) * underflow**(1/4) in absolute value, and for greatest
     !! accuracy, it should not be much smaller than that.
     !! See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal
     !! Matrix", Report CS41, Computer Science Dept., Stanford
     !! University, July 21, 1966.
               iblock, isplit, 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 
           character, intent(in) :: order, range
           integer(${ik}$), intent(in) :: il, iu, n
           integer(${ik}$), intent(out) :: info, m, nsplit
           real(${rk}$), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iblock(*), isplit(*), iwork(*)
           real(${rk}$), intent(in) :: d(*), e(*)
           real(${rk}$), intent(out) :: w(*), work(*)
        ! =====================================================================
           ! Parameters 
           real(${rk}$), parameter :: fudge = 2.1_${rk}$
           real(${rk}$), parameter :: relfac = two
           
           
           ! Local Scalars 
           logical(lk) :: ncnvrg, toofew
           integer(${ik}$) :: ib, ibegin, idiscl, idiscu, ie, iend, iinfo, im, in, ioff, iorder, &
                     iout, irange, itmax, itmp1, iw, iwoff, j, jb, jdisc, je, nb, nwl, nwu
           real(${rk}$) :: atoli, bnorm, gl, gu, pivmin, rtoli, safemn, tmp1, tmp2, tnorm, ulp, wkill,&
                      wl, wlu, wu, wul
           ! Local Arrays 
           integer(${ik}$) :: idumma(1_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           info = 0_${ik}$
           ! decode range
           if( stdlib_lsame( range, 'A' ) ) then
              irange = 1_${ik}$
           else if( stdlib_lsame( range, 'V' ) ) then
              irange = 2_${ik}$
           else if( stdlib_lsame( range, 'I' ) ) then
              irange = 3_${ik}$
           else
              irange = 0_${ik}$
           end if
           ! decode order
           if( stdlib_lsame( order, 'B' ) ) then
              iorder = 2_${ik}$
           else if( stdlib_lsame( order, 'E' ) ) then
              iorder = 1_${ik}$
           else
              iorder = 0_${ik}$
           end if
           ! check for errors
           if( irange<=0_${ik}$ ) then
              info = -1_${ik}$
           else if( iorder<=0_${ik}$ ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( irange==2_${ik}$ ) then
              if( vl>=vu )info = -5_${ik}$
           else if( irange==3_${ik}$ .and. ( il<1_${ik}$ .or. il>max( 1_${ik}$, n ) ) )then
              info = -6_${ik}$
           else if( irange==3_${ik}$ .and. ( iu<min( n, il ) .or. iu>n ) )then
              info = -7_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEBZ', -info )
              return
           end if
           ! initialize error flags
           info = 0_${ik}$
           ncnvrg = .false.
           toofew = .false.
           ! quick return if possible
           m = 0_${ik}$
           if( n==0 )return
           ! simplifications:
           if( irange==3_${ik}$ .and. il==1_${ik}$ .and. iu==n )irange = 1_${ik}$
           ! get machine constants
           ! nb is the minimum vector length for vector bisection, or 0
           ! if only scalar is to be done.
           safemn = stdlib${ii}$_${ri}$lamch( 'S' )
           ulp = stdlib${ii}$_${ri}$lamch( 'P' )
           rtoli = ulp*relfac
           nb = stdlib${ii}$_ilaenv( 1_${ik}$, 'DSTEBZ', ' ', n, -1_${ik}$, -1_${ik}$, -1_${ik}$ )
           if( nb<=1_${ik}$ )nb = 0_${ik}$
           ! special case when n=1
           if( n==1_${ik}$ ) then
              nsplit = 1_${ik}$
              isplit( 1_${ik}$ ) = 1_${ik}$
              if( irange==2_${ik}$ .and. ( vl>=d( 1_${ik}$ ) .or. vu<d( 1_${ik}$ ) ) ) then
                 m = 0_${ik}$
              else
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
                 iblock( 1_${ik}$ ) = 1_${ik}$
                 m = 1_${ik}$
              end if
              return
           end if
           ! compute splitting points
           nsplit = 1_${ik}$
           work( n ) = zero
           pivmin = one
           do j = 2, n
              tmp1 = e( j-1 )**2_${ik}$
              if( abs( d( j )*d( j-1 ) )*ulp**2_${ik}$+safemn>tmp1 ) then
                 isplit( nsplit ) = j - 1_${ik}$
                 nsplit = nsplit + 1_${ik}$
                 work( j-1 ) = zero
              else
                 work( j-1 ) = tmp1
                 pivmin = max( pivmin, tmp1 )
              end if
           end do
           isplit( nsplit ) = n
           pivmin = pivmin*safemn
           ! compute interval and atoli
           if( irange==3_${ik}$ ) then
              ! range='i': compute the interval containing eigenvalues
                         ! il through iu.
              ! compute gershgorin interval for entire (split) matrix
              ! and use it as the initial interval
              gu = d( 1_${ik}$ )
              gl = d( 1_${ik}$ )
              tmp1 = zero
              do j = 1, n - 1
                 tmp2 = sqrt( work( j ) )
                 gu = max( gu, d( j )+tmp1+tmp2 )
                 gl = min( gl, d( j )-tmp1-tmp2 )
                 tmp1 = tmp2
              end do
              gu = max( gu, d( n )+tmp1 )
              gl = min( gl, d( n )-tmp1 )
              tnorm = max( abs( gl ), abs( gu ) )
              gl = gl - fudge*tnorm*ulp*n - fudge*two*pivmin
              gu = gu + fudge*tnorm*ulp*n + fudge*pivmin
              ! compute iteration parameters
              itmax = int( ( log( tnorm+pivmin )-log( pivmin ) ) /log( two ),KIND=${ik}$) + 2_${ik}$
              if( abstol<=zero ) then
                 atoli = ulp*tnorm
              else
                 atoli = abstol
              end if
              work( n+1 ) = gl
              work( n+2 ) = gl
              work( n+3 ) = gu
              work( n+4 ) = gu
              work( n+5 ) = gl
              work( n+6 ) = gu
              iwork( 1_${ik}$ ) = -1_${ik}$
              iwork( 2_${ik}$ ) = -1_${ik}$
              iwork( 3_${ik}$ ) = n + 1_${ik}$
              iwork( 4_${ik}$ ) = n + 1_${ik}$
              iwork( 5_${ik}$ ) = il - 1_${ik}$
              iwork( 6_${ik}$ ) = iu
              call stdlib${ii}$_${ri}$laebz( 3_${ik}$, itmax, n, 2_${ik}$, 2_${ik}$, nb, atoli, rtoli, pivmin, d, e,work, iwork( &
                        5_${ik}$ ), work( n+1 ), work( n+5 ), iout,iwork, w, iblock, iinfo )
              if( iwork( 6_${ik}$ )==iu ) then
                 wl = work( n+1 )
                 wlu = work( n+3 )
                 nwl = iwork( 1_${ik}$ )
                 wu = work( n+4 )
                 wul = work( n+2 )
                 nwu = iwork( 4_${ik}$ )
              else
                 wl = work( n+2 )
                 wlu = work( n+4 )
                 nwl = iwork( 2_${ik}$ )
                 wu = work( n+3 )
                 wul = work( n+1 )
                 nwu = iwork( 3_${ik}$ )
              end if
              if( nwl<0_${ik}$ .or. nwl>=n .or. nwu<1_${ik}$ .or. nwu>n ) then
                 info = 4_${ik}$
                 return
              end if
           else
              ! range='a' or 'v' -- set atoli
              tnorm = max( abs( d( 1_${ik}$ ) )+abs( e( 1_${ik}$ ) ),abs( d( n ) )+abs( e( n-1 ) ) )
              do j = 2, n - 1
                 tnorm = max( tnorm, abs( d( j ) )+abs( e( j-1 ) )+abs( e( j ) ) )
              end do
              if( abstol<=zero ) then
                 atoli = ulp*tnorm
              else
                 atoli = abstol
              end if
              if( irange==2_${ik}$ ) then
                 wl = vl
                 wu = vu
              else
                 wl = zero
                 wu = zero
              end if
           end if
           ! find eigenvalues -- loop over blocks and recompute nwl and nwu.
           ! nwl accumulates the number of eigenvalues .le. wl,
           ! nwu accumulates the number of eigenvalues .le. wu
           m = 0_${ik}$
           iend = 0_${ik}$
           info = 0_${ik}$
           nwl = 0_${ik}$
           nwu = 0_${ik}$
           loop_70: do jb = 1, nsplit
              ioff = iend
              ibegin = ioff + 1_${ik}$
              iend = isplit( jb )
              in = iend - ioff
              if( in==1_${ik}$ ) then
                 ! special case -- in=1
                 if( irange==1_${ik}$ .or. wl>=d( ibegin )-pivmin )nwl = nwl + 1_${ik}$
                 if( irange==1_${ik}$ .or. wu>=d( ibegin )-pivmin )nwu = nwu + 1_${ik}$
                 if( irange==1_${ik}$ .or. ( wl<d( ibegin )-pivmin .and. wu>=d( ibegin )-pivmin ) ) &
                           then
                    m = m + 1_${ik}$
                    w( m ) = d( ibegin )
                    iblock( m ) = jb
                 end if
              else
                 ! general case -- in > 1
                 ! compute gershgorin interval
                 ! and use it as the initial interval
                 gu = d( ibegin )
                 gl = d( ibegin )
                 tmp1 = zero
                 do j = ibegin, iend - 1
                    tmp2 = abs( e( j ) )
                    gu = max( gu, d( j )+tmp1+tmp2 )
                    gl = min( gl, d( j )-tmp1-tmp2 )
                    tmp1 = tmp2
                 end do
                 gu = max( gu, d( iend )+tmp1 )
                 gl = min( gl, d( iend )-tmp1 )
                 bnorm = max( abs( gl ), abs( gu ) )
                 gl = gl - fudge*bnorm*ulp*in - fudge*pivmin
                 gu = gu + fudge*bnorm*ulp*in + fudge*pivmin
                 ! compute atoli for the current submatrix
                 if( abstol<=zero ) then
                    atoli = ulp*max( abs( gl ), abs( gu ) )
                 else
                    atoli = abstol
                 end if
                 if( irange>1_${ik}$ ) then
                    if( gu<wl ) then
                       nwl = nwl + in
                       nwu = nwu + in
                       cycle loop_70
                    end if
                    gl = max( gl, wl )
                    gu = min( gu, wu )
                    if( gl>=gu )cycle loop_70
                 end if
                 ! set up initial interval
                 work( n+1 ) = gl
                 work( n+in+1 ) = gu
                 call stdlib${ii}$_${ri}$laebz( 1_${ik}$, 0_${ik}$, in, in, 1_${ik}$, nb, atoli, rtoli, pivmin,d( ibegin ), e( &
                 ibegin ), work( ibegin ),idumma, work( n+1 ), work( n+2*in+1 ), im,iwork, w( m+1 &
                           ), iblock( m+1 ), iinfo )
                 nwl = nwl + iwork( 1_${ik}$ )
                 nwu = nwu + iwork( in+1 )
                 iwoff = m - iwork( 1_${ik}$ )
                 ! compute eigenvalues
                 itmax = int( ( log( gu-gl+pivmin )-log( pivmin ) ) /log( two ),KIND=${ik}$) + &
                           2_${ik}$
                 call stdlib${ii}$_${ri}$laebz( 2_${ik}$, itmax, in, in, 1_${ik}$, nb, atoli, rtoli, pivmin,d( ibegin ), e(&
                  ibegin ), work( ibegin ),idumma, work( n+1 ), work( n+2*in+1 ), iout,iwork, w( &
                            m+1 ), iblock( m+1 ), iinfo )
                 ! copy eigenvalues into w and iblock
                 ! use -jb for block number for unconverged eigenvalues.
                 do j = 1, iout
                    tmp1 = half*( work( j+n )+work( j+in+n ) )
                    ! flag non-convergence.
                    if( j>iout-iinfo ) then
                       ncnvrg = .true.
                       ib = -jb
                    else
                       ib = jb
                    end if
                    do je = iwork( j ) + 1 + iwoff,iwork( j+in ) + iwoff
                       w( je ) = tmp1
                       iblock( je ) = ib
                    end do
                 end do
                 m = m + im
              end if
           end do loop_70
           ! if range='i', then (wl,wu) contains eigenvalues nwl+1,...,nwu
           ! if nwl+1 < il or nwu > iu, discard extra eigenvalues.
           if( irange==3_${ik}$ ) then
              im = 0_${ik}$
              idiscl = il - 1_${ik}$ - nwl
              idiscu = nwu - iu
              if( idiscl>0_${ik}$ .or. idiscu>0_${ik}$ ) then
                 do je = 1, m
                    if( w( je )<=wlu .and. idiscl>0_${ik}$ ) then
                       idiscl = idiscl - 1_${ik}$
                    else if( w( je )>=wul .and. idiscu>0_${ik}$ ) then
                       idiscu = idiscu - 1_${ik}$
                    else
                       im = im + 1_${ik}$
                       w( im ) = w( je )
                       iblock( im ) = iblock( je )
                    end if
                 end do
                 m = im
              end if
              if( idiscl>0_${ik}$ .or. idiscu>0_${ik}$ ) then
                 ! code to deal with effects of bad arithmetic:
                 ! some low eigenvalues to be discarded are not in (wl,wlu],
                 ! or high eigenvalues to be discarded are not in (wul,wu]
                 ! so just kill off the smallest idiscl/largest idiscu
                 ! eigenvalues, by simply finding the smallest/largest
                 ! eigenvalue(s).
                 ! (if n(w) is monotone non-decreasing, this should never
                     ! happen.)
                 if( idiscl>0_${ik}$ ) then
                    wkill = wu
                    do jdisc = 1, idiscl
                       iw = 0_${ik}$
                       do je = 1, m
                          if( iblock( je )/=0_${ik}$ .and.( w( je )<wkill .or. iw==0_${ik}$ ) ) then
                             iw = je
                             wkill = w( je )
                          end if
                       end do
                       iblock( iw ) = 0_${ik}$
                    end do
                 end if
                 if( idiscu>0_${ik}$ ) then
                    wkill = wl
                    do jdisc = 1, idiscu
                       iw = 0_${ik}$
                       do je = 1, m
                          if( iblock( je )/=0_${ik}$ .and.( w( je )>wkill .or. iw==0_${ik}$ ) ) then
                             iw = je
                             wkill = w( je )
                          end if
                       end do
                       iblock( iw ) = 0_${ik}$
                    end do
                 end if
                 im = 0_${ik}$
                 do je = 1, m
                    if( iblock( je )/=0_${ik}$ ) then
                       im = im + 1_${ik}$
                       w( im ) = w( je )
                       iblock( im ) = iblock( je )
                    end if
                 end do
                 m = im
              end if
              if( idiscl<0_${ik}$ .or. idiscu<0_${ik}$ ) then
                 toofew = .true.
              end if
           end if
           ! if order='b', do nothing -- the eigenvalues are already sorted
              ! by block.
           ! if order='e', sort the eigenvalues from smallest to largest
           if( iorder==1_${ik}$ .and. nsplit>1_${ik}$ ) then
              do je = 1, m - 1
                 ie = 0_${ik}$
                 tmp1 = w( je )
                 do j = je + 1, m
                    if( w( j )<tmp1 ) then
                       ie = j
                       tmp1 = w( j )
                    end if
                 end do
                 if( ie/=0_${ik}$ ) then
                    itmp1 = iblock( ie )
                    w( ie ) = w( je )
                    iblock( ie ) = iblock( je )
                    w( je ) = tmp1
                    iblock( je ) = itmp1
                 end if
              end do
           end if
           info = 0_${ik}$
           if( ncnvrg )info = info + 1_${ik}$
           if( toofew )info = info + 2_${ik}$
           return
     end subroutine stdlib${ii}$_${ri}$stebz

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_ssterf( n, d, e, info )
     !! SSTERF computes all eigenvalues of a symmetric tridiagonal matrix
     !! using the Pal-Walker-Kahan variant of the QL or QR algorithm.
        ! -- 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) :: n
           ! Array Arguments 
           real(sp), intent(inout) :: d(*), e(*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, iscale, jtot, l, l1, lend, lendsv, lsv, m, nmaxit
           real(sp) :: alpha, anorm, bb, c, eps, eps2, gamma, oldc, oldgam, p, r, rt1, rt2, rte, &
                     s, safmax, safmin, sigma, ssfmax, ssfmin
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           ! quick return if possible
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
              call stdlib${ii}$_xerbla( 'SSTERF', -info )
              return
           end if
           if( n<=1 )return
           ! determine the unit roundoff for this environment.
           eps = stdlib${ii}$_slamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_slamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues of the tridiagonal matrix.
           nmaxit = n*maxit
           sigma = zero
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           10 continue
           if( l1>n )go to 170
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           do m = l1, n - 1
              if( abs( e( m ) )<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) &
                        then
                 e( m ) = zero
                 go to 30
              end if
           end do
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_slanst( 'M', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           do i = l, lend - 1
              e( i ) = e( i )**2_${ik}$
           end do
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>=l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              50 continue
              if( l/=lend ) then
                 do m = l, lend - 1
                    if( abs( e( m ) )<=eps2*abs( d( m )*d( m+1 ) ) )go to 70
                 end do
              end if
              m = lend
              70 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 90
              ! if remaining matrix is 2 by 2, use stdlib_slae2 to compute its
              ! eigenvalues.
              if( m==l+1 ) then
                 rte = sqrt( e( l ) )
                 call stdlib${ii}$_slae2( d( l ), rte, d( l+1 ), rt1, rt2 )
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 50
                 go to 150
              end if
              if( jtot==nmaxit )go to 150
              jtot = jtot + 1_${ik}$
              ! form shift.
              rte = sqrt( e( l ) )
              sigma = ( d( l+1 )-p ) / ( two*rte )
              r = stdlib${ii}$_slapy2( sigma, one )
              sigma = p - ( rte / ( sigma+sign( r, sigma ) ) )
              c = one
              s = zero
              gamma = d( m ) - sigma
              p = gamma*gamma
              ! inner loop
              do i = m - 1, l, -1
                 bb = e( i )
                 r = p + bb
                 if( i/=m-1 )e( i+1 ) = s*r
                 oldc = c
                 c = p / r
                 s = bb / r
                 oldgam = gamma
                 alpha = d( i )
                 gamma = c*( alpha-sigma ) - s*oldgam
                 d( i+1 ) = oldgam + ( alpha-gamma )
                 if( c/=zero ) then
                    p = ( gamma*gamma ) / c
                 else
                    p = oldc*bb
                 end if
              end do
              e( l ) = s*p
              d( l ) = sigma + gamma
              go to 50
              ! eigenvalue found.
              90 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 50
              go to 150
           else
              ! qr iteration
              ! look for small superdiagonal element.
              100 continue
              do m = l, lend + 1, -1
                 if( abs( e( m-1 ) )<=eps2*abs( d( m )*d( m-1 ) ) )go to 120
              end do
              m = lend
              120 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 140
              ! if remaining matrix is 2 by 2, use stdlib_slae2 to compute its
              ! eigenvalues.
              if( m==l-1 ) then
                 rte = sqrt( e( l-1 ) )
                 call stdlib${ii}$_slae2( d( l ), rte, d( l-1 ), rt1, rt2 )
                 d( l ) = rt1
                 d( l-1 ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 100
                 go to 150
              end if
              if( jtot==nmaxit )go to 150
              jtot = jtot + 1_${ik}$
              ! form shift.
              rte = sqrt( e( l-1 ) )
              sigma = ( d( l-1 )-p ) / ( two*rte )
              r = stdlib${ii}$_slapy2( sigma, one )
              sigma = p - ( rte / ( sigma+sign( r, sigma ) ) )
              c = one
              s = zero
              gamma = d( m ) - sigma
              p = gamma*gamma
              ! inner loop
              do i = m, l - 1
                 bb = e( i )
                 r = p + bb
                 if( i/=m )e( i-1 ) = s*r
                 oldc = c
                 c = p / r
                 s = bb / r
                 oldgam = gamma
                 alpha = d( i+1 )
                 gamma = c*( alpha-sigma ) - s*oldgam
                 d( i ) = oldgam + ( alpha-gamma )
                 if( c/=zero ) then
                    p = ( gamma*gamma ) / c
                 else
                    p = oldc*bb
                 end if
              end do
              e( l-1 ) = s*p
              d( l ) = sigma + gamma
              go to 100
              ! eigenvalue found.
              140 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 100
              go to 150
           end if
           ! undo scaling if necessary
           150 continue
           if( iscale==1_${ik}$ )call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), &
                     n, info )
           if( iscale==2_${ik}$ )call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), &
                     n, info )
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot<nmaxit )go to 10
           do i = 1, n - 1
              if( e( i )/=zero )info = info + 1_${ik}$
           end do
           go to 180
           ! sort eigenvalues in increasing order.
           170 continue
           call stdlib${ii}$_slasrt( 'I', n, d, info )
           180 continue
           return
     end subroutine stdlib${ii}$_ssterf

     pure module subroutine stdlib${ii}$_dsterf( n, d, e, info )
     !! DSTERF computes all eigenvalues of a symmetric tridiagonal matrix
     !! using the Pal-Walker-Kahan variant of the QL or QR algorithm.
        ! -- 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) :: n
           ! Array Arguments 
           real(dp), intent(inout) :: d(*), e(*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, iscale, jtot, l, l1, lend, lendsv, lsv, m, nmaxit
           real(dp) :: alpha, anorm, bb, c, eps, eps2, gamma, oldc, oldgam, p, r, rt1, rt2, rte, &
                     s, safmax, safmin, sigma, ssfmax, ssfmin, rmax
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           ! quick return if possible
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
              call stdlib${ii}$_xerbla( 'DSTERF', -info )
              return
           end if
           if( n<=1 )return
           ! determine the unit roundoff for this environment.
           eps = stdlib${ii}$_dlamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_dlamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           rmax = stdlib${ii}$_dlamch( 'O' )
           ! compute the eigenvalues of the tridiagonal matrix.
           nmaxit = n*maxit
           sigma = zero
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           10 continue
           if( l1>n )go to 170
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           do m = l1, n - 1
              if( abs( e( m ) )<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) &
                        then
                 e( m ) = zero
                 go to 30
              end if
           end do
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_dlanst( 'M', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( (anorm>ssfmax) ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           do i = l, lend - 1
              e( i ) = e( i )**2_${ik}$
           end do
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>=l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              50 continue
              if( l/=lend ) then
                 do m = l, lend - 1
                    if( abs( e( m ) )<=eps2*abs( d( m )*d( m+1 ) ) )go to 70
                 end do
              end if
              m = lend
              70 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 90
              ! if remaining matrix is 2 by 2, use stdlib_dlae2 to compute its
              ! eigenvalues.
              if( m==l+1 ) then
                 rte = sqrt( e( l ) )
                 call stdlib${ii}$_dlae2( d( l ), rte, d( l+1 ), rt1, rt2 )
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 50
                 go to 150
              end if
              if( jtot==nmaxit )go to 150
              jtot = jtot + 1_${ik}$
              ! form shift.
              rte = sqrt( e( l ) )
              sigma = ( d( l+1 )-p ) / ( two*rte )
              r = stdlib${ii}$_dlapy2( sigma, one )
              sigma = p - ( rte / ( sigma+sign( r, sigma ) ) )
              c = one
              s = zero
              gamma = d( m ) - sigma
              p = gamma*gamma
              ! inner loop
              do i = m - 1, l, -1
                 bb = e( i )
                 r = p + bb
                 if( i/=m-1 )e( i+1 ) = s*r
                 oldc = c
                 c = p / r
                 s = bb / r
                 oldgam = gamma
                 alpha = d( i )
                 gamma = c*( alpha-sigma ) - s*oldgam
                 d( i+1 ) = oldgam + ( alpha-gamma )
                 if( c/=zero ) then
                    p = ( gamma*gamma ) / c
                 else
                    p = oldc*bb
                 end if
              end do
              e( l ) = s*p
              d( l ) = sigma + gamma
              go to 50
              ! eigenvalue found.
              90 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 50
              go to 150
           else
              ! qr iteration
              ! look for small superdiagonal element.
              100 continue
              do m = l, lend + 1, -1
                 if( abs( e( m-1 ) )<=eps2*abs( d( m )*d( m-1 ) ) )go to 120
              end do
              m = lend
              120 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 140
              ! if remaining matrix is 2 by 2, use stdlib_dlae2 to compute its
              ! eigenvalues.
              if( m==l-1 ) then
                 rte = sqrt( e( l-1 ) )
                 call stdlib${ii}$_dlae2( d( l ), rte, d( l-1 ), rt1, rt2 )
                 d( l ) = rt1
                 d( l-1 ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 100
                 go to 150
              end if
              if( jtot==nmaxit )go to 150
              jtot = jtot + 1_${ik}$
              ! form shift.
              rte = sqrt( e( l-1 ) )
              sigma = ( d( l-1 )-p ) / ( two*rte )
              r = stdlib${ii}$_dlapy2( sigma, one )
              sigma = p - ( rte / ( sigma+sign( r, sigma ) ) )
              c = one
              s = zero
              gamma = d( m ) - sigma
              p = gamma*gamma
              ! inner loop
              do i = m, l - 1
                 bb = e( i )
                 r = p + bb
                 if( i/=m )e( i-1 ) = s*r
                 oldc = c
                 c = p / r
                 s = bb / r
                 oldgam = gamma
                 alpha = d( i+1 )
                 gamma = c*( alpha-sigma ) - s*oldgam
                 d( i ) = oldgam + ( alpha-gamma )
                 if( c/=zero ) then
                    p = ( gamma*gamma ) / c
                 else
                    p = oldc*bb
                 end if
              end do
              e( l-1 ) = s*p
              d( l ) = sigma + gamma
              go to 100
              ! eigenvalue found.
              140 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 100
              go to 150
           end if
           ! undo scaling if necessary
           150 continue
           if( iscale==1_${ik}$ )call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), &
                     n, info )
           if( iscale==2_${ik}$ )call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), &
                     n, info )
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot<nmaxit )go to 10
           do i = 1, n - 1
              if( e( i )/=zero )info = info + 1_${ik}$
           end do
           go to 180
           ! sort eigenvalues in increasing order.
           170 continue
           call stdlib${ii}$_dlasrt( 'I', n, d, info )
           180 continue
           return
     end subroutine stdlib${ii}$_dsterf

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$sterf( n, d, e, info )
     !! DSTERF: computes all eigenvalues of a symmetric tridiagonal matrix
     !! using the Pal-Walker-Kahan variant of the QL or QR algorithm.
        ! -- 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) :: n
           ! Array Arguments 
           real(${rk}$), intent(inout) :: d(*), e(*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, iscale, jtot, l, l1, lend, lendsv, lsv, m, nmaxit
           real(${rk}$) :: alpha, anorm, bb, c, eps, eps2, gamma, oldc, oldgam, p, r, rt1, rt2, rte, &
                     s, safmax, safmin, sigma, ssfmax, ssfmin, rmax
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           ! quick return if possible
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
              call stdlib${ii}$_xerbla( 'DSTERF', -info )
              return
           end if
           if( n<=1 )return
           ! determine the unit roundoff for this environment.
           eps = stdlib${ii}$_${ri}$lamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_${ri}$lamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           rmax = stdlib${ii}$_${ri}$lamch( 'O' )
           ! compute the eigenvalues of the tridiagonal matrix.
           nmaxit = n*maxit
           sigma = zero
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           10 continue
           if( l1>n )go to 170
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           do m = l1, n - 1
              if( abs( e( m ) )<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) &
                        then
                 e( m ) = zero
                 go to 30
              end if
           end do
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_${ri}$lanst( 'M', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( (anorm>ssfmax) ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           do i = l, lend - 1
              e( i ) = e( i )**2_${ik}$
           end do
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>=l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              50 continue
              if( l/=lend ) then
                 do m = l, lend - 1
                    if( abs( e( m ) )<=eps2*abs( d( m )*d( m+1 ) ) )go to 70
                 end do
              end if
              m = lend
              70 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 90
              ! if remaining matrix is 2 by 2, use stdlib_${ri}$lae2 to compute its
              ! eigenvalues.
              if( m==l+1 ) then
                 rte = sqrt( e( l ) )
                 call stdlib${ii}$_${ri}$lae2( d( l ), rte, d( l+1 ), rt1, rt2 )
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 50
                 go to 150
              end if
              if( jtot==nmaxit )go to 150
              jtot = jtot + 1_${ik}$
              ! form shift.
              rte = sqrt( e( l ) )
              sigma = ( d( l+1 )-p ) / ( two*rte )
              r = stdlib${ii}$_${ri}$lapy2( sigma, one )
              sigma = p - ( rte / ( sigma+sign( r, sigma ) ) )
              c = one
              s = zero
              gamma = d( m ) - sigma
              p = gamma*gamma
              ! inner loop
              do i = m - 1, l, -1
                 bb = e( i )
                 r = p + bb
                 if( i/=m-1 )e( i+1 ) = s*r
                 oldc = c
                 c = p / r
                 s = bb / r
                 oldgam = gamma
                 alpha = d( i )
                 gamma = c*( alpha-sigma ) - s*oldgam
                 d( i+1 ) = oldgam + ( alpha-gamma )
                 if( c/=zero ) then
                    p = ( gamma*gamma ) / c
                 else
                    p = oldc*bb
                 end if
              end do
              e( l ) = s*p
              d( l ) = sigma + gamma
              go to 50
              ! eigenvalue found.
              90 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 50
              go to 150
           else
              ! qr iteration
              ! look for small superdiagonal element.
              100 continue
              do m = l, lend + 1, -1
                 if( abs( e( m-1 ) )<=eps2*abs( d( m )*d( m-1 ) ) )go to 120
              end do
              m = lend
              120 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 140
              ! if remaining matrix is 2 by 2, use stdlib_${ri}$lae2 to compute its
              ! eigenvalues.
              if( m==l-1 ) then
                 rte = sqrt( e( l-1 ) )
                 call stdlib${ii}$_${ri}$lae2( d( l ), rte, d( l-1 ), rt1, rt2 )
                 d( l ) = rt1
                 d( l-1 ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 100
                 go to 150
              end if
              if( jtot==nmaxit )go to 150
              jtot = jtot + 1_${ik}$
              ! form shift.
              rte = sqrt( e( l-1 ) )
              sigma = ( d( l-1 )-p ) / ( two*rte )
              r = stdlib${ii}$_${ri}$lapy2( sigma, one )
              sigma = p - ( rte / ( sigma+sign( r, sigma ) ) )
              c = one
              s = zero
              gamma = d( m ) - sigma
              p = gamma*gamma
              ! inner loop
              do i = m, l - 1
                 bb = e( i )
                 r = p + bb
                 if( i/=m )e( i-1 ) = s*r
                 oldc = c
                 c = p / r
                 s = bb / r
                 oldgam = gamma
                 alpha = d( i+1 )
                 gamma = c*( alpha-sigma ) - s*oldgam
                 d( i ) = oldgam + ( alpha-gamma )
                 if( c/=zero ) then
                    p = ( gamma*gamma ) / c
                 else
                    p = oldc*bb
                 end if
              end do
              e( l-1 ) = s*p
              d( l ) = sigma + gamma
              go to 100
              ! eigenvalue found.
              140 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 100
              go to 150
           end if
           ! undo scaling if necessary
           150 continue
           if( iscale==1_${ik}$ )call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), &
                     n, info )
           if( iscale==2_${ik}$ )call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), &
                     n, info )
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot<nmaxit )go to 10
           do i = 1, n - 1
              if( e( i )/=zero )info = info + 1_${ik}$
           end do
           go to 180
           ! sort eigenvalues in increasing order.
           170 continue
           call stdlib${ii}$_${ri}$lasrt( 'I', n, d, info )
           180 continue
           return
     end subroutine stdlib${ii}$_${ri}$sterf

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstedc( compz, n, d, e, z, ldz, work, lwork, iwork,liwork, info )
     !! SSTEDC computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the divide and conquer method.
     !! The eigenvectors of a full or band real symmetric matrix can also be
     !! found if SSYTRD or SSPTRD or SSBTRD has been used to reduce this
     !! matrix to tridiagonal form.
     !! 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.  See SLAED3 for details.
               
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(sp), intent(inout) :: d(*), e(*), z(ldz,*)
           real(sp), intent(out) :: work(*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery
           integer(${ik}$) :: finish, i, icompz, ii, j, k, lgn, liwmin, lwmin, m, smlsiz, start, &
                     storez, strtrw
           real(sp) :: eps, orgnrm, p, tiny
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           lquery = ( lwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or.( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$, n ) ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              ! compute the workspace requirements
              smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'SSTEDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ )
              if( n<=1_${ik}$ .or. icompz==0_${ik}$ ) then
                 liwmin = 1_${ik}$
                 lwmin = 1_${ik}$
              else if( n<=smlsiz ) then
                 liwmin = 1_${ik}$
                 lwmin = 2_${ik}$*( n - 1_${ik}$ )
              else
                 lgn = int( log( real( n,KIND=sp) )/log( two ),KIND=${ik}$)
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( icompz==1_${ik}$ ) then
                    lwmin = 1_${ik}$ + 3_${ik}$*n + 2_${ik}$*n*lgn + 4_${ik}$*n**2_${ik}$
                    liwmin = 6_${ik}$ + 6_${ik}$*n + 5_${ik}$*n*lgn
                 else if( icompz==2_${ik}$ ) then
                    lwmin = 1_${ik}$ + 4_${ik}$*n + n**2_${ik}$
                    liwmin = 3_${ik}$ + 5_${ik}$*n
                 end if
              end if
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not. lquery ) then
                 info = -8_${ik}$
              else if( liwork<liwmin .and. .not. lquery ) then
                 info = -10_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEDC', -info )
              return
           else if (lquery) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz/=0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! if the following conditional clause is removed, then the routine
           ! will use the divide and conquer routine to compute only the
           ! eigenvalues, which requires (3n + 3n**2) real workspace and
           ! (2 + 5n + 2n lg(n)) integer workspace.
           ! since on many architectures stdlib${ii}$_ssterf is much faster than any other
           ! algorithm for finding eigenvalues only, it is used here
           ! as the default. if the conditional clause is removed, then
           ! information on the size of workspace needs to be changed.
           ! if compz = 'n', use stdlib_ssterf to compute the eigenvalues.
           if( icompz==0_${ik}$ ) then
              call stdlib${ii}$_ssterf( n, d, e, info )
              go to 50
           end if
           ! if n is smaller than the minimum divide size (smlsiz+1), then
           ! solve the problem with another solver.
           if( n<=smlsiz ) then
              call stdlib${ii}$_ssteqr( compz, n, d, e, z, ldz, work, info )
           else
              ! if compz = 'v', the z matrix must be stored elsewhere for later
              ! use.
              if( icompz==1_${ik}$ ) then
                 storez = 1_${ik}$ + n*n
              else
                 storez = 1_${ik}$
              end if
              if( icompz==2_${ik}$ ) then
                 call stdlib${ii}$_slaset( 'FULL', n, n, zero, one, z, ldz )
              end if
              ! scale.
              orgnrm = stdlib${ii}$_slanst( 'M', n, d, e )
              if( orgnrm==zero )go to 50
              eps = stdlib${ii}$_slamch( 'EPSILON' )
              start = 1_${ik}$
              ! while ( start <= n )
              10 continue
              if( start<=n ) then
                 ! let finish be the position of the next subdiagonal entry
                 ! such that e( finish ) <= tiny or finish = n if no such
                 ! subdiagonal exists.  the matrix identified by the elements
                 ! between start and finish constitutes an independent
                 ! sub-problem.
                 finish = start
                 20 continue
                 if( finish<n ) then
                    tiny = eps*sqrt( abs( d( finish ) ) )*sqrt( abs( d( finish+1 ) ) )
                    if( abs( e( finish ) )>tiny ) then
                       finish = finish + 1_${ik}$
                       go to 20
                    end if
                 end if
                 ! (sub) problem determined.  compute its size and solve it.
                 m = finish - start + 1_${ik}$
                 if( m==1_${ik}$ ) then
                    start = finish + 1_${ik}$
                    go to 10
                 end if
                 if( m>smlsiz ) then
                    ! scale.
                    orgnrm = stdlib${ii}$_slanst( 'M', m, d( start ), e( start ) )
                    call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m, 1_${ik}$, d( start ), m,info )
                    call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m-1, 1_${ik}$, e( start ),m-1, info )
                              
                    if( icompz==1_${ik}$ ) then
                       strtrw = 1_${ik}$
                    else
                       strtrw = start
                    end if
                    call stdlib${ii}$_slaed0( icompz, n, m, d( start ), e( start ),z( strtrw, start ), &
                              ldz, work( 1_${ik}$ ), n,work( storez ), iwork, info )
                    if( info/=0_${ik}$ ) then
                       info = ( info / ( m+1 )+start-1 )*( n+1 ) +mod( info, ( m+1 ) ) + start - &
                                 1_${ik}$
                       go to 50
                    end if
                    ! scale back.
                    call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, m, 1_${ik}$, d( start ), m,info )
                 else
                    if( icompz==1_${ik}$ ) then
                       ! since qr won't update a z matrix which is larger than
                       ! the length of d, we must solve the sub-problem in a
                       ! workspace and then multiply back into z.
                       call stdlib${ii}$_ssteqr( 'I', m, d( start ), e( start ), work, m,work( m*m+1 ), &
                                 info )
                       call stdlib${ii}$_slacpy( 'A', n, m, z( 1_${ik}$, start ), ldz,work( storez ), n )
                                 
                       call stdlib${ii}$_sgemm( 'N', 'N', n, m, m, one,work( storez ), n, work, m, zero,&
                                 z( 1_${ik}$, start ), ldz )
                    else if( icompz==2_${ik}$ ) then
                       call stdlib${ii}$_ssteqr( 'I', m, d( start ), e( start ),z( start, start ), ldz, &
                                 work, info )
                    else
                       call stdlib${ii}$_ssterf( m, d( start ), e( start ), info )
                    end if
                    if( info/=0_${ik}$ ) then
                       info = start*( n+1 ) + finish
                       go to 50
                    end if
                 end if
                 start = finish + 1_${ik}$
                 go to 10
              end if
              ! endwhile
              if( icompz==0_${ik}$ ) then
                ! use quick sort
                call stdlib${ii}$_slasrt( 'I', n, d, info )
              else
                ! use selection sort to minimize swaps of eigenvectors
                do ii = 2, n
                   i = ii - 1_${ik}$
                   k = i
                   p = d( i )
                   do j = ii, n
                      if( d( j )<p ) then
                         k = j
                         p = d( j )
                      end if
                   end do
                   if( k/=i ) then
                      d( k ) = d( i )
                      d( i ) = p
                      call stdlib${ii}$_sswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                   end if
                end do
              end if
           end if
           50 continue
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_sstedc

     pure module subroutine stdlib${ii}$_dstedc( compz, n, d, e, z, ldz, work, lwork, iwork,liwork, info )
     !! DSTEDC computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the divide and conquer method.
     !! The eigenvectors of a full or band real symmetric matrix can also be
     !! found if DSYTRD or DSPTRD or DSBTRD has been used to reduce this
     !! matrix to tridiagonal form.
     !! 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.  See DLAED3 for details.
               
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(dp), intent(inout) :: d(*), e(*), z(ldz,*)
           real(dp), intent(out) :: work(*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery
           integer(${ik}$) :: finish, i, icompz, ii, j, k, lgn, liwmin, lwmin, m, smlsiz, start, &
                     storez, strtrw
           real(dp) :: eps, orgnrm, p, tiny
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           lquery = ( lwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or.( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$, n ) ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              ! compute the workspace requirements
              smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'DSTEDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ )
              if( n<=1_${ik}$ .or. icompz==0_${ik}$ ) then
                 liwmin = 1_${ik}$
                 lwmin = 1_${ik}$
              else if( n<=smlsiz ) then
                 liwmin = 1_${ik}$
                 lwmin = 2_${ik}$*( n - 1_${ik}$ )
              else
                 lgn = int( log( real( n,KIND=dp) )/log( two ),KIND=${ik}$)
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( icompz==1_${ik}$ ) then
                    lwmin = 1_${ik}$ + 3_${ik}$*n + 2_${ik}$*n*lgn + 4_${ik}$*n**2_${ik}$
                    liwmin = 6_${ik}$ + 6_${ik}$*n + 5_${ik}$*n*lgn
                 else if( icompz==2_${ik}$ ) then
                    lwmin = 1_${ik}$ + 4_${ik}$*n + n**2_${ik}$
                    liwmin = 3_${ik}$ + 5_${ik}$*n
                 end if
              end if
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not. lquery ) then
                 info = -8_${ik}$
              else if( liwork<liwmin .and. .not. lquery ) then
                 info = -10_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEDC', -info )
              return
           else if (lquery) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz/=0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! if the following conditional clause is removed, then the routine
           ! will use the divide and conquer routine to compute only the
           ! eigenvalues, which requires (3n + 3n**2) real workspace and
           ! (2 + 5n + 2n lg(n)) integer workspace.
           ! since on many architectures stdlib${ii}$_dsterf is much faster than any other
           ! algorithm for finding eigenvalues only, it is used here
           ! as the default. if the conditional clause is removed, then
           ! information on the size of workspace needs to be changed.
           ! if compz = 'n', use stdlib_dsterf to compute the eigenvalues.
           if( icompz==0_${ik}$ ) then
              call stdlib${ii}$_dsterf( n, d, e, info )
              go to 50
           end if
           ! if n is smaller than the minimum divide size (smlsiz+1), then
           ! solve the problem with another solver.
           if( n<=smlsiz ) then
              call stdlib${ii}$_dsteqr( compz, n, d, e, z, ldz, work, info )
           else
              ! if compz = 'v', the z matrix must be stored elsewhere for later
              ! use.
              if( icompz==1_${ik}$ ) then
                 storez = 1_${ik}$ + n*n
              else
                 storez = 1_${ik}$
              end if
              if( icompz==2_${ik}$ ) then
                 call stdlib${ii}$_dlaset( 'FULL', n, n, zero, one, z, ldz )
              end if
              ! scale.
              orgnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
              if( orgnrm==zero )go to 50
              eps = stdlib${ii}$_dlamch( 'EPSILON' )
              start = 1_${ik}$
              ! while ( start <= n )
              10 continue
              if( start<=n ) then
                 ! let finish be the position of the next subdiagonal entry
                 ! such that e( finish ) <= tiny or finish = n if no such
                 ! subdiagonal exists.  the matrix identified by the elements
                 ! between start and finish constitutes an independent
                 ! sub-problem.
                 finish = start
                 20 continue
                 if( finish<n ) then
                    tiny = eps*sqrt( abs( d( finish ) ) )*sqrt( abs( d( finish+1 ) ) )
                    if( abs( e( finish ) )>tiny ) then
                       finish = finish + 1_${ik}$
                       go to 20
                    end if
                 end if
                 ! (sub) problem determined.  compute its size and solve it.
                 m = finish - start + 1_${ik}$
                 if( m==1_${ik}$ ) then
                    start = finish + 1_${ik}$
                    go to 10
                 end if
                 if( m>smlsiz ) then
                    ! scale.
                    orgnrm = stdlib${ii}$_dlanst( 'M', m, d( start ), e( start ) )
                    call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m, 1_${ik}$, d( start ), m,info )
                    call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m-1, 1_${ik}$, e( start ),m-1, info )
                              
                    if( icompz==1_${ik}$ ) then
                       strtrw = 1_${ik}$
                    else
                       strtrw = start
                    end if
                    call stdlib${ii}$_dlaed0( icompz, n, m, d( start ), e( start ),z( strtrw, start ), &
                              ldz, work( 1_${ik}$ ), n,work( storez ), iwork, info )
                    if( info/=0_${ik}$ ) then
                       info = ( info / ( m+1 )+start-1 )*( n+1 ) +mod( info, ( m+1 ) ) + start - &
                                 1_${ik}$
                       go to 50
                    end if
                    ! scale back.
                    call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, m, 1_${ik}$, d( start ), m,info )
                 else
                    if( icompz==1_${ik}$ ) then
                       ! since qr won't update a z matrix which is larger than
                       ! the length of d, we must solve the sub-problem in a
                       ! workspace and then multiply back into z.
                       call stdlib${ii}$_dsteqr( 'I', m, d( start ), e( start ), work, m,work( m*m+1 ), &
                                 info )
                       call stdlib${ii}$_dlacpy( 'A', n, m, z( 1_${ik}$, start ), ldz,work( storez ), n )
                                 
                       call stdlib${ii}$_dgemm( 'N', 'N', n, m, m, one,work( storez ), n, work, m, zero,&
                                 z( 1_${ik}$, start ), ldz )
                    else if( icompz==2_${ik}$ ) then
                       call stdlib${ii}$_dsteqr( 'I', m, d( start ), e( start ),z( start, start ), ldz, &
                                 work, info )
                    else
                       call stdlib${ii}$_dsterf( m, d( start ), e( start ), info )
                    end if
                    if( info/=0_${ik}$ ) then
                       info = start*( n+1 ) + finish
                       go to 50
                    end if
                 end if
                 start = finish + 1_${ik}$
                 go to 10
              end if
              ! endwhile
              if( icompz==0_${ik}$ ) then
                ! use quick sort
                call stdlib${ii}$_dlasrt( 'I', n, d, info )
              else
                ! use selection sort to minimize swaps of eigenvectors
                do ii = 2, n
                   i = ii - 1_${ik}$
                   k = i
                   p = d( i )
                   do j = ii, n
                      if( d( j )<p ) then
                         k = j
                         p = d( j )
                      end if
                   end do
                   if( k/=i ) then
                      d( k ) = d( i )
                      d( i ) = p
                      call stdlib${ii}$_dswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                   end if
                end do
              end if
           end if
           50 continue
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_dstedc

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stedc( compz, n, d, e, z, ldz, work, lwork, iwork,liwork, info )
     !! DSTEDC: computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the divide and conquer method.
     !! The eigenvectors of a full or band real symmetric matrix can also be
     !! found if DSYTRD or DSPTRD or DSBTRD has been used to reduce this
     !! matrix to tridiagonal form.
     !! 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.  See DLAED3 for details.
               
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(${rk}$), intent(inout) :: d(*), e(*), z(ldz,*)
           real(${rk}$), intent(out) :: work(*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery
           integer(${ik}$) :: finish, i, icompz, ii, j, k, lgn, liwmin, lwmin, m, smlsiz, start, &
                     storez, strtrw
           real(${rk}$) :: eps, orgnrm, p, tiny
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           lquery = ( lwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or.( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$, n ) ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              ! compute the workspace requirements
              smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'DSTEDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ )
              if( n<=1_${ik}$ .or. icompz==0_${ik}$ ) then
                 liwmin = 1_${ik}$
                 lwmin = 1_${ik}$
              else if( n<=smlsiz ) then
                 liwmin = 1_${ik}$
                 lwmin = 2_${ik}$*( n - 1_${ik}$ )
              else
                 lgn = int( log( real( n,KIND=${rk}$) )/log( two ),KIND=${ik}$)
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( icompz==1_${ik}$ ) then
                    lwmin = 1_${ik}$ + 3_${ik}$*n + 2_${ik}$*n*lgn + 4_${ik}$*n**2_${ik}$
                    liwmin = 6_${ik}$ + 6_${ik}$*n + 5_${ik}$*n*lgn
                 else if( icompz==2_${ik}$ ) then
                    lwmin = 1_${ik}$ + 4_${ik}$*n + n**2_${ik}$
                    liwmin = 3_${ik}$ + 5_${ik}$*n
                 end if
              end if
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not. lquery ) then
                 info = -8_${ik}$
              else if( liwork<liwmin .and. .not. lquery ) then
                 info = -10_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEDC', -info )
              return
           else if (lquery) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz/=0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! if the following conditional clause is removed, then the routine
           ! will use the divide and conquer routine to compute only the
           ! eigenvalues, which requires (3n + 3n**2) real workspace and
           ! (2 + 5n + 2n lg(n)) integer workspace.
           ! since on many architectures stdlib${ii}$_${ri}$sterf is much faster than any other
           ! algorithm for finding eigenvalues only, it is used here
           ! as the default. if the conditional clause is removed, then
           ! information on the size of workspace needs to be changed.
           ! if compz = 'n', use stdlib_${ri}$sterf to compute the eigenvalues.
           if( icompz==0_${ik}$ ) then
              call stdlib${ii}$_${ri}$sterf( n, d, e, info )
              go to 50
           end if
           ! if n is smaller than the minimum divide size (smlsiz+1), then
           ! solve the problem with another solver.
           if( n<=smlsiz ) then
              call stdlib${ii}$_${ri}$steqr( compz, n, d, e, z, ldz, work, info )
           else
              ! if compz = 'v', the z matrix must be stored elsewhere for later
              ! use.
              if( icompz==1_${ik}$ ) then
                 storez = 1_${ik}$ + n*n
              else
                 storez = 1_${ik}$
              end if
              if( icompz==2_${ik}$ ) then
                 call stdlib${ii}$_${ri}$laset( 'FULL', n, n, zero, one, z, ldz )
              end if
              ! scale.
              orgnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e )
              if( orgnrm==zero )go to 50
              eps = stdlib${ii}$_${ri}$lamch( 'EPSILON' )
              start = 1_${ik}$
              ! while ( start <= n )
              10 continue
              if( start<=n ) then
                 ! let finish be the position of the next subdiagonal entry
                 ! such that e( finish ) <= tiny or finish = n if no such
                 ! subdiagonal exists.  the matrix identified by the elements
                 ! between start and finish constitutes an independent
                 ! sub-problem.
                 finish = start
                 20 continue
                 if( finish<n ) then
                    tiny = eps*sqrt( abs( d( finish ) ) )*sqrt( abs( d( finish+1 ) ) )
                    if( abs( e( finish ) )>tiny ) then
                       finish = finish + 1_${ik}$
                       go to 20
                    end if
                 end if
                 ! (sub) problem determined.  compute its size and solve it.
                 m = finish - start + 1_${ik}$
                 if( m==1_${ik}$ ) then
                    start = finish + 1_${ik}$
                    go to 10
                 end if
                 if( m>smlsiz ) then
                    ! scale.
                    orgnrm = stdlib${ii}$_${ri}$lanst( 'M', m, d( start ), e( start ) )
                    call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m, 1_${ik}$, d( start ), m,info )
                    call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m-1, 1_${ik}$, e( start ),m-1, info )
                              
                    if( icompz==1_${ik}$ ) then
                       strtrw = 1_${ik}$
                    else
                       strtrw = start
                    end if
                    call stdlib${ii}$_${ri}$laed0( icompz, n, m, d( start ), e( start ),z( strtrw, start ), &
                              ldz, work( 1_${ik}$ ), n,work( storez ), iwork, info )
                    if( info/=0_${ik}$ ) then
                       info = ( info / ( m+1 )+start-1 )*( n+1 ) +mod( info, ( m+1 ) ) + start - &
                                 1_${ik}$
                       go to 50
                    end if
                    ! scale back.
                    call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, m, 1_${ik}$, d( start ), m,info )
                 else
                    if( icompz==1_${ik}$ ) then
                       ! since qr won't update a z matrix which is larger than
                       ! the length of d, we must solve the sub-problem in a
                       ! workspace and then multiply back into z.
                       call stdlib${ii}$_${ri}$steqr( 'I', m, d( start ), e( start ), work, m,work( m*m+1 ), &
                                 info )
                       call stdlib${ii}$_${ri}$lacpy( 'A', n, m, z( 1_${ik}$, start ), ldz,work( storez ), n )
                                 
                       call stdlib${ii}$_${ri}$gemm( 'N', 'N', n, m, m, one,work( storez ), n, work, m, zero,&
                                 z( 1_${ik}$, start ), ldz )
                    else if( icompz==2_${ik}$ ) then
                       call stdlib${ii}$_${ri}$steqr( 'I', m, d( start ), e( start ),z( start, start ), ldz, &
                                 work, info )
                    else
                       call stdlib${ii}$_${ri}$sterf( m, d( start ), e( start ), info )
                    end if
                    if( info/=0_${ik}$ ) then
                       info = start*( n+1 ) + finish
                       go to 50
                    end if
                 end if
                 start = finish + 1_${ik}$
                 go to 10
              end if
              ! endwhile
              if( icompz==0_${ik}$ ) then
                ! use quick sort
                call stdlib${ii}$_${ri}$lasrt( 'I', n, d, info )
              else
                ! use selection sort to minimize swaps of eigenvectors
                do ii = 2, n
                   i = ii - 1_${ik}$
                   k = i
                   p = d( i )
                   do j = ii, n
                      if( d( j )<p ) then
                         k = j
                         p = d( j )
                      end if
                   end do
                   if( k/=i ) then
                      d( k ) = d( i )
                      d( i ) = p
                      call stdlib${ii}$_${ri}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                   end if
                end do
              end if
           end if
           50 continue
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_${ri}$stedc

#:endif
#:endfor

     pure module subroutine stdlib${ii}$_cstedc( compz, n, d, e, z, ldz, work, lwork, rwork,lrwork, iwork, &
     !! CSTEDC computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the divide and conquer method.
     !! The eigenvectors of a full or band complex Hermitian matrix can also
     !! be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this
     !! matrix to tridiagonal form.
     !! 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.  See SLAED3 for details.
               liwork, 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lrwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: rwork(*)
           complex(sp), intent(out) :: work(*)
           complex(sp), intent(inout) :: z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery
           integer(${ik}$) :: finish, i, icompz, ii, j, k, lgn, liwmin, ll, lrwmin, lwmin, m, smlsiz,&
                      start
           real(sp) :: eps, orgnrm, p, tiny
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           lquery = ( lwork==-1_${ik}$ .or. lrwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or.( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$, n ) ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              ! compute the workspace requirements
              smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'CSTEDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ )
              if( n<=1_${ik}$ .or. icompz==0_${ik}$ ) then
                 lwmin = 1_${ik}$
                 liwmin = 1_${ik}$
                 lrwmin = 1_${ik}$
              else if( n<=smlsiz ) then
                 lwmin = 1_${ik}$
                 liwmin = 1_${ik}$
                 lrwmin = 2_${ik}$*( n - 1_${ik}$ )
              else if( icompz==1_${ik}$ ) then
                 lgn = int( log( real( n,KIND=sp) ) / log( two ),KIND=${ik}$)
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 lwmin = n*n
                 lrwmin = 1_${ik}$ + 3_${ik}$*n + 2_${ik}$*n*lgn + 4_${ik}$*n**2_${ik}$
                 liwmin = 6_${ik}$ + 6_${ik}$*n + 5_${ik}$*n*lgn
              else if( icompz==2_${ik}$ ) then
                 lwmin = 1_${ik}$
                 lrwmin = 1_${ik}$ + 4_${ik}$*n + 2_${ik}$*n**2_${ik}$
                 liwmin = 3_${ik}$ + 5_${ik}$*n
              end if
              work( 1_${ik}$ ) = lwmin
              rwork( 1_${ik}$ ) = lrwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -8_${ik}$
              else if( lrwork<lrwmin .and. .not.lquery ) then
                 info = -10_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -12_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'CSTEDC', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz/=0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! if the following conditional clause is removed, then the routine
           ! will use the divide and conquer routine to compute only the
           ! eigenvalues, which requires (3n + 3n**2) real workspace and
           ! (2 + 5n + 2n lg(n)) integer workspace.
           ! since on many architectures stdlib${ii}$_ssterf is much faster than any other
           ! algorithm for finding eigenvalues only, it is used here
           ! as the default. if the conditional clause is removed, then
           ! information on the size of workspace needs to be changed.
           ! if compz = 'n', use stdlib_ssterf to compute the eigenvalues.
           if( icompz==0_${ik}$ ) then
              call stdlib${ii}$_ssterf( n, d, e, info )
              go to 70
           end if
           ! if n is smaller than the minimum divide size (smlsiz+1), then
           ! solve the problem with another solver.
           if( n<=smlsiz ) then
              call stdlib${ii}$_csteqr( compz, n, d, e, z, ldz, rwork, info )
           else
              ! if compz = 'i', we simply call stdlib${ii}$_sstedc instead.
              if( icompz==2_${ik}$ ) then
                 call stdlib${ii}$_slaset( 'FULL', n, n, zero, one, rwork, n )
                 ll = n*n + 1_${ik}$
                 call stdlib${ii}$_sstedc( 'I', n, d, e, rwork, n,rwork( ll ), lrwork-ll+1, iwork, &
                           liwork, info )
                 do j = 1, n
                    do i = 1, n
                       z( i, j ) = rwork( ( j-1 )*n+i )
                    end do
                 end do
                 go to 70
              end if
              ! from now on, only option left to be handled is compz = 'v',
              ! i.e. icompz = 1.
              ! scale.
              orgnrm = stdlib${ii}$_slanst( 'M', n, d, e )
              if( orgnrm==zero )go to 70
              eps = stdlib${ii}$_slamch( 'EPSILON' )
              start = 1_${ik}$
              ! while ( start <= n )
              30 continue
              if( start<=n ) then
                 ! let finish be the position of the next subdiagonal entry
                 ! such that e( finish ) <= tiny or finish = n if no such
                 ! subdiagonal exists.  the matrix identified by the elements
                 ! between start and finish constitutes an independent
                 ! sub-problem.
                 finish = start
                 40 continue
                 if( finish<n ) then
                    tiny = eps*sqrt( abs( d( finish ) ) )*sqrt( abs( d( finish+1 ) ) )
                    if( abs( e( finish ) )>tiny ) then
                       finish = finish + 1_${ik}$
                       go to 40
                    end if
                 end if
                 ! (sub) problem determined.  compute its size and solve it.
                 m = finish - start + 1_${ik}$
                 if( m>smlsiz ) then
                    ! scale.
                    orgnrm = stdlib${ii}$_slanst( 'M', m, d( start ), e( start ) )
                    call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m, 1_${ik}$, d( start ), m,info )
                    call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m-1, 1_${ik}$, e( start ),m-1, info )
                              
                    call stdlib${ii}$_claed0( n, m, d( start ), e( start ), z( 1_${ik}$, start ),ldz, work, n, &
                              rwork, iwork, info )
                    if( info>0_${ik}$ ) then
                       info = ( info / ( m+1 )+start-1 )*( n+1 ) +mod( info, ( m+1 ) ) + start - &
                                 1_${ik}$
                       go to 70
                    end if
                    ! scale back.
                    call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, m, 1_${ik}$, d( start ), m,info )
                 else
                    call stdlib${ii}$_ssteqr( 'I', m, d( start ), e( start ), rwork, m,rwork( m*m+1 ), &
                              info )
                    call stdlib${ii}$_clacrm( n, m, z( 1_${ik}$, start ), ldz, rwork, m, work, n,rwork( m*m+1 )&
                               )
                    call stdlib${ii}$_clacpy( 'A', n, m, work, n, z( 1_${ik}$, start ), ldz )
                    if( info>0_${ik}$ ) then
                       info = start*( n+1 ) + finish
                       go to 70
                    end if
                 end if
                 start = finish + 1_${ik}$
                 go to 30
              end if
              ! endwhile
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                i = ii - 1_${ik}$
                k = i
                p = d( i )
                do j = ii, n
                   if( d( j )<p ) then
                      k = j
                      p = d( j )
                   end if
                end do
                if( k/=i ) then
                   d( k ) = d( i )
                   d( i ) = p
                   call stdlib${ii}$_cswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                end if
              end do
           end if
           70 continue
           work( 1_${ik}$ ) = lwmin
           rwork( 1_${ik}$ ) = lrwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_cstedc

     pure module subroutine stdlib${ii}$_zstedc( compz, n, d, e, z, ldz, work, lwork, rwork,lrwork, iwork, &
     !! ZSTEDC computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the divide and conquer method.
     !! The eigenvectors of a full or band complex Hermitian matrix can also
     !! be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this
     !! matrix to tridiagonal form.
     !! 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.  See DLAED3 for details.
               liwork, 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lrwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: rwork(*)
           complex(dp), intent(out) :: work(*)
           complex(dp), intent(inout) :: z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery
           integer(${ik}$) :: finish, i, icompz, ii, j, k, lgn, liwmin, ll, lrwmin, lwmin, m, smlsiz,&
                      start
           real(dp) :: eps, orgnrm, p, tiny
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           lquery = ( lwork==-1_${ik}$ .or. lrwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or.( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$, n ) ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              ! compute the workspace requirements
              smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'ZSTEDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ )
              if( n<=1_${ik}$ .or. icompz==0_${ik}$ ) then
                 lwmin = 1_${ik}$
                 liwmin = 1_${ik}$
                 lrwmin = 1_${ik}$
              else if( n<=smlsiz ) then
                 lwmin = 1_${ik}$
                 liwmin = 1_${ik}$
                 lrwmin = 2_${ik}$*( n - 1_${ik}$ )
              else if( icompz==1_${ik}$ ) then
                 lgn = int( log( real( n,KIND=dp) ) / log( two ),KIND=${ik}$)
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 lwmin = n*n
                 lrwmin = 1_${ik}$ + 3_${ik}$*n + 2_${ik}$*n*lgn + 4_${ik}$*n**2_${ik}$
                 liwmin = 6_${ik}$ + 6_${ik}$*n + 5_${ik}$*n*lgn
              else if( icompz==2_${ik}$ ) then
                 lwmin = 1_${ik}$
                 lrwmin = 1_${ik}$ + 4_${ik}$*n + 2_${ik}$*n**2_${ik}$
                 liwmin = 3_${ik}$ + 5_${ik}$*n
              end if
              work( 1_${ik}$ ) = lwmin
              rwork( 1_${ik}$ ) = lrwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -8_${ik}$
              else if( lrwork<lrwmin .and. .not.lquery ) then
                 info = -10_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -12_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEDC', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz/=0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! if the following conditional clause is removed, then the routine
           ! will use the divide and conquer routine to compute only the
           ! eigenvalues, which requires (3n + 3n**2) real workspace and
           ! (2 + 5n + 2n lg(n)) integer workspace.
           ! since on many architectures stdlib${ii}$_dsterf is much faster than any other
           ! algorithm for finding eigenvalues only, it is used here
           ! as the default. if the conditional clause is removed, then
           ! information on the size of workspace needs to be changed.
           ! if compz = 'n', use stdlib_dsterf to compute the eigenvalues.
           if( icompz==0_${ik}$ ) then
              call stdlib${ii}$_dsterf( n, d, e, info )
              go to 70
           end if
           ! if n is smaller than the minimum divide size (smlsiz+1), then
           ! solve the problem with another solver.
           if( n<=smlsiz ) then
              call stdlib${ii}$_zsteqr( compz, n, d, e, z, ldz, rwork, info )
           else
              ! if compz = 'i', we simply call stdlib${ii}$_dstedc instead.
              if( icompz==2_${ik}$ ) then
                 call stdlib${ii}$_dlaset( 'FULL', n, n, zero, one, rwork, n )
                 ll = n*n + 1_${ik}$
                 call stdlib${ii}$_dstedc( 'I', n, d, e, rwork, n,rwork( ll ), lrwork-ll+1, iwork, &
                           liwork, info )
                 do j = 1, n
                    do i = 1, n
                       z( i, j ) = rwork( ( j-1 )*n+i )
                    end do
                 end do
                 go to 70
              end if
              ! from now on, only option left to be handled is compz = 'v',
              ! i.e. icompz = 1.
              ! scale.
              orgnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
              if( orgnrm==zero )go to 70
              eps = stdlib${ii}$_dlamch( 'EPSILON' )
              start = 1_${ik}$
              ! while ( start <= n )
              30 continue
              if( start<=n ) then
                 ! let finish be the position of the next subdiagonal entry
                 ! such that e( finish ) <= tiny or finish = n if no such
                 ! subdiagonal exists.  the matrix identified by the elements
                 ! between start and finish constitutes an independent
                 ! sub-problem.
                 finish = start
                 40 continue
                 if( finish<n ) then
                    tiny = eps*sqrt( abs( d( finish ) ) )*sqrt( abs( d( finish+1 ) ) )
                    if( abs( e( finish ) )>tiny ) then
                       finish = finish + 1_${ik}$
                       go to 40
                    end if
                 end if
                 ! (sub) problem determined.  compute its size and solve it.
                 m = finish - start + 1_${ik}$
                 if( m>smlsiz ) then
                    ! scale.
                    orgnrm = stdlib${ii}$_dlanst( 'M', m, d( start ), e( start ) )
                    call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m, 1_${ik}$, d( start ), m,info )
                    call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m-1, 1_${ik}$, e( start ),m-1, info )
                              
                    call stdlib${ii}$_zlaed0( n, m, d( start ), e( start ), z( 1_${ik}$, start ),ldz, work, n, &
                              rwork, iwork, info )
                    if( info>0_${ik}$ ) then
                       info = ( info / ( m+1 )+start-1 )*( n+1 ) +mod( info, ( m+1 ) ) + start - &
                                 1_${ik}$
                       go to 70
                    end if
                    ! scale back.
                    call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, m, 1_${ik}$, d( start ), m,info )
                 else
                    call stdlib${ii}$_dsteqr( 'I', m, d( start ), e( start ), rwork, m,rwork( m*m+1 ), &
                              info )
                    call stdlib${ii}$_zlacrm( n, m, z( 1_${ik}$, start ), ldz, rwork, m, work, n,rwork( m*m+1 )&
                               )
                    call stdlib${ii}$_zlacpy( 'A', n, m, work, n, z( 1_${ik}$, start ), ldz )
                    if( info>0_${ik}$ ) then
                       info = start*( n+1 ) + finish
                       go to 70
                    end if
                 end if
                 start = finish + 1_${ik}$
                 go to 30
              end if
              ! endwhile
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                i = ii - 1_${ik}$
                k = i
                p = d( i )
                do j = ii, n
                   if( d( j )<p ) then
                      k = j
                      p = d( j )
                   end if
                end do
                if( k/=i ) then
                   d( k ) = d( i )
                   d( i ) = p
                   call stdlib${ii}$_zswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                end if
              end do
           end if
           70 continue
           work( 1_${ik}$ ) = lwmin
           rwork( 1_${ik}$ ) = lrwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_zstedc

#:for ck,ct,ci in CMPLX_KINDS_TYPES
#:if not ck in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ci}$stedc( compz, n, d, e, z, ldz, work, lwork, rwork,lrwork, iwork, &
     !! ZSTEDC: computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the divide and conquer method.
     !! The eigenvectors of a full or band complex Hermitian matrix can also
     !! be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this
     !! matrix to tridiagonal form.
     !! 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.  See DLAED3 for details.
               liwork, 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, liwork, lrwork, lwork, n
           ! Array Arguments 
           integer(${ik}$), intent(out) :: iwork(*)
           real(${ck}$), intent(inout) :: d(*), e(*)
           real(${ck}$), intent(out) :: rwork(*)
           complex(${ck}$), intent(out) :: work(*)
           complex(${ck}$), intent(inout) :: z(ldz,*)
        ! =====================================================================
           
           ! Local Scalars 
           logical(lk) :: lquery
           integer(${ik}$) :: finish, i, icompz, ii, j, k, lgn, liwmin, ll, lrwmin, lwmin, m, smlsiz,&
                      start
           real(${ck}$) :: eps, orgnrm, p, tiny
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           lquery = ( lwork==-1_${ik}$ .or. lrwork==-1_${ik}$ .or. liwork==-1_${ik}$ )
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or.( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$, n ) ) ) then
              info = -6_${ik}$
           end if
           if( info==0_${ik}$ ) then
              ! compute the workspace requirements
              smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'ZSTEDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ )
              if( n<=1_${ik}$ .or. icompz==0_${ik}$ ) then
                 lwmin = 1_${ik}$
                 liwmin = 1_${ik}$
                 lrwmin = 1_${ik}$
              else if( n<=smlsiz ) then
                 lwmin = 1_${ik}$
                 liwmin = 1_${ik}$
                 lrwmin = 2_${ik}$*( n - 1_${ik}$ )
              else if( icompz==1_${ik}$ ) then
                 lgn = int( log( real( n,KIND=${ck}$) ) / log( two ),KIND=${ik}$)
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 if( 2_${ik}$**lgn<n )lgn = lgn + 1_${ik}$
                 lwmin = n*n
                 lrwmin = 1_${ik}$ + 3_${ik}$*n + 2_${ik}$*n*lgn + 4_${ik}$*n**2_${ik}$
                 liwmin = 6_${ik}$ + 6_${ik}$*n + 5_${ik}$*n*lgn
              else if( icompz==2_${ik}$ ) then
                 lwmin = 1_${ik}$
                 lrwmin = 1_${ik}$ + 4_${ik}$*n + 2_${ik}$*n**2_${ik}$
                 liwmin = 3_${ik}$ + 5_${ik}$*n
              end if
              work( 1_${ik}$ ) = lwmin
              rwork( 1_${ik}$ ) = lrwmin
              iwork( 1_${ik}$ ) = liwmin
              if( lwork<lwmin .and. .not.lquery ) then
                 info = -8_${ik}$
              else if( lrwork<lrwmin .and. .not.lquery ) then
                 info = -10_${ik}$
              else if( liwork<liwmin .and. .not.lquery ) then
                 info = -12_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEDC', -info )
              return
           else if( lquery ) then
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz/=0_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! if the following conditional clause is removed, then the routine
           ! will use the divide and conquer routine to compute only the
           ! eigenvalues, which requires (3n + 3n**2) real workspace and
           ! (2 + 5n + 2n lg(n)) integer workspace.
           ! since on many architectures stdlib${ii}$_${c2ri(ci)}$sterf is much faster than any other
           ! algorithm for finding eigenvalues only, it is used here
           ! as the default. if the conditional clause is removed, then
           ! information on the size of workspace needs to be changed.
           ! if compz = 'n', use stdlib_${c2ri(ci)}$sterf to compute the eigenvalues.
           if( icompz==0_${ik}$ ) then
              call stdlib${ii}$_${c2ri(ci)}$sterf( n, d, e, info )
              go to 70
           end if
           ! if n is smaller than the minimum divide size (smlsiz+1), then
           ! solve the problem with another solver.
           if( n<=smlsiz ) then
              call stdlib${ii}$_${ci}$steqr( compz, n, d, e, z, ldz, rwork, info )
           else
              ! if compz = 'i', we simply call stdlib${ii}$_${c2ri(ci)}$stedc instead.
              if( icompz==2_${ik}$ ) then
                 call stdlib${ii}$_${c2ri(ci)}$laset( 'FULL', n, n, zero, one, rwork, n )
                 ll = n*n + 1_${ik}$
                 call stdlib${ii}$_${c2ri(ci)}$stedc( 'I', n, d, e, rwork, n,rwork( ll ), lrwork-ll+1, iwork, &
                           liwork, info )
                 do j = 1, n
                    do i = 1, n
                       z( i, j ) = rwork( ( j-1 )*n+i )
                    end do
                 end do
                 go to 70
              end if
              ! from now on, only option left to be handled is compz = 'v',
              ! i.e. icompz = 1.
              ! scale.
              orgnrm = stdlib${ii}$_${c2ri(ci)}$lanst( 'M', n, d, e )
              if( orgnrm==zero )go to 70
              eps = stdlib${ii}$_${c2ri(ci)}$lamch( 'EPSILON' )
              start = 1_${ik}$
              ! while ( start <= n )
              30 continue
              if( start<=n ) then
                 ! let finish be the position of the next subdiagonal entry
                 ! such that e( finish ) <= tiny or finish = n if no such
                 ! subdiagonal exists.  the matrix identified by the elements
                 ! between start and finish constitutes an independent
                 ! sub-problem.
                 finish = start
                 40 continue
                 if( finish<n ) then
                    tiny = eps*sqrt( abs( d( finish ) ) )*sqrt( abs( d( finish+1 ) ) )
                    if( abs( e( finish ) )>tiny ) then
                       finish = finish + 1_${ik}$
                       go to 40
                    end if
                 end if
                 ! (sub) problem determined.  compute its size and solve it.
                 m = finish - start + 1_${ik}$
                 if( m>smlsiz ) then
                    ! scale.
                    orgnrm = stdlib${ii}$_${c2ri(ci)}$lanst( 'M', m, d( start ), e( start ) )
                    call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m, 1_${ik}$, d( start ), m,info )
                    call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, m-1, 1_${ik}$, e( start ),m-1, info )
                              
                    call stdlib${ii}$_${ci}$laed0( n, m, d( start ), e( start ), z( 1_${ik}$, start ),ldz, work, n, &
                              rwork, iwork, info )
                    if( info>0_${ik}$ ) then
                       info = ( info / ( m+1 )+start-1 )*( n+1 ) +mod( info, ( m+1 ) ) + start - &
                                 1_${ik}$
                       go to 70
                    end if
                    ! scale back.
                    call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, m, 1_${ik}$, d( start ), m,info )
                 else
                    call stdlib${ii}$_${c2ri(ci)}$steqr( 'I', m, d( start ), e( start ), rwork, m,rwork( m*m+1 ), &
                              info )
                    call stdlib${ii}$_${ci}$lacrm( n, m, z( 1_${ik}$, start ), ldz, rwork, m, work, n,rwork( m*m+1 )&
                               )
                    call stdlib${ii}$_${ci}$lacpy( 'A', n, m, work, n, z( 1_${ik}$, start ), ldz )
                    if( info>0_${ik}$ ) then
                       info = start*( n+1 ) + finish
                       go to 70
                    end if
                 end if
                 start = finish + 1_${ik}$
                 go to 30
              end if
              ! endwhile
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                i = ii - 1_${ik}$
                k = i
                p = d( i )
                do j = ii, n
                   if( d( j )<p ) then
                      k = j
                      p = d( j )
                   end if
                end do
                if( k/=i ) then
                   d( k ) = d( i )
                   d( i ) = p
                   call stdlib${ii}$_${ci}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                end if
              end do
           end if
           70 continue
           work( 1_${ik}$ ) = lwmin
           rwork( 1_${ik}$ ) = lrwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_${ci}$stedc

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstegr( jobz, range, n, d, e, vl, vu, il, iu,abstol, m, w, z, ldz, &
     !! SSTEGR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! SSTEGR is a compatibility wrapper around the improved SSTEMR routine.
     !! See SSTEMR for further details.
     !! One important change is that the ABSTOL parameter no longer provides any
     !! benefit and hence is no longer used.
     !! Note : SSTEGR and SSTEMR work only on machines which follow
     !! IEEE-754 floating-point standard in their handling of infinities and
     !! NaNs.  Normal execution may create these exceptiona values and hence
     !! may abort due to a floating point exception in environments which
     !! do not conform to the IEEE-754 standard.
               isuppz, work, lwork, iwork,liwork, 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(sp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*)
           real(sp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Local Scalars 
           logical(lk) :: tryrac
           ! Executable Statements 
           info = 0_${ik}$
           tryrac = .false.
           call stdlib${ii}$_sstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, n, isuppz, &
                     tryrac, work, lwork,iwork, liwork, info )
     end subroutine stdlib${ii}$_sstegr

     pure module subroutine stdlib${ii}$_dstegr( jobz, range, n, d, e, vl, vu, il, iu,abstol, m, w, z, ldz, &
     !! DSTEGR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! DSTEGR is a compatibility wrapper around the improved DSTEMR routine.
     !! See DSTEMR for further details.
     !! One important change is that the ABSTOL parameter no longer provides any
     !! benefit and hence is no longer used.
     !! Note : DSTEGR and DSTEMR work only on machines which follow
     !! IEEE-754 floating-point standard in their handling of infinities and
     !! NaNs.  Normal execution may create these exceptiona values and hence
     !! may abort due to a floating point exception in environments which
     !! do not conform to the IEEE-754 standard.
               isuppz, work, lwork, iwork,liwork, 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(dp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*)
           real(dp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Local Scalars 
           logical(lk) :: tryrac
           ! Executable Statements 
           info = 0_${ik}$
           tryrac = .false.
           call stdlib${ii}$_dstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, n, isuppz, &
                     tryrac, work, lwork,iwork, liwork, info )
     end subroutine stdlib${ii}$_dstegr

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stegr( jobz, range, n, d, e, vl, vu, il, iu,abstol, m, w, z, ldz, &
     !! DSTEGR: computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! DSTEGR is a compatibility wrapper around the improved DSTEMR routine.
     !! See DSTEMR for further details.
     !! One important change is that the ABSTOL parameter no longer provides any
     !! benefit and hence is no longer used.
     !! Note : DSTEGR and DSTEMR work only on machines which follow
     !! IEEE-754 floating-point standard in their handling of infinities and
     !! NaNs.  Normal execution may create these exceptiona values and hence
     !! may abort due to a floating point exception in environments which
     !! do not conform to the IEEE-754 standard.
               isuppz, work, lwork, iwork,liwork, 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(${rk}$), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(${rk}$), intent(inout) :: d(*), e(*)
           real(${rk}$), intent(out) :: w(*), work(*)
           real(${rk}$), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Local Scalars 
           logical(lk) :: tryrac
           ! Executable Statements 
           info = 0_${ik}$
           tryrac = .false.
           call stdlib${ii}$_${ri}$stemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, n, isuppz, &
                     tryrac, work, lwork,iwork, liwork, info )
     end subroutine stdlib${ii}$_${ri}$stegr

#:endif
#:endfor

     pure module subroutine stdlib${ii}$_cstegr( jobz, range, n, d, e, vl, vu, il, iu,abstol, m, w, z, ldz, &
     !! CSTEGR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! CSTEGR is a compatibility wrapper around the improved CSTEMR routine.
     !! See SSTEMR for further details.
     !! One important change is that the ABSTOL parameter no longer provides any
     !! benefit and hence is no longer used.
     !! Note : CSTEGR and CSTEMR work only on machines which follow
     !! IEEE-754 floating-point standard in their handling of infinities and
     !! NaNs.  Normal execution may create these exceptiona values and hence
     !! may abort due to a floating point exception in environments which
     !! do not conform to the IEEE-754 standard.
               isuppz, work, lwork, iwork,liwork, 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(sp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*)
           complex(sp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Local Scalars 
           logical(lk) :: tryrac
           ! Executable Statements 
           info = 0_${ik}$
           tryrac = .false.
           call stdlib${ii}$_cstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, n, isuppz, &
                     tryrac, work, lwork,iwork, liwork, info )
     end subroutine stdlib${ii}$_cstegr

     pure module subroutine stdlib${ii}$_zstegr( jobz, range, n, d, e, vl, vu, il, iu,abstol, m, w, z, ldz, &
     !! ZSTEGR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! ZSTEGR is a compatibility wrapper around the improved ZSTEMR routine.
     !! See ZSTEMR for further details.
     !! One important change is that the ABSTOL parameter no longer provides any
     !! benefit and hence is no longer used.
     !! Note : ZSTEGR and ZSTEMR work only on machines which follow
     !! IEEE-754 floating-point standard in their handling of infinities and
     !! NaNs.  Normal execution may create these exceptiona values and hence
     !! may abort due to a floating point exception in environments which
     !! do not conform to the IEEE-754 standard.
               isuppz, work, lwork, iwork,liwork, 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(dp), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*)
           complex(dp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Local Scalars 
           logical(lk) :: tryrac
           ! Executable Statements 
           info = 0_${ik}$
           tryrac = .false.
           call stdlib${ii}$_zstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, n, isuppz, &
                     tryrac, work, lwork,iwork, liwork, info )
     end subroutine stdlib${ii}$_zstegr

#:for ck,ct,ci in CMPLX_KINDS_TYPES
#:if not ck in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ci}$stegr( jobz, range, n, d, e, vl, vu, il, iu,abstol, m, w, z, ldz, &
     !! ZSTEGR: computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! ZSTEGR is a compatibility wrapper around the improved ZSTEMR routine.
     !! See ZSTEMR for further details.
     !! One important change is that the ABSTOL parameter no longer provides any
     !! benefit and hence is no longer used.
     !! Note : ZSTEGR and ZSTEMR work only on machines which follow
     !! IEEE-754 floating-point standard in their handling of infinities and
     !! NaNs.  Normal execution may create these exceptiona values and hence
     !! may abort due to a floating point exception in environments which
     !! do not conform to the IEEE-754 standard.
               isuppz, work, lwork, iwork,liwork, 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 
           character, intent(in) :: jobz, range
           integer(${ik}$), intent(in) :: il, iu, ldz, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(${ck}$), intent(in) :: abstol, vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(${ck}$), intent(inout) :: d(*), e(*)
           real(${ck}$), intent(out) :: w(*), work(*)
           complex(${ck}$), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Local Scalars 
           logical(lk) :: tryrac
           ! Executable Statements 
           info = 0_${ik}$
           tryrac = .false.
           call stdlib${ii}$_${ci}$stemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, n, isuppz, &
                     tryrac, work, lwork,iwork, liwork, info )
     end subroutine stdlib${ii}$_${ci}$stegr

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstein( n, d, e, m, w, iblock, isplit, z, ldz, work,iwork, ifail, &
     !! SSTEIN computes the eigenvectors of a real symmetric tridiagonal
     !! matrix T corresponding to specified eigenvalues, using inverse
     !! iteration.
     !! The maximum number of iterations allowed for each eigenvector is
     !! specified by an internal parameter MAXITS (currently set to 5).
               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
           integer(${ik}$), intent(in) :: ldz, m, n
           ! Array Arguments 
           integer(${ik}$), intent(in) :: iblock(*), isplit(*)
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(sp), intent(in) :: d(*), e(*), w(*)
           real(sp), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(sp), parameter :: odm3 = 1.0e-3_sp
           real(sp), parameter :: odm1 = 1.0e-1_sp
           integer(${ik}$), parameter :: maxits = 5_${ik}$
           integer(${ik}$), parameter :: extra = 2_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: b1, blksiz, bn, gpind, i, iinfo, indrv1, indrv2, indrv3, indrv4, &
                     indrv5, its, j, j1, jblk, jmax, nblk, nrmchk
           real(sp) :: ctr, eps, eps1, nrm, onenrm, ortol, pertol, scl, sep, stpcrt, tol, xj, &
                     xjm
           ! Local Arrays 
           integer(${ik}$) :: iseed(4_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           do i = 1, m
              ifail( i ) = 0_${ik}$
           end do
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
           else if( m<0_${ik}$ .or. m>n ) then
              info = -4_${ik}$
           else if( ldz<max( 1_${ik}$, n ) ) then
              info = -9_${ik}$
           else
              do j = 2, m
                 if( iblock( j )<iblock( j-1 ) ) then
                    info = -6_${ik}$
                    go to 30
                 end if
                 if( iblock( j )==iblock( j-1 ) .and. w( j )<w( j-1 ) )then
                    info = -5_${ik}$
                    go to 30
                 end if
              end do
              30 continue
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEIN', -info )
              return
           end if
           ! quick return if possible
           if( n==0_${ik}$ .or. m==0_${ik}$ ) then
              return
           else if( n==1_${ik}$ ) then
              z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           ! initialize seed for random number generator stdlib${ii}$_slarnv.
           do i = 1, 4
              iseed( i ) = 1_${ik}$
           end do
           ! initialize pointers.
           indrv1 = 0_${ik}$
           indrv2 = indrv1 + n
           indrv3 = indrv2 + n
           indrv4 = indrv3 + n
           indrv5 = indrv4 + n
           ! compute eigenvectors of matrix blocks.
           j1 = 1_${ik}$
           loop_160: do nblk = 1, iblock( m )
              ! find starting and ending indices of block nblk.
              if( nblk==1_${ik}$ ) then
                 b1 = 1_${ik}$
              else
                 b1 = isplit( nblk-1 ) + 1_${ik}$
              end if
              bn = isplit( nblk )
              blksiz = bn - b1 + 1_${ik}$
              if( blksiz==1 )go to 60
              gpind = j1
              ! compute reorthogonalization criterion and stopping criterion.
              onenrm = abs( d( b1 ) ) + abs( e( b1 ) )
              onenrm = max( onenrm, abs( d( bn ) )+abs( e( bn-1 ) ) )
              do i = b1 + 1, bn - 1
                 onenrm = max( onenrm, abs( d( i ) )+abs( e( i-1 ) )+abs( e( i ) ) )
              end do
              ortol = odm3*onenrm
              stpcrt = sqrt( odm1 / blksiz )
              ! loop through eigenvalues of block nblk.
              60 continue
              jblk = 0_${ik}$
              loop_150: do j = j1, m
                 if( iblock( j )/=nblk ) then
                    j1 = j
                    cycle loop_160
                 end if
                 jblk = jblk + 1_${ik}$
                 xj = w( j )
                 ! skip all the work if the block size is one.
                 if( blksiz==1_${ik}$ ) then
                    work( indrv1+1 ) = one
                    go to 120
                 end if
                 ! if eigenvalues j and j-1 are too close, add a relatively
                 ! small perturbation.
                 if( jblk>1_${ik}$ ) then
                    eps1 = abs( eps*xj )
                    pertol = ten*eps1
                    sep = xj - xjm
                    if( sep<pertol )xj = xjm + pertol
                 end if
                 its = 0_${ik}$
                 nrmchk = 0_${ik}$
                 ! get random starting vector.
                 call stdlib${ii}$_slarnv( 2_${ik}$, iseed, blksiz, work( indrv1+1 ) )
                 ! copy the matrix t so it won't be destroyed in factorization.
                 call stdlib${ii}$_scopy( blksiz, d( b1 ), 1_${ik}$, work( indrv4+1 ), 1_${ik}$ )
                 call stdlib${ii}$_scopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv2+2 ), 1_${ik}$ )
                 call stdlib${ii}$_scopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv3+1 ), 1_${ik}$ )
                 ! compute lu factors with partial pivoting  ( pt = lu )
                 tol = zero
                 call stdlib${ii}$_slagtf( blksiz, work( indrv4+1 ), xj, work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), tol, work( indrv5+1 ), iwork,iinfo )
                 ! update iteration count.
                 70 continue
                 its = its + 1_${ik}$
                 if( its>maxits )go to 100
                 ! normalize and scale the righthand side vector pb.
                 jmax = stdlib${ii}$_isamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 scl = blksiz*onenrm*max( eps,abs( work( indrv4+blksiz ) ) ) /abs( work( indrv1+&
                           jmax ) )
                 call stdlib${ii}$_sscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 ! solve the system lu = pb.
                 call stdlib${ii}$_slagts( -1_${ik}$, blksiz, work( indrv4+1 ), work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), work( indrv5+1 ), iwork,work( indrv1+1 ), tol, iinfo )
                 ! reorthogonalize by modified gram-schmidt if eigenvalues are
                 ! close enough.
                 if( jblk==1 )go to 90
                 if( abs( xj-xjm )>ortol )gpind = j
                 if( gpind/=j ) then
                    do i = gpind, j - 1
                       ctr = -stdlib${ii}$_sdot( blksiz, work( indrv1+1 ), 1_${ik}$, z( b1, i ),1_${ik}$ )
                       call stdlib${ii}$_saxpy( blksiz, ctr, z( b1, i ), 1_${ik}$,work( indrv1+1 ), 1_${ik}$ )
                    end do
                 end if
                 ! check the infinity norm of the iterate.
                 90 continue
                 jmax = stdlib${ii}$_isamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 nrm = abs( work( indrv1+jmax ) )
                 ! continue for additional iterations after norm reaches
                 ! stopping criterion.
                 if( nrm<stpcrt )go to 70
                 nrmchk = nrmchk + 1_${ik}$
                 if( nrmchk<extra+1 )go to 70
                 go to 110
                 ! if stopping criterion was not satisfied, update info and
                 ! store eigenvector number in array ifail.
                 100 continue
                 info = info + 1_${ik}$
                 ifail( info ) = j
                 ! accept iterate as jth eigenvector.
                 110 continue
                 scl = one / stdlib${ii}$_snrm2( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 jmax = stdlib${ii}$_isamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 if( work( indrv1+jmax )<zero )scl = -scl
                 call stdlib${ii}$_sscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 120 continue
                 do i = 1, n
                    z( i, j ) = zero
                 end do
                 do i = 1, blksiz
                    z( b1+i-1, j ) = work( indrv1+i )
                 end do
                 ! save the shift to check eigenvalue spacing at next
                 ! iteration.
                 xjm = xj
              end do loop_150
           end do loop_160
           return
     end subroutine stdlib${ii}$_sstein

     pure module subroutine stdlib${ii}$_dstein( n, d, e, m, w, iblock, isplit, z, ldz, work,iwork, ifail, &
     !! DSTEIN computes the eigenvectors of a real symmetric tridiagonal
     !! matrix T corresponding to specified eigenvalues, using inverse
     !! iteration.
     !! The maximum number of iterations allowed for each eigenvector is
     !! specified by an internal parameter MAXITS (currently set to 5).
               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
           integer(${ik}$), intent(in) :: ldz, m, n
           ! Array Arguments 
           integer(${ik}$), intent(in) :: iblock(*), isplit(*)
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(dp), intent(in) :: d(*), e(*), w(*)
           real(dp), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(dp), parameter :: odm3 = 1.0e-3_dp
           real(dp), parameter :: odm1 = 1.0e-1_dp
           integer(${ik}$), parameter :: maxits = 5_${ik}$
           integer(${ik}$), parameter :: extra = 2_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: b1, blksiz, bn, gpind, i, iinfo, indrv1, indrv2, indrv3, indrv4, &
                     indrv5, its, j, j1, jblk, jmax, nblk, nrmchk
           real(dp) :: dtpcrt, eps, eps1, nrm, onenrm, ortol, pertol, scl, sep, tol, xj, xjm, &
                     ztr
           ! Local Arrays 
           integer(${ik}$) :: iseed(4_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           do i = 1, m
              ifail( i ) = 0_${ik}$
           end do
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
           else if( m<0_${ik}$ .or. m>n ) then
              info = -4_${ik}$
           else if( ldz<max( 1_${ik}$, n ) ) then
              info = -9_${ik}$
           else
              do j = 2, m
                 if( iblock( j )<iblock( j-1 ) ) then
                    info = -6_${ik}$
                    go to 30
                 end if
                 if( iblock( j )==iblock( j-1 ) .and. w( j )<w( j-1 ) )then
                    info = -5_${ik}$
                    go to 30
                 end if
              end do
              30 continue
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEIN', -info )
              return
           end if
           ! quick return if possible
           if( n==0_${ik}$ .or. m==0_${ik}$ ) then
              return
           else if( n==1_${ik}$ ) then
              z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           ! initialize seed for random number generator stdlib${ii}$_dlarnv.
           do i = 1, 4
              iseed( i ) = 1_${ik}$
           end do
           ! initialize pointers.
           indrv1 = 0_${ik}$
           indrv2 = indrv1 + n
           indrv3 = indrv2 + n
           indrv4 = indrv3 + n
           indrv5 = indrv4 + n
           ! compute eigenvectors of matrix blocks.
           j1 = 1_${ik}$
           loop_160: do nblk = 1, iblock( m )
              ! find starting and ending indices of block nblk.
              if( nblk==1_${ik}$ ) then
                 b1 = 1_${ik}$
              else
                 b1 = isplit( nblk-1 ) + 1_${ik}$
              end if
              bn = isplit( nblk )
              blksiz = bn - b1 + 1_${ik}$
              if( blksiz==1 )go to 60
              gpind = j1
              ! compute reorthogonalization criterion and stopping criterion.
              onenrm = abs( d( b1 ) ) + abs( e( b1 ) )
              onenrm = max( onenrm, abs( d( bn ) )+abs( e( bn-1 ) ) )
              do i = b1 + 1, bn - 1
                 onenrm = max( onenrm, abs( d( i ) )+abs( e( i-1 ) )+abs( e( i ) ) )
              end do
              ortol = odm3*onenrm
              dtpcrt = sqrt( odm1 / blksiz )
              ! loop through eigenvalues of block nblk.
              60 continue
              jblk = 0_${ik}$
              loop_150: do j = j1, m
                 if( iblock( j )/=nblk ) then
                    j1 = j
                    cycle loop_160
                 end if
                 jblk = jblk + 1_${ik}$
                 xj = w( j )
                 ! skip all the work if the block size is one.
                 if( blksiz==1_${ik}$ ) then
                    work( indrv1+1 ) = one
                    go to 120
                 end if
                 ! if eigenvalues j and j-1 are too close, add a relatively
                 ! small perturbation.
                 if( jblk>1_${ik}$ ) then
                    eps1 = abs( eps*xj )
                    pertol = ten*eps1
                    sep = xj - xjm
                    if( sep<pertol )xj = xjm + pertol
                 end if
                 its = 0_${ik}$
                 nrmchk = 0_${ik}$
                 ! get random starting vector.
                 call stdlib${ii}$_dlarnv( 2_${ik}$, iseed, blksiz, work( indrv1+1 ) )
                 ! copy the matrix t so it won't be destroyed in factorization.
                 call stdlib${ii}$_dcopy( blksiz, d( b1 ), 1_${ik}$, work( indrv4+1 ), 1_${ik}$ )
                 call stdlib${ii}$_dcopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv2+2 ), 1_${ik}$ )
                 call stdlib${ii}$_dcopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv3+1 ), 1_${ik}$ )
                 ! compute lu factors with partial pivoting  ( pt = lu )
                 tol = zero
                 call stdlib${ii}$_dlagtf( blksiz, work( indrv4+1 ), xj, work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), tol, work( indrv5+1 ), iwork,iinfo )
                 ! update iteration count.
                 70 continue
                 its = its + 1_${ik}$
                 if( its>maxits )go to 100
                 ! normalize and scale the righthand side vector pb.
                 jmax = stdlib${ii}$_idamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 scl = blksiz*onenrm*max( eps,abs( work( indrv4+blksiz ) ) ) /abs( work( indrv1+&
                           jmax ) )
                 call stdlib${ii}$_dscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 ! solve the system lu = pb.
                 call stdlib${ii}$_dlagts( -1_${ik}$, blksiz, work( indrv4+1 ), work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), work( indrv5+1 ), iwork,work( indrv1+1 ), tol, iinfo )
                 ! reorthogonalize by modified gram-schmidt if eigenvalues are
                 ! close enough.
                 if( jblk==1 )go to 90
                 if( abs( xj-xjm )>ortol )gpind = j
                 if( gpind/=j ) then
                    do i = gpind, j - 1
                       ztr = -stdlib${ii}$_ddot( blksiz, work( indrv1+1 ), 1_${ik}$, z( b1, i ),1_${ik}$ )
                       call stdlib${ii}$_daxpy( blksiz, ztr, z( b1, i ), 1_${ik}$,work( indrv1+1 ), 1_${ik}$ )
                    end do
                 end if
                 ! check the infinity norm of the iterate.
                 90 continue
                 jmax = stdlib${ii}$_idamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 nrm = abs( work( indrv1+jmax ) )
                 ! continue for additional iterations after norm reaches
                 ! stopping criterion.
                 if( nrm<dtpcrt )go to 70
                 nrmchk = nrmchk + 1_${ik}$
                 if( nrmchk<extra+1 )go to 70
                 go to 110
                 ! if stopping criterion was not satisfied, update info and
                 ! store eigenvector number in array ifail.
                 100 continue
                 info = info + 1_${ik}$
                 ifail( info ) = j
                 ! accept iterate as jth eigenvector.
                 110 continue
                 scl = one / stdlib${ii}$_dnrm2( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 jmax = stdlib${ii}$_idamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 if( work( indrv1+jmax )<zero )scl = -scl
                 call stdlib${ii}$_dscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 120 continue
                 do i = 1, n
                    z( i, j ) = zero
                 end do
                 do i = 1, blksiz
                    z( b1+i-1, j ) = work( indrv1+i )
                 end do
                 ! save the shift to check eigenvalue spacing at next
                 ! iteration.
                 xjm = xj
              end do loop_150
           end do loop_160
           return
     end subroutine stdlib${ii}$_dstein

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stein( n, d, e, m, w, iblock, isplit, z, ldz, work,iwork, ifail, &
     !! DSTEIN: computes the eigenvectors of a real symmetric tridiagonal
     !! matrix T corresponding to specified eigenvalues, using inverse
     !! iteration.
     !! The maximum number of iterations allowed for each eigenvector is
     !! specified by an internal parameter MAXITS (currently set to 5).
               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
           integer(${ik}$), intent(in) :: ldz, m, n
           ! Array Arguments 
           integer(${ik}$), intent(in) :: iblock(*), isplit(*)
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(${rk}$), intent(in) :: d(*), e(*), w(*)
           real(${rk}$), intent(out) :: work(*), z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(${rk}$), parameter :: odm3 = 1.0e-3_${rk}$
           real(${rk}$), parameter :: odm1 = 1.0e-1_${rk}$
           integer(${ik}$), parameter :: maxits = 5_${ik}$
           integer(${ik}$), parameter :: extra = 2_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: b1, blksiz, bn, gpind, i, iinfo, indrv1, indrv2, indrv3, indrv4, &
                     indrv5, its, j, j1, jblk, jmax, nblk, nrmchk
           real(${rk}$) :: dtpcrt, eps, eps1, nrm, onenrm, ortol, pertol, scl, sep, tol, xj, xjm, &
                     ztr
           ! Local Arrays 
           integer(${ik}$) :: iseed(4_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           do i = 1, m
              ifail( i ) = 0_${ik}$
           end do
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
           else if( m<0_${ik}$ .or. m>n ) then
              info = -4_${ik}$
           else if( ldz<max( 1_${ik}$, n ) ) then
              info = -9_${ik}$
           else
              do j = 2, m
                 if( iblock( j )<iblock( j-1 ) ) then
                    info = -6_${ik}$
                    go to 30
                 end if
                 if( iblock( j )==iblock( j-1 ) .and. w( j )<w( j-1 ) )then
                    info = -5_${ik}$
                    go to 30
                 end if
              end do
              30 continue
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEIN', -info )
              return
           end if
           ! quick return if possible
           if( n==0_${ik}$ .or. m==0_${ik}$ ) then
              return
           else if( n==1_${ik}$ ) then
              z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! get machine constants.
           eps = stdlib${ii}$_${ri}$lamch( 'PRECISION' )
           ! initialize seed for random number generator stdlib${ii}$_${ri}$larnv.
           do i = 1, 4
              iseed( i ) = 1_${ik}$
           end do
           ! initialize pointers.
           indrv1 = 0_${ik}$
           indrv2 = indrv1 + n
           indrv3 = indrv2 + n
           indrv4 = indrv3 + n
           indrv5 = indrv4 + n
           ! compute eigenvectors of matrix blocks.
           j1 = 1_${ik}$
           loop_160: do nblk = 1, iblock( m )
              ! find starting and ending indices of block nblk.
              if( nblk==1_${ik}$ ) then
                 b1 = 1_${ik}$
              else
                 b1 = isplit( nblk-1 ) + 1_${ik}$
              end if
              bn = isplit( nblk )
              blksiz = bn - b1 + 1_${ik}$
              if( blksiz==1 )go to 60
              gpind = j1
              ! compute reorthogonalization criterion and stopping criterion.
              onenrm = abs( d( b1 ) ) + abs( e( b1 ) )
              onenrm = max( onenrm, abs( d( bn ) )+abs( e( bn-1 ) ) )
              do i = b1 + 1, bn - 1
                 onenrm = max( onenrm, abs( d( i ) )+abs( e( i-1 ) )+abs( e( i ) ) )
              end do
              ortol = odm3*onenrm
              dtpcrt = sqrt( odm1 / blksiz )
              ! loop through eigenvalues of block nblk.
              60 continue
              jblk = 0_${ik}$
              loop_150: do j = j1, m
                 if( iblock( j )/=nblk ) then
                    j1 = j
                    cycle loop_160
                 end if
                 jblk = jblk + 1_${ik}$
                 xj = w( j )
                 ! skip all the work if the block size is one.
                 if( blksiz==1_${ik}$ ) then
                    work( indrv1+1 ) = one
                    go to 120
                 end if
                 ! if eigenvalues j and j-1 are too close, add a relatively
                 ! small perturbation.
                 if( jblk>1_${ik}$ ) then
                    eps1 = abs( eps*xj )
                    pertol = ten*eps1
                    sep = xj - xjm
                    if( sep<pertol )xj = xjm + pertol
                 end if
                 its = 0_${ik}$
                 nrmchk = 0_${ik}$
                 ! get random starting vector.
                 call stdlib${ii}$_${ri}$larnv( 2_${ik}$, iseed, blksiz, work( indrv1+1 ) )
                 ! copy the matrix t so it won't be destroyed in factorization.
                 call stdlib${ii}$_${ri}$copy( blksiz, d( b1 ), 1_${ik}$, work( indrv4+1 ), 1_${ik}$ )
                 call stdlib${ii}$_${ri}$copy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv2+2 ), 1_${ik}$ )
                 call stdlib${ii}$_${ri}$copy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv3+1 ), 1_${ik}$ )
                 ! compute lu factors with partial pivoting  ( pt = lu )
                 tol = zero
                 call stdlib${ii}$_${ri}$lagtf( blksiz, work( indrv4+1 ), xj, work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), tol, work( indrv5+1 ), iwork,iinfo )
                 ! update iteration count.
                 70 continue
                 its = its + 1_${ik}$
                 if( its>maxits )go to 100
                 ! normalize and scale the righthand side vector pb.
                 jmax = stdlib${ii}$_i${ri}$amax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 scl = blksiz*onenrm*max( eps,abs( work( indrv4+blksiz ) ) ) /abs( work( indrv1+&
                           jmax ) )
                 call stdlib${ii}$_${ri}$scal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 ! solve the system lu = pb.
                 call stdlib${ii}$_${ri}$lagts( -1_${ik}$, blksiz, work( indrv4+1 ), work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), work( indrv5+1 ), iwork,work( indrv1+1 ), tol, iinfo )
                 ! reorthogonalize by modified gram-schmidt if eigenvalues are
                 ! close enough.
                 if( jblk==1 )go to 90
                 if( abs( xj-xjm )>ortol )gpind = j
                 if( gpind/=j ) then
                    do i = gpind, j - 1
                       ztr = -stdlib${ii}$_${ri}$dot( blksiz, work( indrv1+1 ), 1_${ik}$, z( b1, i ),1_${ik}$ )
                       call stdlib${ii}$_${ri}$axpy( blksiz, ztr, z( b1, i ), 1_${ik}$,work( indrv1+1 ), 1_${ik}$ )
                    end do
                 end if
                 ! check the infinity norm of the iterate.
                 90 continue
                 jmax = stdlib${ii}$_i${ri}$amax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 nrm = abs( work( indrv1+jmax ) )
                 ! continue for additional iterations after norm reaches
                 ! stopping criterion.
                 if( nrm<dtpcrt )go to 70
                 nrmchk = nrmchk + 1_${ik}$
                 if( nrmchk<extra+1 )go to 70
                 go to 110
                 ! if stopping criterion was not satisfied, update info and
                 ! store eigenvector number in array ifail.
                 100 continue
                 info = info + 1_${ik}$
                 ifail( info ) = j
                 ! accept iterate as jth eigenvector.
                 110 continue
                 scl = one / stdlib${ii}$_${ri}$nrm2( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 jmax = stdlib${ii}$_i${ri}$amax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 if( work( indrv1+jmax )<zero )scl = -scl
                 call stdlib${ii}$_${ri}$scal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 120 continue
                 do i = 1, n
                    z( i, j ) = zero
                 end do
                 do i = 1, blksiz
                    z( b1+i-1, j ) = work( indrv1+i )
                 end do
                 ! save the shift to check eigenvalue spacing at next
                 ! iteration.
                 xjm = xj
              end do loop_150
           end do loop_160
           return
     end subroutine stdlib${ii}$_${ri}$stein

#:endif
#:endfor

     pure module subroutine stdlib${ii}$_cstein( n, d, e, m, w, iblock, isplit, z, ldz, work,iwork, ifail, &
     !! CSTEIN computes the eigenvectors of a real symmetric tridiagonal
     !! matrix T corresponding to specified eigenvalues, using inverse
     !! iteration.
     !! The maximum number of iterations allowed for each eigenvector is
     !! specified by an internal parameter MAXITS (currently set to 5).
     !! Although the eigenvectors are real, they are stored in a complex
     !! array, which may be passed to CUNMTR or CUPMTR for back
     !! transformation to the eigenvectors of a complex Hermitian matrix
     !! which was reduced to tridiagonal form.
               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
           integer(${ik}$), intent(in) :: ldz, m, n
           ! Array Arguments 
           integer(${ik}$), intent(in) :: iblock(*), isplit(*)
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(sp), intent(in) :: d(*), e(*), w(*)
           real(sp), intent(out) :: work(*)
           complex(sp), intent(out) :: z(ldz,*)
       ! =====================================================================
           ! Parameters 
           real(sp), parameter :: odm3 = 1.0e-3_sp
           real(sp), parameter :: odm1 = 1.0e-1_sp
           integer(${ik}$), parameter :: maxits = 5_${ik}$
           integer(${ik}$), parameter :: extra = 2_${ik}$
           
           
           
           ! Local Scalars 
           integer(${ik}$) :: b1, blksiz, bn, gpind, i, iinfo, indrv1, indrv2, indrv3, indrv4, &
                     indrv5, its, j, j1, jblk, jmax, jr, nblk, nrmchk
           real(sp) :: ctr, eps, eps1, nrm, onenrm, ortol, pertol, scl, sep, stpcrt, tol, xj, &
                     xjm
           ! Local Arrays 
           integer(${ik}$) :: iseed(4_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           do i = 1, m
              ifail( i ) = 0_${ik}$
           end do
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
           else if( m<0_${ik}$ .or. m>n ) then
              info = -4_${ik}$
           else if( ldz<max( 1_${ik}$, n ) ) then
              info = -9_${ik}$
           else
              do j = 2, m
                 if( iblock( j )<iblock( j-1 ) ) then
                    info = -6_${ik}$
                    go to 30
                 end if
                 if( iblock( j )==iblock( j-1 ) .and. w( j )<w( j-1 ) )then
                    info = -5_${ik}$
                    go to 30
                 end if
              end do
              30 continue
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'CSTEIN', -info )
              return
           end if
           ! quick return if possible
           if( n==0_${ik}$ .or. m==0_${ik}$ ) then
              return
           else if( n==1_${ik}$ ) then
              z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           ! get machine constants.
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           ! initialize seed for random number generator stdlib${ii}$_slarnv.
           do i = 1, 4
              iseed( i ) = 1_${ik}$
           end do
           ! initialize pointers.
           indrv1 = 0_${ik}$
           indrv2 = indrv1 + n
           indrv3 = indrv2 + n
           indrv4 = indrv3 + n
           indrv5 = indrv4 + n
           ! compute eigenvectors of matrix blocks.
           j1 = 1_${ik}$
           loop_180: do nblk = 1, iblock( m )
              ! find starting and ending indices of block nblk.
              if( nblk==1_${ik}$ ) then
                 b1 = 1_${ik}$
              else
                 b1 = isplit( nblk-1 ) + 1_${ik}$
              end if
              bn = isplit( nblk )
              blksiz = bn - b1 + 1_${ik}$
              if( blksiz==1 )go to 60
              gpind = j1
              ! compute reorthogonalization criterion and stopping criterion.
              onenrm = abs( d( b1 ) ) + abs( e( b1 ) )
              onenrm = max( onenrm, abs( d( bn ) )+abs( e( bn-1 ) ) )
              do i = b1 + 1, bn - 1
                 onenrm = max( onenrm, abs( d( i ) )+abs( e( i-1 ) )+abs( e( i ) ) )
              end do
              ortol = odm3*onenrm
              stpcrt = sqrt( odm1 / blksiz )
              ! loop through eigenvalues of block nblk.
              60 continue
              jblk = 0_${ik}$
              loop_170: do j = j1, m
                 if( iblock( j )/=nblk ) then
                    j1 = j
                    cycle loop_180
                 end if
                 jblk = jblk + 1_${ik}$
                 xj = w( j )
                 ! skip all the work if the block size is one.
                 if( blksiz==1_${ik}$ ) then
                    work( indrv1+1 ) = one
                    go to 140
                 end if
                 ! if eigenvalues j and j-1 are too close, add a relatively
                 ! small perturbation.
                 if( jblk>1_${ik}$ ) then
                    eps1 = abs( eps*xj )
                    pertol = ten*eps1
                    sep = xj - xjm
                    if( sep<pertol )xj = xjm + pertol
                 end if
                 its = 0_${ik}$
                 nrmchk = 0_${ik}$
                 ! get random starting vector.
                 call stdlib${ii}$_slarnv( 2_${ik}$, iseed, blksiz, work( indrv1+1 ) )
                 ! copy the matrix t so it won't be destroyed in factorization.
                 call stdlib${ii}$_scopy( blksiz, d( b1 ), 1_${ik}$, work( indrv4+1 ), 1_${ik}$ )
                 call stdlib${ii}$_scopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv2+2 ), 1_${ik}$ )
                 call stdlib${ii}$_scopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv3+1 ), 1_${ik}$ )
                 ! compute lu factors with partial pivoting  ( pt = lu )
                 tol = zero
                 call stdlib${ii}$_slagtf( blksiz, work( indrv4+1 ), xj, work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), tol, work( indrv5+1 ), iwork,iinfo )
                 ! update iteration count.
                 70 continue
                 its = its + 1_${ik}$
                 if( its>maxits )go to 120
                 ! normalize and scale the righthand side vector pb.
                 jmax = stdlib${ii}$_isamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 scl = blksiz*onenrm*max( eps,abs( work( indrv4+blksiz ) ) ) /abs( work( indrv1+&
                           jmax ) )
                 call stdlib${ii}$_sscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 ! solve the system lu = pb.
                 call stdlib${ii}$_slagts( -1_${ik}$, blksiz, work( indrv4+1 ), work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), work( indrv5+1 ), iwork,work( indrv1+1 ), tol, iinfo )
                 ! reorthogonalize by modified gram-schmidt if eigenvalues are
                 ! close enough.
                 if( jblk==1 )go to 110
                 if( abs( xj-xjm )>ortol )gpind = j
                 if( gpind/=j ) then
                    do i = gpind, j - 1
                       ctr = zero
                       do jr = 1, blksiz
                          ctr = ctr + work( indrv1+jr )*real( z( b1-1+jr, i ),KIND=sp)
                       end do
                       do jr = 1, blksiz
                          work( indrv1+jr ) = work( indrv1+jr ) -ctr*real( z( b1-1+jr, i ),&
                                    KIND=sp)
                       end do
                    end do
                 end if
                 ! check the infinity norm of the iterate.
                 110 continue
                 jmax = stdlib${ii}$_isamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 nrm = abs( work( indrv1+jmax ) )
                 ! continue for additional iterations after norm reaches
                 ! stopping criterion.
                 if( nrm<stpcrt )go to 70
                 nrmchk = nrmchk + 1_${ik}$
                 if( nrmchk<extra+1 )go to 70
                 go to 130
                 ! if stopping criterion was not satisfied, update info and
                 ! store eigenvector number in array ifail.
                 120 continue
                 info = info + 1_${ik}$
                 ifail( info ) = j
                 ! accept iterate as jth eigenvector.
                 130 continue
                 scl = one / stdlib${ii}$_snrm2( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 jmax = stdlib${ii}$_isamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 if( work( indrv1+jmax )<zero )scl = -scl
                 call stdlib${ii}$_sscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 140 continue
                 do i = 1, n
                    z( i, j ) = czero
                 end do
                 do i = 1, blksiz
                    z( b1+i-1, j ) = cmplx( work( indrv1+i ), zero,KIND=sp)
                 end do
                 ! save the shift to check eigenvalue spacing at next
                 ! iteration.
                 xjm = xj
              end do loop_170
           end do loop_180
           return
     end subroutine stdlib${ii}$_cstein

     pure module subroutine stdlib${ii}$_zstein( n, d, e, m, w, iblock, isplit, z, ldz, work,iwork, ifail, &
     !! ZSTEIN computes the eigenvectors of a real symmetric tridiagonal
     !! matrix T corresponding to specified eigenvalues, using inverse
     !! iteration.
     !! The maximum number of iterations allowed for each eigenvector is
     !! specified by an internal parameter MAXITS (currently set to 5).
     !! Although the eigenvectors are real, they are stored in a complex
     !! array, which may be passed to ZUNMTR or ZUPMTR for back
     !! transformation to the eigenvectors of a complex Hermitian matrix
     !! which was reduced to tridiagonal form.
               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
           integer(${ik}$), intent(in) :: ldz, m, n
           ! Array Arguments 
           integer(${ik}$), intent(in) :: iblock(*), isplit(*)
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(dp), intent(in) :: d(*), e(*), w(*)
           real(dp), intent(out) :: work(*)
           complex(dp), intent(out) :: z(ldz,*)
       ! =====================================================================
           ! Parameters 
           real(dp), parameter :: odm3 = 1.0e-3_dp
           real(dp), parameter :: odm1 = 1.0e-1_dp
           integer(${ik}$), parameter :: maxits = 5_${ik}$
           integer(${ik}$), parameter :: extra = 2_${ik}$
           
           
           
           ! Local Scalars 
           integer(${ik}$) :: b1, blksiz, bn, gpind, i, iinfo, indrv1, indrv2, indrv3, indrv4, &
                     indrv5, its, j, j1, jblk, jmax, jr, nblk, nrmchk
           real(dp) :: dtpcrt, eps, eps1, nrm, onenrm, ortol, pertol, scl, sep, tol, xj, xjm, &
                     ztr
           ! Local Arrays 
           integer(${ik}$) :: iseed(4_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           do i = 1, m
              ifail( i ) = 0_${ik}$
           end do
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
           else if( m<0_${ik}$ .or. m>n ) then
              info = -4_${ik}$
           else if( ldz<max( 1_${ik}$, n ) ) then
              info = -9_${ik}$
           else
              do j = 2, m
                 if( iblock( j )<iblock( j-1 ) ) then
                    info = -6_${ik}$
                    go to 30
                 end if
                 if( iblock( j )==iblock( j-1 ) .and. w( j )<w( j-1 ) )then
                    info = -5_${ik}$
                    go to 30
                 end if
              end do
              30 continue
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEIN', -info )
              return
           end if
           ! quick return if possible
           if( n==0_${ik}$ .or. m==0_${ik}$ ) then
              return
           else if( n==1_${ik}$ ) then
              z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           ! get machine constants.
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           ! initialize seed for random number generator stdlib${ii}$_dlarnv.
           do i = 1, 4
              iseed( i ) = 1_${ik}$
           end do
           ! initialize pointers.
           indrv1 = 0_${ik}$
           indrv2 = indrv1 + n
           indrv3 = indrv2 + n
           indrv4 = indrv3 + n
           indrv5 = indrv4 + n
           ! compute eigenvectors of matrix blocks.
           j1 = 1_${ik}$
           loop_180: do nblk = 1, iblock( m )
              ! find starting and ending indices of block nblk.
              if( nblk==1_${ik}$ ) then
                 b1 = 1_${ik}$
              else
                 b1 = isplit( nblk-1 ) + 1_${ik}$
              end if
              bn = isplit( nblk )
              blksiz = bn - b1 + 1_${ik}$
              if( blksiz==1 )go to 60
              gpind = j1
              ! compute reorthogonalization criterion and stopping criterion.
              onenrm = abs( d( b1 ) ) + abs( e( b1 ) )
              onenrm = max( onenrm, abs( d( bn ) )+abs( e( bn-1 ) ) )
              do i = b1 + 1, bn - 1
                 onenrm = max( onenrm, abs( d( i ) )+abs( e( i-1 ) )+abs( e( i ) ) )
              end do
              ortol = odm3*onenrm
              dtpcrt = sqrt( odm1 / blksiz )
              ! loop through eigenvalues of block nblk.
              60 continue
              jblk = 0_${ik}$
              loop_170: do j = j1, m
                 if( iblock( j )/=nblk ) then
                    j1 = j
                    cycle loop_180
                 end if
                 jblk = jblk + 1_${ik}$
                 xj = w( j )
                 ! skip all the work if the block size is one.
                 if( blksiz==1_${ik}$ ) then
                    work( indrv1+1 ) = one
                    go to 140
                 end if
                 ! if eigenvalues j and j-1 are too close, add a relatively
                 ! small perturbation.
                 if( jblk>1_${ik}$ ) then
                    eps1 = abs( eps*xj )
                    pertol = ten*eps1
                    sep = xj - xjm
                    if( sep<pertol )xj = xjm + pertol
                 end if
                 its = 0_${ik}$
                 nrmchk = 0_${ik}$
                 ! get random starting vector.
                 call stdlib${ii}$_dlarnv( 2_${ik}$, iseed, blksiz, work( indrv1+1 ) )
                 ! copy the matrix t so it won't be destroyed in factorization.
                 call stdlib${ii}$_dcopy( blksiz, d( b1 ), 1_${ik}$, work( indrv4+1 ), 1_${ik}$ )
                 call stdlib${ii}$_dcopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv2+2 ), 1_${ik}$ )
                 call stdlib${ii}$_dcopy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv3+1 ), 1_${ik}$ )
                 ! compute lu factors with partial pivoting  ( pt = lu )
                 tol = zero
                 call stdlib${ii}$_dlagtf( blksiz, work( indrv4+1 ), xj, work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), tol, work( indrv5+1 ), iwork,iinfo )
                 ! update iteration count.
                 70 continue
                 its = its + 1_${ik}$
                 if( its>maxits )go to 120
                 ! normalize and scale the righthand side vector pb.
                 jmax = stdlib${ii}$_idamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 scl = blksiz*onenrm*max( eps,abs( work( indrv4+blksiz ) ) ) /abs( work( indrv1+&
                           jmax ) )
                 call stdlib${ii}$_dscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 ! solve the system lu = pb.
                 call stdlib${ii}$_dlagts( -1_${ik}$, blksiz, work( indrv4+1 ), work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), work( indrv5+1 ), iwork,work( indrv1+1 ), tol, iinfo )
                 ! reorthogonalize by modified gram-schmidt if eigenvalues are
                 ! close enough.
                 if( jblk==1 )go to 110
                 if( abs( xj-xjm )>ortol )gpind = j
                 if( gpind/=j ) then
                    do i = gpind, j - 1
                       ztr = zero
                       do jr = 1, blksiz
                          ztr = ztr + work( indrv1+jr )*real( z( b1-1+jr, i ),KIND=dp)
                       end do
                       do jr = 1, blksiz
                          work( indrv1+jr ) = work( indrv1+jr ) -ztr*real( z( b1-1+jr, i ),&
                                    KIND=dp)
                       end do
                    end do
                 end if
                 ! check the infinity norm of the iterate.
                 110 continue
                 jmax = stdlib${ii}$_idamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 nrm = abs( work( indrv1+jmax ) )
                 ! continue for additional iterations after norm reaches
                 ! stopping criterion.
                 if( nrm<dtpcrt )go to 70
                 nrmchk = nrmchk + 1_${ik}$
                 if( nrmchk<extra+1 )go to 70
                 go to 130
                 ! if stopping criterion was not satisfied, update info and
                 ! store eigenvector number in array ifail.
                 120 continue
                 info = info + 1_${ik}$
                 ifail( info ) = j
                 ! accept iterate as jth eigenvector.
                 130 continue
                 scl = one / stdlib${ii}$_dnrm2( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 jmax = stdlib${ii}$_idamax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 if( work( indrv1+jmax )<zero )scl = -scl
                 call stdlib${ii}$_dscal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 140 continue
                 do i = 1, n
                    z( i, j ) = czero
                 end do
                 do i = 1, blksiz
                    z( b1+i-1, j ) = cmplx( work( indrv1+i ), zero,KIND=dp)
                 end do
                 ! save the shift to check eigenvalue spacing at next
                 ! iteration.
                 xjm = xj
              end do loop_170
           end do loop_180
           return
     end subroutine stdlib${ii}$_zstein

#:for ck,ct,ci in CMPLX_KINDS_TYPES
#:if not ck in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ci}$stein( n, d, e, m, w, iblock, isplit, z, ldz, work,iwork, ifail, &
     !! ZSTEIN: computes the eigenvectors of a real symmetric tridiagonal
     !! matrix T corresponding to specified eigenvalues, using inverse
     !! iteration.
     !! The maximum number of iterations allowed for each eigenvector is
     !! specified by an internal parameter MAXITS (currently set to 5).
     !! Although the eigenvectors are real, they are stored in a complex
     !! array, which may be passed to ZUNMTR or ZUPMTR for back
     !! transformation to the eigenvectors of a complex Hermitian matrix
     !! which was reduced to tridiagonal form.
               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(out) :: info
           integer(${ik}$), intent(in) :: ldz, m, n
           ! Array Arguments 
           integer(${ik}$), intent(in) :: iblock(*), isplit(*)
           integer(${ik}$), intent(out) :: ifail(*), iwork(*)
           real(${ck}$), intent(in) :: d(*), e(*), w(*)
           real(${ck}$), intent(out) :: work(*)
           complex(${ck}$), intent(out) :: z(ldz,*)
       ! =====================================================================
           ! Parameters 
           real(${ck}$), parameter :: odm3 = 1.0e-3_${ck}$
           real(${ck}$), parameter :: odm1 = 1.0e-1_${ck}$
           integer(${ik}$), parameter :: maxits = 5_${ik}$
           integer(${ik}$), parameter :: extra = 2_${ik}$
           
           
           
           ! Local Scalars 
           integer(${ik}$) :: b1, blksiz, bn, gpind, i, iinfo, indrv1, indrv2, indrv3, indrv4, &
                     indrv5, its, j, j1, jblk, jmax, jr, nblk, nrmchk
           real(${ck}$) :: dtpcrt, eps, eps1, nrm, onenrm, ortol, pertol, scl, sep, tol, xj, xjm, &
                     ztr
           ! Local Arrays 
           integer(${ik}$) :: iseed(4_${ik}$)
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           do i = 1, m
              ifail( i ) = 0_${ik}$
           end do
           if( n<0_${ik}$ ) then
              info = -1_${ik}$
           else if( m<0_${ik}$ .or. m>n ) then
              info = -4_${ik}$
           else if( ldz<max( 1_${ik}$, n ) ) then
              info = -9_${ik}$
           else
              do j = 2, m
                 if( iblock( j )<iblock( j-1 ) ) then
                    info = -6_${ik}$
                    go to 30
                 end if
                 if( iblock( j )==iblock( j-1 ) .and. w( j )<w( j-1 ) )then
                    info = -5_${ik}$
                    go to 30
                 end if
              end do
              30 continue
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEIN', -info )
              return
           end if
           ! quick return if possible
           if( n==0_${ik}$ .or. m==0_${ik}$ ) then
              return
           else if( n==1_${ik}$ ) then
              z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           ! get machine constants.
           eps = stdlib${ii}$_${c2ri(ci)}$lamch( 'PRECISION' )
           ! initialize seed for random number generator stdlib${ii}$_${c2ri(ci)}$larnv.
           do i = 1, 4
              iseed( i ) = 1_${ik}$
           end do
           ! initialize pointers.
           indrv1 = 0_${ik}$
           indrv2 = indrv1 + n
           indrv3 = indrv2 + n
           indrv4 = indrv3 + n
           indrv5 = indrv4 + n
           ! compute eigenvectors of matrix blocks.
           j1 = 1_${ik}$
           loop_180: do nblk = 1, iblock( m )
              ! find starting and ending indices of block nblk.
              if( nblk==1_${ik}$ ) then
                 b1 = 1_${ik}$
              else
                 b1 = isplit( nblk-1 ) + 1_${ik}$
              end if
              bn = isplit( nblk )
              blksiz = bn - b1 + 1_${ik}$
              if( blksiz==1 )go to 60
              gpind = j1
              ! compute reorthogonalization criterion and stopping criterion.
              onenrm = abs( d( b1 ) ) + abs( e( b1 ) )
              onenrm = max( onenrm, abs( d( bn ) )+abs( e( bn-1 ) ) )
              do i = b1 + 1, bn - 1
                 onenrm = max( onenrm, abs( d( i ) )+abs( e( i-1 ) )+abs( e( i ) ) )
              end do
              ortol = odm3*onenrm
              dtpcrt = sqrt( odm1 / blksiz )
              ! loop through eigenvalues of block nblk.
              60 continue
              jblk = 0_${ik}$
              loop_170: do j = j1, m
                 if( iblock( j )/=nblk ) then
                    j1 = j
                    cycle loop_180
                 end if
                 jblk = jblk + 1_${ik}$
                 xj = w( j )
                 ! skip all the work if the block size is one.
                 if( blksiz==1_${ik}$ ) then
                    work( indrv1+1 ) = one
                    go to 140
                 end if
                 ! if eigenvalues j and j-1 are too close, add a relatively
                 ! small perturbation.
                 if( jblk>1_${ik}$ ) then
                    eps1 = abs( eps*xj )
                    pertol = ten*eps1
                    sep = xj - xjm
                    if( sep<pertol )xj = xjm + pertol
                 end if
                 its = 0_${ik}$
                 nrmchk = 0_${ik}$
                 ! get random starting vector.
                 call stdlib${ii}$_${c2ri(ci)}$larnv( 2_${ik}$, iseed, blksiz, work( indrv1+1 ) )
                 ! copy the matrix t so it won't be destroyed in factorization.
                 call stdlib${ii}$_${c2ri(ci)}$copy( blksiz, d( b1 ), 1_${ik}$, work( indrv4+1 ), 1_${ik}$ )
                 call stdlib${ii}$_${c2ri(ci)}$copy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv2+2 ), 1_${ik}$ )
                 call stdlib${ii}$_${c2ri(ci)}$copy( blksiz-1, e( b1 ), 1_${ik}$, work( indrv3+1 ), 1_${ik}$ )
                 ! compute lu factors with partial pivoting  ( pt = lu )
                 tol = zero
                 call stdlib${ii}$_${c2ri(ci)}$lagtf( blksiz, work( indrv4+1 ), xj, work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), tol, work( indrv5+1 ), iwork,iinfo )
                 ! update iteration count.
                 70 continue
                 its = its + 1_${ik}$
                 if( its>maxits )go to 120
                 ! normalize and scale the righthand side vector pb.
                 jmax = stdlib${ii}$_i${c2ri(ci)}$amax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 scl = blksiz*onenrm*max( eps,abs( work( indrv4+blksiz ) ) ) /abs( work( indrv1+&
                           jmax ) )
                 call stdlib${ii}$_${c2ri(ci)}$scal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 ! solve the system lu = pb.
                 call stdlib${ii}$_${c2ri(ci)}$lagts( -1_${ik}$, blksiz, work( indrv4+1 ), work( indrv2+2 ),work( indrv3+&
                           1_${ik}$ ), work( indrv5+1 ), iwork,work( indrv1+1 ), tol, iinfo )
                 ! reorthogonalize by modified gram-schmidt if eigenvalues are
                 ! close enough.
                 if( jblk==1 )go to 110
                 if( abs( xj-xjm )>ortol )gpind = j
                 if( gpind/=j ) then
                    do i = gpind, j - 1
                       ztr = zero
                       do jr = 1, blksiz
                          ztr = ztr + work( indrv1+jr )*real( z( b1-1+jr, i ),KIND=${ck}$)
                       end do
                       do jr = 1, blksiz
                          work( indrv1+jr ) = work( indrv1+jr ) -ztr*real( z( b1-1+jr, i ),&
                                    KIND=${ck}$)
                       end do
                    end do
                 end if
                 ! check the infinity norm of the iterate.
                 110 continue
                 jmax = stdlib${ii}$_i${c2ri(ci)}$amax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 nrm = abs( work( indrv1+jmax ) )
                 ! continue for additional iterations after norm reaches
                 ! stopping criterion.
                 if( nrm<dtpcrt )go to 70
                 nrmchk = nrmchk + 1_${ik}$
                 if( nrmchk<extra+1 )go to 70
                 go to 130
                 ! if stopping criterion was not satisfied, update info and
                 ! store eigenvector number in array ifail.
                 120 continue
                 info = info + 1_${ik}$
                 ifail( info ) = j
                 ! accept iterate as jth eigenvector.
                 130 continue
                 scl = one / stdlib${ii}$_${c2ri(ci)}$nrm2( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 jmax = stdlib${ii}$_i${c2ri(ci)}$amax( blksiz, work( indrv1+1 ), 1_${ik}$ )
                 if( work( indrv1+jmax )<zero )scl = -scl
                 call stdlib${ii}$_${c2ri(ci)}$scal( blksiz, scl, work( indrv1+1 ), 1_${ik}$ )
                 140 continue
                 do i = 1, n
                    z( i, j ) = czero
                 end do
                 do i = 1, blksiz
                    z( b1+i-1, j ) = cmplx( work( indrv1+i ), zero,KIND=${ck}$)
                 end do
                 ! save the shift to check eigenvalue spacing at next
                 ! iteration.
                 xjm = xj
              end do loop_170
           end do loop_180
           return
     end subroutine stdlib${ii}$_${ci}$stein

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_sstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, nzc, &
     !! SSTEMR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! Depending on the number of desired eigenvalues, these are computed either
     !! by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are
     !! computed by the use of various suitable L D L^T factorizations near clusters
     !! of close eigenvalues (referred to as RRRs, Relatively Robust
     !! Representations). An informal sketch of the algorithm follows.
     !! For each unreduced block (submatrix) of T,
     !! (a) Compute T - sigma I  = L D L^T, so that L and D
     !! define all the wanted eigenvalues to high relative accuracy.
     !! This means that small relative changes in the entries of D and L
     !! cause only small relative changes in the eigenvalues and
     !! eigenvectors. The standard (unfactored) representation of the
     !! tridiagonal matrix T does not have this property in general.
     !! (b) Compute the eigenvalues to suitable accuracy.
     !! If the eigenvectors are desired, the algorithm attains full
     !! accuracy of the computed eigenvalues only right before
     !! the corresponding vectors have to be computed, see steps c) and d).
     !! (c) For each cluster of close eigenvalues, select a new
     !! shift close to the cluster, find a new factorization, and refine
     !! the shifted eigenvalues to suitable accuracy.
     !! (d) For each eigenvalue with a large enough relative separation compute
     !! the corresponding eigenvector by forming a rank revealing twisted
     !! factorization. Go back to (c) for any clusters that remain.
     !! For more details, see:
     !! - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
     !! to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
     !! Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
     !! - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
     !! Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
     !! 2004.  Also LAPACK Working Note 154.
     !! - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem",
     !! Computer Science Division Technical Report No. UCB/CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Further Details
     !! 1.SSTEMR works only on machines which follow IEEE-754
     !! floating-point standard in their handling of infinities and NaNs.
     !! This permits the use of efficient inner loops avoiding a check for
     !! zero divisors.
               isuppz, tryrac, work, lwork,iwork, liwork, 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 
           character, intent(in) :: jobz, range
           logical(lk), intent(inout) :: tryrac
           integer(${ik}$), intent(in) :: il, iu, ldz, nzc, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(sp), intent(in) :: vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*)
           real(sp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(sp), parameter :: minrgp = 3.0e-3_sp
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, lquery, valeig, wantz, zquery
           integer(${ik}$) :: i, ibegin, iend, ifirst, iil, iindbl, iindw, iindwk, iinfo, iinspl, &
           iiu, ilast, in, indd, inde2, inderr, indgp, indgrs, indwrk, itmp, itmp2, j, jblk, jj, &
                     liwmin, lwmin, nsplit, nzcmin, offset, wbegin, wend
           real(sp) :: bignum, cs, eps, pivmin, r1, r2, rmax, rmin, rtol1, rtol2, safmin, scale, &
                     smlnum, sn, thresh, tmp, tnrm, wl, wu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ).or.( liwork==-1_${ik}$ ) )
           zquery = ( nzc==-1_${ik}$ )
           ! stdlib${ii}$_sstemr needs work of size 6*n, iwork of size 3*n.
           ! in addition, stdlib${ii}$_slarre needs work of size 6*n, iwork of size 5*n.
           ! furthermore, stdlib${ii}$_slarrv needs work of size 12*n, iwork of size 7*n.
           if( wantz ) then
              lwmin = 18_${ik}$*n
              liwmin = 10_${ik}$*n
           else
              ! need less workspace if only the eigenvalues are wanted
              lwmin = 12_${ik}$*n
              liwmin = 8_${ik}$*n
           endif
           wl = zero
           wu = zero
           iil = 0_${ik}$
           iiu = 0_${ik}$
           nsplit = 0_${ik}$
           if( valeig ) then
              ! we do not reference vl, vu in the cases range = 'i','a'
              ! the interval (wl, wu] contains all the wanted eigenvalues.
              ! it is either given by the user or computed in stdlib${ii}$_slarre.
              wl = vl
              wu = vu
           elseif( indeig ) then
              ! we do not reference il, iu in the cases range = 'v','a'
              iil = il
              iiu = iu
           endif
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( valeig .and. n>0_${ik}$ .and. wu<=wl ) then
              info = -7_${ik}$
           else if( indeig .and. ( iil<1_${ik}$ .or. iil>n ) ) then
              info = -8_${ik}$
           else if( indeig .and. ( iiu<iil .or. iiu>n ) ) then
              info = -9_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -13_${ik}$
           else if( lwork<lwmin .and. .not.lquery ) then
              info = -17_${ik}$
           else if( liwork<liwmin .and. .not.lquery ) then
              info = -19_${ik}$
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_slamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( wantz .and. alleig ) then
                 nzcmin = n
              else if( wantz .and. valeig ) then
                 call stdlib${ii}$_slarrc( 'T', n, vl, vu, d, e, safmin,nzcmin, itmp, itmp2, info )
                           
              else if( wantz .and. indeig ) then
                 nzcmin = iiu-iil+1
              else
                 ! wantz == false.
                 nzcmin = 0_${ik}$
              endif
              if( zquery .and. info==0_${ik}$ ) then
                 z( 1_${ik}$,1_${ik}$ ) = nzcmin
              else if( nzc<nzcmin .and. .not.zquery ) then
                 info = -14_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEMR', -info )
              return
           else if( lquery .or. zquery ) then
              return
           end if
           ! handle n = 0, 1, and 2 cases immediately
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( wl<d( 1_${ik}$ ) .and. wu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz.and.(.not.zquery) ) then
                 z( 1_${ik}$, 1_${ik}$ ) = one
                 isuppz(1_${ik}$) = 1_${ik}$
                 isuppz(2_${ik}$) = 1_${ik}$
              end if
              return
           end if
           if( n==2_${ik}$ ) then
              if( .not.wantz ) then
                 call stdlib${ii}$_slae2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2 )
              else if( wantz.and.(.not.zquery) ) then
                 call stdlib${ii}$_slaev2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2, cs, sn )
              end if
              if( alleig.or.(valeig.and.(r2>wl).and.(r2<=wu)).or.(indeig.and.(iil==1_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r2
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = -sn
                    z( 2_${ik}$, m ) = cs
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
              if( alleig.or.(valeig.and.(r1>wl).and.(r1<=wu)).or.(indeig.and.(iiu==2_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r1
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = cs
                    z( 2_${ik}$, m ) = sn
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
           else
           ! continue with general n
              indgrs = 1_${ik}$
              inderr = 2_${ik}$*n + 1_${ik}$
              indgp = 3_${ik}$*n + 1_${ik}$
              indd = 4_${ik}$*n + 1_${ik}$
              inde2 = 5_${ik}$*n + 1_${ik}$
              indwrk = 6_${ik}$*n + 1_${ik}$
              iinspl = 1_${ik}$
              iindbl = n + 1_${ik}$
              iindw = 2_${ik}$*n + 1_${ik}$
              iindwk = 3_${ik}$*n + 1_${ik}$
              ! scale matrix to allowable range, if necessary.
              ! the allowable range is related to the pivmin parameter; see the
              ! comments in stdlib${ii}$_slarrd.  the preference for scaling small values
              ! up is heuristic; we expect users' matrices not to be close to the
              ! rmax threshold.
              scale = one
              tnrm = stdlib${ii}$_slanst( 'M', n, d, e )
              if( tnrm>zero .and. tnrm<rmin ) then
                 scale = rmin / tnrm
              else if( tnrm>rmax ) then
                 scale = rmax / tnrm
              end if
              if( scale/=one ) then
                 call stdlib${ii}$_sscal( n, scale, d, 1_${ik}$ )
                 call stdlib${ii}$_sscal( n-1, scale, e, 1_${ik}$ )
                 tnrm = tnrm*scale
                 if( valeig ) then
                    ! if eigenvalues in interval have to be found,
                    ! scale (wl, wu] accordingly
                    wl = wl*scale
                    wu = wu*scale
                 endif
              end if
              ! compute the desired eigenvalues of the tridiagonal after splitting
              ! into smaller subblocks if the corresponding off-diagonal elements
              ! are small
              ! thresh is the splitting parameter for stdlib${ii}$_slarre
              ! a negative thresh forces the old splitting criterion based on the
              ! size of the off-diagonal. a positive thresh switches to splitting
              ! which preserves relative accuracy.
              if( tryrac ) then
                 ! test whether the matrix warrants the more expensive relative approach.
                 call stdlib${ii}$_slarrr( n, d, e, iinfo )
              else
                 ! the user does not care about relative accurately eigenvalues
                 iinfo = -1_${ik}$
              endif
              ! set the splitting criterion
              if (iinfo==0_${ik}$) then
                 thresh = eps
              else
                 thresh = -eps
                 ! relative accuracy is desired but t does not guarantee it
                 tryrac = .false.
              endif
              if( tryrac ) then
                 ! copy original diagonal, needed to guarantee relative accuracy
                 call stdlib${ii}$_scopy(n,d,1_${ik}$,work(indd),1_${ik}$)
              endif
              ! store the squares of the offdiagonal values of t
              do j = 1, n-1
                 work( inde2+j-1 ) = e(j)**2_${ik}$
              end do
              ! set the tolerance parameters for bisection
              if( .not.wantz ) then
                 ! stdlib${ii}$_slarre computes the eigenvalues to full precision.
                 rtol1 = four * eps
                 rtol2 = four * eps
              else
                 ! stdlib${ii}$_slarre computes the eigenvalues to less than full precision.
                 ! stdlib${ii}$_slarrv will refine the eigenvalue approximations, and we can
                 ! need less accurate initial bisection in stdlib${ii}$_slarre.
                 ! note: these settings do only affect the subset case and stdlib${ii}$_slarre
                 rtol1 = max( sqrt(eps)*5.0e-2_sp, four * eps )
                 rtol2 = max( sqrt(eps)*5.0e-3_sp, four * eps )
              endif
              call stdlib${ii}$_slarre( range, n, wl, wu, iil, iiu, d, e,work(inde2), rtol1, rtol2, &
              thresh, nsplit,iwork( iinspl ), m, w, work( inderr ),work( indgp ), iwork( iindbl ),&
              iwork( iindw ), work( indgrs ), pivmin,work( indwrk ), iwork( iindwk ), iinfo )
                        
              if( iinfo/=0_${ik}$ ) then
                 info = 10_${ik}$ + abs( iinfo )
                 return
              end if
              ! note that if range /= 'v', stdlib${ii}$_slarre computes bounds on the desired
              ! part of the spectrum. all desired eigenvalues are contained in
              ! (wl,wu]
              if( wantz ) then
                 ! compute the desired eigenvectors corresponding to the computed
                 ! eigenvalues
                 call stdlib${ii}$_slarrv( n, wl, wu, d, e,pivmin, iwork( iinspl ), m,1_${ik}$, m, minrgp, &
                 rtol1, rtol2,w, work( inderr ), work( indgp ), iwork( iindbl ),iwork( iindw ), &
                           work( indgrs ), z, ldz,isuppz, work( indwrk ), iwork( iindwk ), iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 20_${ik}$ + abs( iinfo )
                    return
                 end if
              else
                 ! stdlib${ii}$_slarre computes eigenvalues of the (shifted) root representation
                 ! stdlib${ii}$_slarrv returns the eigenvalues of the unshifted matrix.
                 ! however, if the eigenvectors are not desired by the user, we need
                 ! to apply the corresponding shifts from stdlib${ii}$_slarre to obtain the
                 ! eigenvalues of the original matrix.
                 do j = 1, m
                    itmp = iwork( iindbl+j-1 )
                    w( j ) = w( j ) + e( iwork( iinspl+itmp-1 ) )
                 end do
              end if
              if ( tryrac ) then
                 ! refine computed eigenvalues so that they are relatively accurate
                 ! with respect to the original matrix t.
                 ibegin = 1_${ik}$
                 wbegin = 1_${ik}$
                 loop_39: do jblk = 1, iwork( iindbl+m-1 )
                    iend = iwork( iinspl+jblk-1 )
                    in = iend - ibegin + 1_${ik}$
                    wend = wbegin - 1_${ik}$
                    ! check if any eigenvalues have to be refined in this block
                    36 continue
                    if( wend<m ) then
                       if( iwork( iindbl+wend )==jblk ) then
                          wend = wend + 1_${ik}$
                          go to 36
                       end if
                    end if
                    if( wend<wbegin ) then
                       ibegin = iend + 1_${ik}$
                       cycle loop_39
                    end if
                    offset = iwork(iindw+wbegin-1)-1_${ik}$
                    ifirst = iwork(iindw+wbegin-1)
                    ilast = iwork(iindw+wend-1)
                    rtol2 = four * eps
                    call stdlib${ii}$_slarrj( in,work(indd+ibegin-1), work(inde2+ibegin-1),ifirst, &
                    ilast, rtol2, offset, w(wbegin),work( inderr+wbegin-1 ),work( indwrk ), iwork(&
                               iindwk ), pivmin,tnrm, iinfo )
                    ibegin = iend + 1_${ik}$
                    wbegin = wend + 1_${ik}$
                 end do loop_39
              endif
              ! if matrix was scaled, then rescale eigenvalues appropriately.
              if( scale/=one ) then
                 call stdlib${ii}$_sscal( m, one / scale, w, 1_${ik}$ )
              end if
           end if
           ! if eigenvalues are not in increasing order, then sort them,
           ! possibly along with eigenvectors.
           if( nsplit>1_${ik}$ .or. n==2_${ik}$ ) then
              if( .not. wantz ) then
                 call stdlib${ii}$_slasrt( 'I', m, w, iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 3_${ik}$
                    return
                 end if
              else
                 do j = 1, m - 1
                    i = 0_${ik}$
                    tmp = w( j )
                    do jj = j + 1, m
                       if( w( jj )<tmp ) then
                          i = jj
                          tmp = w( jj )
                       end if
                    end do
                    if( i/=0_${ik}$ ) then
                       w( i ) = w( j )
                       w( j ) = tmp
                       if( wantz ) then
                          call stdlib${ii}$_sswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                          itmp = isuppz( 2_${ik}$*i-1 )
                          isuppz( 2_${ik}$*i-1 ) = isuppz( 2_${ik}$*j-1 )
                          isuppz( 2_${ik}$*j-1 ) = itmp
                          itmp = isuppz( 2_${ik}$*i )
                          isuppz( 2_${ik}$*i ) = isuppz( 2_${ik}$*j )
                          isuppz( 2_${ik}$*j ) = itmp
                       end if
                    end if
                 end do
              end if
           endif
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_sstemr

     pure module subroutine stdlib${ii}$_dstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, nzc, &
     !! DSTEMR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! Depending on the number of desired eigenvalues, these are computed either
     !! by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are
     !! computed by the use of various suitable L D L^T factorizations near clusters
     !! of close eigenvalues (referred to as RRRs, Relatively Robust
     !! Representations). An informal sketch of the algorithm follows.
     !! For each unreduced block (submatrix) of T,
     !! (a) Compute T - sigma I  = L D L^T, so that L and D
     !! define all the wanted eigenvalues to high relative accuracy.
     !! This means that small relative changes in the entries of D and L
     !! cause only small relative changes in the eigenvalues and
     !! eigenvectors. The standard (unfactored) representation of the
     !! tridiagonal matrix T does not have this property in general.
     !! (b) Compute the eigenvalues to suitable accuracy.
     !! If the eigenvectors are desired, the algorithm attains full
     !! accuracy of the computed eigenvalues only right before
     !! the corresponding vectors have to be computed, see steps c) and d).
     !! (c) For each cluster of close eigenvalues, select a new
     !! shift close to the cluster, find a new factorization, and refine
     !! the shifted eigenvalues to suitable accuracy.
     !! (d) For each eigenvalue with a large enough relative separation compute
     !! the corresponding eigenvector by forming a rank revealing twisted
     !! factorization. Go back to (c) for any clusters that remain.
     !! For more details, see:
     !! - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
     !! to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
     !! Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
     !! - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
     !! Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
     !! 2004.  Also LAPACK Working Note 154.
     !! - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem",
     !! Computer Science Division Technical Report No. UCB/CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Further Details
     !! 1.DSTEMR works only on machines which follow IEEE-754
     !! floating-point standard in their handling of infinities and NaNs.
     !! This permits the use of efficient inner loops avoiding a check for
     !! zero divisors.
               isuppz, tryrac, work, lwork,iwork, liwork, 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 
           character, intent(in) :: jobz, range
           logical(lk), intent(inout) :: tryrac
           integer(${ik}$), intent(in) :: il, iu, ldz, nzc, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(dp), intent(in) :: vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*)
           real(dp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(dp), parameter :: minrgp = 1.0e-3_dp
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, lquery, valeig, wantz, zquery
           integer(${ik}$) :: i, ibegin, iend, ifirst, iil, iindbl, iindw, iindwk, iinfo, iinspl, &
           iiu, ilast, in, indd, inde2, inderr, indgp, indgrs, indwrk, itmp, itmp2, j, jblk, jj, &
                     liwmin, lwmin, nsplit, nzcmin, offset, wbegin, wend
           real(dp) :: bignum, cs, eps, pivmin, r1, r2, rmax, rmin, rtol1, rtol2, safmin, scale, &
                     smlnum, sn, thresh, tmp, tnrm, wl, wu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ).or.( liwork==-1_${ik}$ ) )
           zquery = ( nzc==-1_${ik}$ )
           ! stdlib${ii}$_dstemr needs work of size 6*n, iwork of size 3*n.
           ! in addition, stdlib${ii}$_dlarre needs work of size 6*n, iwork of size 5*n.
           ! furthermore, stdlib${ii}$_dlarrv needs work of size 12*n, iwork of size 7*n.
           if( wantz ) then
              lwmin = 18_${ik}$*n
              liwmin = 10_${ik}$*n
           else
              ! need less workspace if only the eigenvalues are wanted
              lwmin = 12_${ik}$*n
              liwmin = 8_${ik}$*n
           endif
           wl = zero
           wu = zero
           iil = 0_${ik}$
           iiu = 0_${ik}$
           nsplit = 0_${ik}$
           if( valeig ) then
              ! we do not reference vl, vu in the cases range = 'i','a'
              ! the interval (wl, wu] contains all the wanted eigenvalues.
              ! it is either given by the user or computed in stdlib${ii}$_dlarre.
              wl = vl
              wu = vu
           elseif( indeig ) then
              ! we do not reference il, iu in the cases range = 'v','a'
              iil = il
              iiu = iu
           endif
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( valeig .and. n>0_${ik}$ .and. wu<=wl ) then
              info = -7_${ik}$
           else if( indeig .and. ( iil<1_${ik}$ .or. iil>n ) ) then
              info = -8_${ik}$
           else if( indeig .and. ( iiu<iil .or. iiu>n ) ) then
              info = -9_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -13_${ik}$
           else if( lwork<lwmin .and. .not.lquery ) then
              info = -17_${ik}$
           else if( liwork<liwmin .and. .not.lquery ) then
              info = -19_${ik}$
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_dlamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( wantz .and. alleig ) then
                 nzcmin = n
              else if( wantz .and. valeig ) then
                 call stdlib${ii}$_dlarrc( 'T', n, vl, vu, d, e, safmin,nzcmin, itmp, itmp2, info )
                           
              else if( wantz .and. indeig ) then
                 nzcmin = iiu-iil+1
              else
                 ! wantz == false.
                 nzcmin = 0_${ik}$
              endif
              if( zquery .and. info==0_${ik}$ ) then
                 z( 1_${ik}$,1_${ik}$ ) = nzcmin
              else if( nzc<nzcmin .and. .not.zquery ) then
                 info = -14_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEMR', -info )
              return
           else if( lquery .or. zquery ) then
              return
           end if
           ! handle n = 0, 1, and 2 cases immediately
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( wl<d( 1_${ik}$ ) .and. wu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz.and.(.not.zquery) ) then
                 z( 1_${ik}$, 1_${ik}$ ) = one
                 isuppz(1_${ik}$) = 1_${ik}$
                 isuppz(2_${ik}$) = 1_${ik}$
              end if
              return
           end if
           if( n==2_${ik}$ ) then
              if( .not.wantz ) then
                 call stdlib${ii}$_dlae2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2 )
              else if( wantz.and.(.not.zquery) ) then
                 call stdlib${ii}$_dlaev2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2, cs, sn )
              end if
              if( alleig.or.(valeig.and.(r2>wl).and.(r2<=wu)).or.(indeig.and.(iil==1_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r2
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = -sn
                    z( 2_${ik}$, m ) = cs
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
              if( alleig.or.(valeig.and.(r1>wl).and.(r1<=wu)).or.(indeig.and.(iiu==2_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r1
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = cs
                    z( 2_${ik}$, m ) = sn
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
           else
           ! continue with general n
              indgrs = 1_${ik}$
              inderr = 2_${ik}$*n + 1_${ik}$
              indgp = 3_${ik}$*n + 1_${ik}$
              indd = 4_${ik}$*n + 1_${ik}$
              inde2 = 5_${ik}$*n + 1_${ik}$
              indwrk = 6_${ik}$*n + 1_${ik}$
              iinspl = 1_${ik}$
              iindbl = n + 1_${ik}$
              iindw = 2_${ik}$*n + 1_${ik}$
              iindwk = 3_${ik}$*n + 1_${ik}$
              ! scale matrix to allowable range, if necessary.
              ! the allowable range is related to the pivmin parameter; see the
              ! comments in stdlib${ii}$_dlarrd.  the preference for scaling small values
              ! up is heuristic; we expect users' matrices not to be close to the
              ! rmax threshold.
              scale = one
              tnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
              if( tnrm>zero .and. tnrm<rmin ) then
                 scale = rmin / tnrm
              else if( tnrm>rmax ) then
                 scale = rmax / tnrm
              end if
              if( scale/=one ) then
                 call stdlib${ii}$_dscal( n, scale, d, 1_${ik}$ )
                 call stdlib${ii}$_dscal( n-1, scale, e, 1_${ik}$ )
                 tnrm = tnrm*scale
                 if( valeig ) then
                    ! if eigenvalues in interval have to be found,
                    ! scale (wl, wu] accordingly
                    wl = wl*scale
                    wu = wu*scale
                 endif
              end if
              ! compute the desired eigenvalues of the tridiagonal after splitting
              ! into smaller subblocks if the corresponding off-diagonal elements
              ! are small
              ! thresh is the splitting parameter for stdlib${ii}$_dlarre
              ! a negative thresh forces the old splitting criterion based on the
              ! size of the off-diagonal. a positive thresh switches to splitting
              ! which preserves relative accuracy.
              if( tryrac ) then
                 ! test whether the matrix warrants the more expensive relative approach.
                 call stdlib${ii}$_dlarrr( n, d, e, iinfo )
              else
                 ! the user does not care about relative accurately eigenvalues
                 iinfo = -1_${ik}$
              endif
              ! set the splitting criterion
              if (iinfo==0_${ik}$) then
                 thresh = eps
              else
                 thresh = -eps
                 ! relative accuracy is desired but t does not guarantee it
                 tryrac = .false.
              endif
              if( tryrac ) then
                 ! copy original diagonal, needed to guarantee relative accuracy
                 call stdlib${ii}$_dcopy(n,d,1_${ik}$,work(indd),1_${ik}$)
              endif
              ! store the squares of the offdiagonal values of t
              do j = 1, n-1
                 work( inde2+j-1 ) = e(j)**2_${ik}$
              end do
              ! set the tolerance parameters for bisection
              if( .not.wantz ) then
                 ! stdlib${ii}$_dlarre computes the eigenvalues to full precision.
                 rtol1 = four * eps
                 rtol2 = four * eps
              else
                 ! stdlib${ii}$_dlarre computes the eigenvalues to less than full precision.
                 ! stdlib${ii}$_dlarrv will refine the eigenvalue approximations, and we can
                 ! need less accurate initial bisection in stdlib${ii}$_dlarre.
                 ! note: these settings do only affect the subset case and stdlib${ii}$_dlarre
                 rtol1 = sqrt(eps)
                 rtol2 = max( sqrt(eps)*5.0e-3_dp, four * eps )
              endif
              call stdlib${ii}$_dlarre( range, n, wl, wu, iil, iiu, d, e,work(inde2), rtol1, rtol2, &
              thresh, nsplit,iwork( iinspl ), m, w, work( inderr ),work( indgp ), iwork( iindbl ),&
              iwork( iindw ), work( indgrs ), pivmin,work( indwrk ), iwork( iindwk ), iinfo )
                        
              if( iinfo/=0_${ik}$ ) then
                 info = 10_${ik}$ + abs( iinfo )
                 return
              end if
              ! note that if range /= 'v', stdlib${ii}$_dlarre computes bounds on the desired
              ! part of the spectrum. all desired eigenvalues are contained in
              ! (wl,wu]
              if( wantz ) then
                 ! compute the desired eigenvectors corresponding to the computed
                 ! eigenvalues
                 call stdlib${ii}$_dlarrv( n, wl, wu, d, e,pivmin, iwork( iinspl ), m,1_${ik}$, m, minrgp, &
                 rtol1, rtol2,w, work( inderr ), work( indgp ), iwork( iindbl ),iwork( iindw ), &
                           work( indgrs ), z, ldz,isuppz, work( indwrk ), iwork( iindwk ), iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 20_${ik}$ + abs( iinfo )
                    return
                 end if
              else
                 ! stdlib${ii}$_dlarre computes eigenvalues of the (shifted) root representation
                 ! stdlib${ii}$_dlarrv returns the eigenvalues of the unshifted matrix.
                 ! however, if the eigenvectors are not desired by the user, we need
                 ! to apply the corresponding shifts from stdlib${ii}$_dlarre to obtain the
                 ! eigenvalues of the original matrix.
                 do j = 1, m
                    itmp = iwork( iindbl+j-1 )
                    w( j ) = w( j ) + e( iwork( iinspl+itmp-1 ) )
                 end do
              end if
              if ( tryrac ) then
                 ! refine computed eigenvalues so that they are relatively accurate
                 ! with respect to the original matrix t.
                 ibegin = 1_${ik}$
                 wbegin = 1_${ik}$
                 loop_39: do jblk = 1, iwork( iindbl+m-1 )
                    iend = iwork( iinspl+jblk-1 )
                    in = iend - ibegin + 1_${ik}$
                    wend = wbegin - 1_${ik}$
                    ! check if any eigenvalues have to be refined in this block
                    36 continue
                    if( wend<m ) then
                       if( iwork( iindbl+wend )==jblk ) then
                          wend = wend + 1_${ik}$
                          go to 36
                       end if
                    end if
                    if( wend<wbegin ) then
                       ibegin = iend + 1_${ik}$
                       cycle loop_39
                    end if
                    offset = iwork(iindw+wbegin-1)-1_${ik}$
                    ifirst = iwork(iindw+wbegin-1)
                    ilast = iwork(iindw+wend-1)
                    rtol2 = four * eps
                    call stdlib${ii}$_dlarrj( in,work(indd+ibegin-1), work(inde2+ibegin-1),ifirst, &
                    ilast, rtol2, offset, w(wbegin),work( inderr+wbegin-1 ),work( indwrk ), iwork(&
                               iindwk ), pivmin,tnrm, iinfo )
                    ibegin = iend + 1_${ik}$
                    wbegin = wend + 1_${ik}$
                 end do loop_39
              endif
              ! if matrix was scaled, then rescale eigenvalues appropriately.
              if( scale/=one ) then
                 call stdlib${ii}$_dscal( m, one / scale, w, 1_${ik}$ )
              end if
           end if
           ! if eigenvalues are not in increasing order, then sort them,
           ! possibly along with eigenvectors.
           if( nsplit>1_${ik}$ .or. n==2_${ik}$ ) then
              if( .not. wantz ) then
                 call stdlib${ii}$_dlasrt( 'I', m, w, iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 3_${ik}$
                    return
                 end if
              else
                 do j = 1, m - 1
                    i = 0_${ik}$
                    tmp = w( j )
                    do jj = j + 1, m
                       if( w( jj )<tmp ) then
                          i = jj
                          tmp = w( jj )
                       end if
                    end do
                    if( i/=0_${ik}$ ) then
                       w( i ) = w( j )
                       w( j ) = tmp
                       if( wantz ) then
                          call stdlib${ii}$_dswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                          itmp = isuppz( 2_${ik}$*i-1 )
                          isuppz( 2_${ik}$*i-1 ) = isuppz( 2_${ik}$*j-1 )
                          isuppz( 2_${ik}$*j-1 ) = itmp
                          itmp = isuppz( 2_${ik}$*i )
                          isuppz( 2_${ik}$*i ) = isuppz( 2_${ik}$*j )
                          isuppz( 2_${ik}$*j ) = itmp
                       end if
                    end if
                 end do
              end if
           endif
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_dstemr

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$stemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, nzc, &
     !! DSTEMR: computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! Depending on the number of desired eigenvalues, these are computed either
     !! by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are
     !! computed by the use of various suitable L D L^T factorizations near clusters
     !! of close eigenvalues (referred to as RRRs, Relatively Robust
     !! Representations). An informal sketch of the algorithm follows.
     !! For each unreduced block (submatrix) of T,
     !! (a) Compute T - sigma I  = L D L^T, so that L and D
     !! define all the wanted eigenvalues to high relative accuracy.
     !! This means that small relative changes in the entries of D and L
     !! cause only small relative changes in the eigenvalues and
     !! eigenvectors. The standard (unfactored) representation of the
     !! tridiagonal matrix T does not have this property in general.
     !! (b) Compute the eigenvalues to suitable accuracy.
     !! If the eigenvectors are desired, the algorithm attains full
     !! accuracy of the computed eigenvalues only right before
     !! the corresponding vectors have to be computed, see steps c) and d).
     !! (c) For each cluster of close eigenvalues, select a new
     !! shift close to the cluster, find a new factorization, and refine
     !! the shifted eigenvalues to suitable accuracy.
     !! (d) For each eigenvalue with a large enough relative separation compute
     !! the corresponding eigenvector by forming a rank revealing twisted
     !! factorization. Go back to (c) for any clusters that remain.
     !! For more details, see:
     !! - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
     !! to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
     !! Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
     !! - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
     !! Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
     !! 2004.  Also LAPACK Working Note 154.
     !! - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem",
     !! Computer Science Division Technical Report No. UCB/CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Further Details
     !! 1.DSTEMR works only on machines which follow IEEE-754
     !! floating-point standard in their handling of infinities and NaNs.
     !! This permits the use of efficient inner loops avoiding a check for
     !! zero divisors.
               isuppz, tryrac, work, lwork,iwork, liwork, 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 
           character, intent(in) :: jobz, range
           logical(lk), intent(inout) :: tryrac
           integer(${ik}$), intent(in) :: il, iu, ldz, nzc, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(${rk}$), intent(in) :: vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(${rk}$), intent(inout) :: d(*), e(*)
           real(${rk}$), intent(out) :: w(*), work(*)
           real(${rk}$), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(${rk}$), parameter :: minrgp = 1.0e-3_${rk}$
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, lquery, valeig, wantz, zquery
           integer(${ik}$) :: i, ibegin, iend, ifirst, iil, iindbl, iindw, iindwk, iinfo, iinspl, &
           iiu, ilast, in, indd, inde2, inderr, indgp, indgrs, indwrk, itmp, itmp2, j, jblk, jj, &
                     liwmin, lwmin, nsplit, nzcmin, offset, wbegin, wend
           real(${rk}$) :: bignum, cs, eps, pivmin, r1, r2, rmax, rmin, rtol1, rtol2, safmin, scale, &
                     smlnum, sn, thresh, tmp, tnrm, wl, wu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ).or.( liwork==-1_${ik}$ ) )
           zquery = ( nzc==-1_${ik}$ )
           ! stdlib${ii}$_${ri}$stemr needs work of size 6*n, iwork of size 3*n.
           ! in addition, stdlib${ii}$_${ri}$larre needs work of size 6*n, iwork of size 5*n.
           ! furthermore, stdlib${ii}$_${ri}$larrv needs work of size 12*n, iwork of size 7*n.
           if( wantz ) then
              lwmin = 18_${ik}$*n
              liwmin = 10_${ik}$*n
           else
              ! need less workspace if only the eigenvalues are wanted
              lwmin = 12_${ik}$*n
              liwmin = 8_${ik}$*n
           endif
           wl = zero
           wu = zero
           iil = 0_${ik}$
           iiu = 0_${ik}$
           nsplit = 0_${ik}$
           if( valeig ) then
              ! we do not reference vl, vu in the cases range = 'i','a'
              ! the interval (wl, wu] contains all the wanted eigenvalues.
              ! it is either given by the user or computed in stdlib${ii}$_${ri}$larre.
              wl = vl
              wu = vu
           elseif( indeig ) then
              ! we do not reference il, iu in the cases range = 'v','a'
              iil = il
              iiu = iu
           endif
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( valeig .and. n>0_${ik}$ .and. wu<=wl ) then
              info = -7_${ik}$
           else if( indeig .and. ( iil<1_${ik}$ .or. iil>n ) ) then
              info = -8_${ik}$
           else if( indeig .and. ( iiu<iil .or. iiu>n ) ) then
              info = -9_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -13_${ik}$
           else if( lwork<lwmin .and. .not.lquery ) then
              info = -17_${ik}$
           else if( liwork<liwmin .and. .not.lquery ) then
              info = -19_${ik}$
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_${ri}$lamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_${ri}$lamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( wantz .and. alleig ) then
                 nzcmin = n
              else if( wantz .and. valeig ) then
                 call stdlib${ii}$_${ri}$larrc( 'T', n, vl, vu, d, e, safmin,nzcmin, itmp, itmp2, info )
                           
              else if( wantz .and. indeig ) then
                 nzcmin = iiu-iil+1
              else
                 ! wantz == false.
                 nzcmin = 0_${ik}$
              endif
              if( zquery .and. info==0_${ik}$ ) then
                 z( 1_${ik}$,1_${ik}$ ) = nzcmin
              else if( nzc<nzcmin .and. .not.zquery ) then
                 info = -14_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEMR', -info )
              return
           else if( lquery .or. zquery ) then
              return
           end if
           ! handle n = 0, 1, and 2 cases immediately
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( wl<d( 1_${ik}$ ) .and. wu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz.and.(.not.zquery) ) then
                 z( 1_${ik}$, 1_${ik}$ ) = one
                 isuppz(1_${ik}$) = 1_${ik}$
                 isuppz(2_${ik}$) = 1_${ik}$
              end if
              return
           end if
           if( n==2_${ik}$ ) then
              if( .not.wantz ) then
                 call stdlib${ii}$_${ri}$lae2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2 )
              else if( wantz.and.(.not.zquery) ) then
                 call stdlib${ii}$_${ri}$laev2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2, cs, sn )
              end if
              if( alleig.or.(valeig.and.(r2>wl).and.(r2<=wu)).or.(indeig.and.(iil==1_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r2
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = -sn
                    z( 2_${ik}$, m ) = cs
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
              if( alleig.or.(valeig.and.(r1>wl).and.(r1<=wu)).or.(indeig.and.(iiu==2_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r1
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = cs
                    z( 2_${ik}$, m ) = sn
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
           else
           ! continue with general n
              indgrs = 1_${ik}$
              inderr = 2_${ik}$*n + 1_${ik}$
              indgp = 3_${ik}$*n + 1_${ik}$
              indd = 4_${ik}$*n + 1_${ik}$
              inde2 = 5_${ik}$*n + 1_${ik}$
              indwrk = 6_${ik}$*n + 1_${ik}$
              iinspl = 1_${ik}$
              iindbl = n + 1_${ik}$
              iindw = 2_${ik}$*n + 1_${ik}$
              iindwk = 3_${ik}$*n + 1_${ik}$
              ! scale matrix to allowable range, if necessary.
              ! the allowable range is related to the pivmin parameter; see the
              ! comments in stdlib${ii}$_${ri}$larrd.  the preference for scaling small values
              ! up is heuristic; we expect users' matrices not to be close to the
              ! rmax threshold.
              scale = one
              tnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e )
              if( tnrm>zero .and. tnrm<rmin ) then
                 scale = rmin / tnrm
              else if( tnrm>rmax ) then
                 scale = rmax / tnrm
              end if
              if( scale/=one ) then
                 call stdlib${ii}$_${ri}$scal( n, scale, d, 1_${ik}$ )
                 call stdlib${ii}$_${ri}$scal( n-1, scale, e, 1_${ik}$ )
                 tnrm = tnrm*scale
                 if( valeig ) then
                    ! if eigenvalues in interval have to be found,
                    ! scale (wl, wu] accordingly
                    wl = wl*scale
                    wu = wu*scale
                 endif
              end if
              ! compute the desired eigenvalues of the tridiagonal after splitting
              ! into smaller subblocks if the corresponding off-diagonal elements
              ! are small
              ! thresh is the splitting parameter for stdlib${ii}$_${ri}$larre
              ! a negative thresh forces the old splitting criterion based on the
              ! size of the off-diagonal. a positive thresh switches to splitting
              ! which preserves relative accuracy.
              if( tryrac ) then
                 ! test whether the matrix warrants the more expensive relative approach.
                 call stdlib${ii}$_${ri}$larrr( n, d, e, iinfo )
              else
                 ! the user does not care about relative accurately eigenvalues
                 iinfo = -1_${ik}$
              endif
              ! set the splitting criterion
              if (iinfo==0_${ik}$) then
                 thresh = eps
              else
                 thresh = -eps
                 ! relative accuracy is desired but t does not guarantee it
                 tryrac = .false.
              endif
              if( tryrac ) then
                 ! copy original diagonal, needed to guarantee relative accuracy
                 call stdlib${ii}$_${ri}$copy(n,d,1_${ik}$,work(indd),1_${ik}$)
              endif
              ! store the squares of the offdiagonal values of t
              do j = 1, n-1
                 work( inde2+j-1 ) = e(j)**2_${ik}$
              end do
              ! set the tolerance parameters for bisection
              if( .not.wantz ) then
                 ! stdlib${ii}$_${ri}$larre computes the eigenvalues to full precision.
                 rtol1 = four * eps
                 rtol2 = four * eps
              else
                 ! stdlib${ii}$_${ri}$larre computes the eigenvalues to less than full precision.
                 ! stdlib${ii}$_${ri}$larrv will refine the eigenvalue approximations, and we can
                 ! need less accurate initial bisection in stdlib${ii}$_${ri}$larre.
                 ! note: these settings do only affect the subset case and stdlib${ii}$_${ri}$larre
                 rtol1 = sqrt(eps)
                 rtol2 = max( sqrt(eps)*5.0e-3_${rk}$, four * eps )
              endif
              call stdlib${ii}$_${ri}$larre( range, n, wl, wu, iil, iiu, d, e,work(inde2), rtol1, rtol2, &
              thresh, nsplit,iwork( iinspl ), m, w, work( inderr ),work( indgp ), iwork( iindbl ),&
              iwork( iindw ), work( indgrs ), pivmin,work( indwrk ), iwork( iindwk ), iinfo )
                        
              if( iinfo/=0_${ik}$ ) then
                 info = 10_${ik}$ + abs( iinfo )
                 return
              end if
              ! note that if range /= 'v', stdlib${ii}$_${ri}$larre computes bounds on the desired
              ! part of the spectrum. all desired eigenvalues are contained in
              ! (wl,wu]
              if( wantz ) then
                 ! compute the desired eigenvectors corresponding to the computed
                 ! eigenvalues
                 call stdlib${ii}$_${ri}$larrv( n, wl, wu, d, e,pivmin, iwork( iinspl ), m,1_${ik}$, m, minrgp, &
                 rtol1, rtol2,w, work( inderr ), work( indgp ), iwork( iindbl ),iwork( iindw ), &
                           work( indgrs ), z, ldz,isuppz, work( indwrk ), iwork( iindwk ), iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 20_${ik}$ + abs( iinfo )
                    return
                 end if
              else
                 ! stdlib${ii}$_${ri}$larre computes eigenvalues of the (shifted) root representation
                 ! stdlib${ii}$_${ri}$larrv returns the eigenvalues of the unshifted matrix.
                 ! however, if the eigenvectors are not desired by the user, we need
                 ! to apply the corresponding shifts from stdlib${ii}$_${ri}$larre to obtain the
                 ! eigenvalues of the original matrix.
                 do j = 1, m
                    itmp = iwork( iindbl+j-1 )
                    w( j ) = w( j ) + e( iwork( iinspl+itmp-1 ) )
                 end do
              end if
              if ( tryrac ) then
                 ! refine computed eigenvalues so that they are relatively accurate
                 ! with respect to the original matrix t.
                 ibegin = 1_${ik}$
                 wbegin = 1_${ik}$
                 loop_39: do jblk = 1, iwork( iindbl+m-1 )
                    iend = iwork( iinspl+jblk-1 )
                    in = iend - ibegin + 1_${ik}$
                    wend = wbegin - 1_${ik}$
                    ! check if any eigenvalues have to be refined in this block
                    36 continue
                    if( wend<m ) then
                       if( iwork( iindbl+wend )==jblk ) then
                          wend = wend + 1_${ik}$
                          go to 36
                       end if
                    end if
                    if( wend<wbegin ) then
                       ibegin = iend + 1_${ik}$
                       cycle loop_39
                    end if
                    offset = iwork(iindw+wbegin-1)-1_${ik}$
                    ifirst = iwork(iindw+wbegin-1)
                    ilast = iwork(iindw+wend-1)
                    rtol2 = four * eps
                    call stdlib${ii}$_${ri}$larrj( in,work(indd+ibegin-1), work(inde2+ibegin-1),ifirst, &
                    ilast, rtol2, offset, w(wbegin),work( inderr+wbegin-1 ),work( indwrk ), iwork(&
                               iindwk ), pivmin,tnrm, iinfo )
                    ibegin = iend + 1_${ik}$
                    wbegin = wend + 1_${ik}$
                 end do loop_39
              endif
              ! if matrix was scaled, then rescale eigenvalues appropriately.
              if( scale/=one ) then
                 call stdlib${ii}$_${ri}$scal( m, one / scale, w, 1_${ik}$ )
              end if
           end if
           ! if eigenvalues are not in increasing order, then sort them,
           ! possibly along with eigenvectors.
           if( nsplit>1_${ik}$ .or. n==2_${ik}$ ) then
              if( .not. wantz ) then
                 call stdlib${ii}$_${ri}$lasrt( 'I', m, w, iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 3_${ik}$
                    return
                 end if
              else
                 do j = 1, m - 1
                    i = 0_${ik}$
                    tmp = w( j )
                    do jj = j + 1, m
                       if( w( jj )<tmp ) then
                          i = jj
                          tmp = w( jj )
                       end if
                    end do
                    if( i/=0_${ik}$ ) then
                       w( i ) = w( j )
                       w( j ) = tmp
                       if( wantz ) then
                          call stdlib${ii}$_${ri}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                          itmp = isuppz( 2_${ik}$*i-1 )
                          isuppz( 2_${ik}$*i-1 ) = isuppz( 2_${ik}$*j-1 )
                          isuppz( 2_${ik}$*j-1 ) = itmp
                          itmp = isuppz( 2_${ik}$*i )
                          isuppz( 2_${ik}$*i ) = isuppz( 2_${ik}$*j )
                          isuppz( 2_${ik}$*j ) = itmp
                       end if
                    end if
                 end do
              end if
           endif
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_${ri}$stemr

#:endif
#:endfor

     pure module subroutine stdlib${ii}$_cstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, nzc, &
     !! CSTEMR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! Depending on the number of desired eigenvalues, these are computed either
     !! by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are
     !! computed by the use of various suitable L D L^T factorizations near clusters
     !! of close eigenvalues (referred to as RRRs, Relatively Robust
     !! Representations). An informal sketch of the algorithm follows.
     !! For each unreduced block (submatrix) of T,
     !! (a) Compute T - sigma I  = L D L^T, so that L and D
     !! define all the wanted eigenvalues to high relative accuracy.
     !! This means that small relative changes in the entries of D and L
     !! cause only small relative changes in the eigenvalues and
     !! eigenvectors. The standard (unfactored) representation of the
     !! tridiagonal matrix T does not have this property in general.
     !! (b) Compute the eigenvalues to suitable accuracy.
     !! If the eigenvectors are desired, the algorithm attains full
     !! accuracy of the computed eigenvalues only right before
     !! the corresponding vectors have to be computed, see steps c) and d).
     !! (c) For each cluster of close eigenvalues, select a new
     !! shift close to the cluster, find a new factorization, and refine
     !! the shifted eigenvalues to suitable accuracy.
     !! (d) For each eigenvalue with a large enough relative separation compute
     !! the corresponding eigenvector by forming a rank revealing twisted
     !! factorization. Go back to (c) for any clusters that remain.
     !! For more details, see:
     !! - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
     !! to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
     !! Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
     !! - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
     !! Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
     !! 2004.  Also LAPACK Working Note 154.
     !! - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem",
     !! Computer Science Division Technical Report No. UCB/CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Further Details
     !! 1.CSTEMR works only on machines which follow IEEE-754
     !! floating-point standard in their handling of infinities and NaNs.
     !! This permits the use of efficient inner loops avoiding a check for
     !! zero divisors.
     !! 2. LAPACK routines can be used to reduce a complex Hermitean matrix to
     !! real symmetric tridiagonal form.
     !! (Any complex Hermitean tridiagonal matrix has real values on its diagonal
     !! and potentially complex numbers on its off-diagonals. By applying a
     !! similarity transform with an appropriate diagonal matrix
     !! diag(1,e^{i \phy_1}, ... , e^{i \phy_{n-1}}), the complex Hermitean
     !! matrix can be transformed into a real symmetric matrix and complex
     !! arithmetic can be entirely avoided.)
     !! While the eigenvectors of the real symmetric tridiagonal matrix are real,
     !! the eigenvectors of original complex Hermitean matrix have complex entries
     !! in general.
     !! Since LAPACK drivers overwrite the matrix data with the eigenvectors,
     !! CSTEMR accepts complex workspace to facilitate interoperability
     !! with CUNMTR or CUPMTR.
               isuppz, tryrac, work, lwork,iwork, liwork, 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 
           character, intent(in) :: jobz, range
           logical(lk), intent(inout) :: tryrac
           integer(${ik}$), intent(in) :: il, iu, ldz, nzc, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(sp), intent(in) :: vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: w(*), work(*)
           complex(sp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(sp), parameter :: minrgp = 3.0e-3_sp
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, lquery, valeig, wantz, zquery
           integer(${ik}$) :: i, ibegin, iend, ifirst, iil, iindbl, iindw, iindwk, iinfo, iinspl, &
           iiu, ilast, in, indd, inde2, inderr, indgp, indgrs, indwrk, itmp, itmp2, j, jblk, jj, &
                     liwmin, lwmin, nsplit, nzcmin, offset, wbegin, wend
           real(sp) :: bignum, cs, eps, pivmin, r1, r2, rmax, rmin, rtol1, rtol2, safmin, scale, &
                     smlnum, sn, thresh, tmp, tnrm, wl, wu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ).or.( liwork==-1_${ik}$ ) )
           zquery = ( nzc==-1_${ik}$ )
           ! stdlib${ii}$_sstemr needs work of size 6*n, iwork of size 3*n.
           ! in addition, stdlib${ii}$_slarre needs work of size 6*n, iwork of size 5*n.
           ! furthermore, stdlib${ii}$_clarrv needs work of size 12*n, iwork of size 7*n.
           if( wantz ) then
              lwmin = 18_${ik}$*n
              liwmin = 10_${ik}$*n
           else
              ! need less workspace if only the eigenvalues are wanted
              lwmin = 12_${ik}$*n
              liwmin = 8_${ik}$*n
           endif
           wl = zero
           wu = zero
           iil = 0_${ik}$
           iiu = 0_${ik}$
           nsplit = 0_${ik}$
           if( valeig ) then
              ! we do not reference vl, vu in the cases range = 'i','a'
              ! the interval (wl, wu] contains all the wanted eigenvalues.
              ! it is either given by the user or computed in stdlib${ii}$_slarre.
              wl = vl
              wu = vu
           elseif( indeig ) then
              ! we do not reference il, iu in the cases range = 'v','a'
              iil = il
              iiu = iu
           endif
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( valeig .and. n>0_${ik}$ .and. wu<=wl ) then
              info = -7_${ik}$
           else if( indeig .and. ( iil<1_${ik}$ .or. iil>n ) ) then
              info = -8_${ik}$
           else if( indeig .and. ( iiu<iil .or. iiu>n ) ) then
              info = -9_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -13_${ik}$
           else if( lwork<lwmin .and. .not.lquery ) then
              info = -17_${ik}$
           else if( liwork<liwmin .and. .not.lquery ) then
              info = -19_${ik}$
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_slamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_slamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( wantz .and. alleig ) then
                 nzcmin = n
              else if( wantz .and. valeig ) then
                 call stdlib${ii}$_slarrc( 'T', n, vl, vu, d, e, safmin,nzcmin, itmp, itmp2, info )
                           
              else if( wantz .and. indeig ) then
                 nzcmin = iiu-iil+1
              else
                 ! wantz == false.
                 nzcmin = 0_${ik}$
              endif
              if( zquery .and. info==0_${ik}$ ) then
                 z( 1_${ik}$,1_${ik}$ ) = nzcmin
              else if( nzc<nzcmin .and. .not.zquery ) then
                 info = -14_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'CSTEMR', -info )
              return
           else if( lquery .or. zquery ) then
              return
           end if
           ! handle n = 0, 1, and 2 cases immediately
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( wl<d( 1_${ik}$ ) .and. wu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz.and.(.not.zquery) ) then
                 z( 1_${ik}$, 1_${ik}$ ) = one
                 isuppz(1_${ik}$) = 1_${ik}$
                 isuppz(2_${ik}$) = 1_${ik}$
              end if
              return
           end if
           if( n==2_${ik}$ ) then
              if( .not.wantz ) then
                 call stdlib${ii}$_slae2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2 )
              else if( wantz.and.(.not.zquery) ) then
                 call stdlib${ii}$_slaev2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2, cs, sn )
              end if
              if( alleig.or.(valeig.and.(r2>wl).and.(r2<=wu)).or.(indeig.and.(iil==1_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r2
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = -sn
                    z( 2_${ik}$, m ) = cs
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
              if( alleig.or.(valeig.and.(r1>wl).and.(r1<=wu)).or.(indeig.and.(iiu==2_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r1
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = cs
                    z( 2_${ik}$, m ) = sn
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
           else
              ! continue with general n
              indgrs = 1_${ik}$
              inderr = 2_${ik}$*n + 1_${ik}$
              indgp = 3_${ik}$*n + 1_${ik}$
              indd = 4_${ik}$*n + 1_${ik}$
              inde2 = 5_${ik}$*n + 1_${ik}$
              indwrk = 6_${ik}$*n + 1_${ik}$
              iinspl = 1_${ik}$
              iindbl = n + 1_${ik}$
              iindw = 2_${ik}$*n + 1_${ik}$
              iindwk = 3_${ik}$*n + 1_${ik}$
              ! scale matrix to allowable range, if necessary.
              ! the allowable range is related to the pivmin parameter; see the
              ! comments in stdlib${ii}$_slarrd.  the preference for scaling small values
              ! up is heuristic; we expect users' matrices not to be close to the
              ! rmax threshold.
              scale = one
              tnrm = stdlib${ii}$_slanst( 'M', n, d, e )
              if( tnrm>zero .and. tnrm<rmin ) then
                 scale = rmin / tnrm
              else if( tnrm>rmax ) then
                 scale = rmax / tnrm
              end if
              if( scale/=one ) then
                 call stdlib${ii}$_sscal( n, scale, d, 1_${ik}$ )
                 call stdlib${ii}$_sscal( n-1, scale, e, 1_${ik}$ )
                 tnrm = tnrm*scale
                 if( valeig ) then
                    ! if eigenvalues in interval have to be found,
                    ! scale (wl, wu] accordingly
                    wl = wl*scale
                    wu = wu*scale
                 endif
              end if
              ! compute the desired eigenvalues of the tridiagonal after splitting
              ! into smaller subblocks if the corresponding off-diagonal elements
              ! are small
              ! thresh is the splitting parameter for stdlib${ii}$_slarre
              ! a negative thresh forces the old splitting criterion based on the
              ! size of the off-diagonal. a positive thresh switches to splitting
              ! which preserves relative accuracy.
              if( tryrac ) then
                 ! test whether the matrix warrants the more expensive relative approach.
                 call stdlib${ii}$_slarrr( n, d, e, iinfo )
              else
                 ! the user does not care about relative accurately eigenvalues
                 iinfo = -1_${ik}$
              endif
              ! set the splitting criterion
              if (iinfo==0_${ik}$) then
                 thresh = eps
              else
                 thresh = -eps
                 ! relative accuracy is desired but t does not guarantee it
                 tryrac = .false.
              endif
              if( tryrac ) then
                 ! copy original diagonal, needed to guarantee relative accuracy
                 call stdlib${ii}$_scopy(n,d,1_${ik}$,work(indd),1_${ik}$)
              endif
              ! store the squares of the offdiagonal values of t
              do j = 1, n-1
                 work( inde2+j-1 ) = e(j)**2_${ik}$
              end do
              ! set the tolerance parameters for bisection
              if( .not.wantz ) then
                 ! stdlib${ii}$_slarre computes the eigenvalues to full precision.
                 rtol1 = four * eps
                 rtol2 = four * eps
              else
                 ! stdlib${ii}$_slarre computes the eigenvalues to less than full precision.
                 ! stdlib${ii}$_clarrv will refine the eigenvalue approximations, and we only
                 ! need less accurate initial bisection in stdlib${ii}$_slarre.
                 ! note: these settings do only affect the subset case and stdlib${ii}$_slarre
                 rtol1 = max( sqrt(eps)*5.0e-2_sp, four * eps )
                 rtol2 = max( sqrt(eps)*5.0e-3_sp, four * eps )
              endif
              call stdlib${ii}$_slarre( range, n, wl, wu, iil, iiu, d, e,work(inde2), rtol1, rtol2, &
              thresh, nsplit,iwork( iinspl ), m, w, work( inderr ),work( indgp ), iwork( iindbl ),&
              iwork( iindw ), work( indgrs ), pivmin,work( indwrk ), iwork( iindwk ), iinfo )
                        
              if( iinfo/=0_${ik}$ ) then
                 info = 10_${ik}$ + abs( iinfo )
                 return
              end if
              ! note that if range /= 'v', stdlib${ii}$_slarre computes bounds on the desired
              ! part of the spectrum. all desired eigenvalues are contained in
              ! (wl,wu]
              if( wantz ) then
                 ! compute the desired eigenvectors corresponding to the computed
                 ! eigenvalues
                 call stdlib${ii}$_clarrv( n, wl, wu, d, e,pivmin, iwork( iinspl ), m,1_${ik}$, m, minrgp, &
                 rtol1, rtol2,w, work( inderr ), work( indgp ), iwork( iindbl ),iwork( iindw ), &
                           work( indgrs ), z, ldz,isuppz, work( indwrk ), iwork( iindwk ), iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 20_${ik}$ + abs( iinfo )
                    return
                 end if
              else
                 ! stdlib${ii}$_slarre computes eigenvalues of the (shifted) root representation
                 ! stdlib${ii}$_clarrv returns the eigenvalues of the unshifted matrix.
                 ! however, if the eigenvectors are not desired by the user, we need
                 ! to apply the corresponding shifts from stdlib${ii}$_slarre to obtain the
                 ! eigenvalues of the original matrix.
                 do j = 1, m
                    itmp = iwork( iindbl+j-1 )
                    w( j ) = w( j ) + e( iwork( iinspl+itmp-1 ) )
                 end do
              end if
              if ( tryrac ) then
                 ! refine computed eigenvalues so that they are relatively accurate
                 ! with respect to the original matrix t.
                 ibegin = 1_${ik}$
                 wbegin = 1_${ik}$
                 loop_39: do jblk = 1, iwork( iindbl+m-1 )
                    iend = iwork( iinspl+jblk-1 )
                    in = iend - ibegin + 1_${ik}$
                    wend = wbegin - 1_${ik}$
                    ! check if any eigenvalues have to be refined in this block
                    36 continue
                    if( wend<m ) then
                       if( iwork( iindbl+wend )==jblk ) then
                          wend = wend + 1_${ik}$
                          go to 36
                       end if
                    end if
                    if( wend<wbegin ) then
                       ibegin = iend + 1_${ik}$
                       cycle loop_39
                    end if
                    offset = iwork(iindw+wbegin-1)-1_${ik}$
                    ifirst = iwork(iindw+wbegin-1)
                    ilast = iwork(iindw+wend-1)
                    rtol2 = four * eps
                    call stdlib${ii}$_slarrj( in,work(indd+ibegin-1), work(inde2+ibegin-1),ifirst, &
                    ilast, rtol2, offset, w(wbegin),work( inderr+wbegin-1 ),work( indwrk ), iwork(&
                               iindwk ), pivmin,tnrm, iinfo )
                    ibegin = iend + 1_${ik}$
                    wbegin = wend + 1_${ik}$
                 end do loop_39
              endif
              ! if matrix was scaled, then rescale eigenvalues appropriately.
              if( scale/=one ) then
                 call stdlib${ii}$_sscal( m, one / scale, w, 1_${ik}$ )
              end if
           end if
           ! if eigenvalues are not in increasing order, then sort them,
           ! possibly along with eigenvectors.
           if( nsplit>1_${ik}$ .or. n==2_${ik}$ ) then
              if( .not. wantz ) then
                 call stdlib${ii}$_slasrt( 'I', m, w, iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 3_${ik}$
                    return
                 end if
              else
                 do j = 1, m - 1
                    i = 0_${ik}$
                    tmp = w( j )
                    do jj = j + 1, m
                       if( w( jj )<tmp ) then
                          i = jj
                          tmp = w( jj )
                       end if
                    end do
                    if( i/=0_${ik}$ ) then
                       w( i ) = w( j )
                       w( j ) = tmp
                       if( wantz ) then
                          call stdlib${ii}$_cswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                          itmp = isuppz( 2_${ik}$*i-1 )
                          isuppz( 2_${ik}$*i-1 ) = isuppz( 2_${ik}$*j-1 )
                          isuppz( 2_${ik}$*j-1 ) = itmp
                          itmp = isuppz( 2_${ik}$*i )
                          isuppz( 2_${ik}$*i ) = isuppz( 2_${ik}$*j )
                          isuppz( 2_${ik}$*j ) = itmp
                       end if
                    end if
                 end do
              end if
           endif
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_cstemr

     pure module subroutine stdlib${ii}$_zstemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, nzc, &
     !! ZSTEMR computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! Depending on the number of desired eigenvalues, these are computed either
     !! by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are
     !! computed by the use of various suitable L D L^T factorizations near clusters
     !! of close eigenvalues (referred to as RRRs, Relatively Robust
     !! Representations). An informal sketch of the algorithm follows.
     !! For each unreduced block (submatrix) of T,
     !! (a) Compute T - sigma I  = L D L^T, so that L and D
     !! define all the wanted eigenvalues to high relative accuracy.
     !! This means that small relative changes in the entries of D and L
     !! cause only small relative changes in the eigenvalues and
     !! eigenvectors. The standard (unfactored) representation of the
     !! tridiagonal matrix T does not have this property in general.
     !! (b) Compute the eigenvalues to suitable accuracy.
     !! If the eigenvectors are desired, the algorithm attains full
     !! accuracy of the computed eigenvalues only right before
     !! the corresponding vectors have to be computed, see steps c) and d).
     !! (c) For each cluster of close eigenvalues, select a new
     !! shift close to the cluster, find a new factorization, and refine
     !! the shifted eigenvalues to suitable accuracy.
     !! (d) For each eigenvalue with a large enough relative separation compute
     !! the corresponding eigenvector by forming a rank revealing twisted
     !! factorization. Go back to (c) for any clusters that remain.
     !! For more details, see:
     !! - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
     !! to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
     !! Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
     !! - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
     !! Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
     !! 2004.  Also LAPACK Working Note 154.
     !! - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem",
     !! Computer Science Division Technical Report No. UCB/CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Further Details
     !! 1.ZSTEMR works only on machines which follow IEEE-754
     !! floating-point standard in their handling of infinities and NaNs.
     !! This permits the use of efficient inner loops avoiding a check for
     !! zero divisors.
     !! 2. LAPACK routines can be used to reduce a complex Hermitean matrix to
     !! real symmetric tridiagonal form.
     !! (Any complex Hermitean tridiagonal matrix has real values on its diagonal
     !! and potentially complex numbers on its off-diagonals. By applying a
     !! similarity transform with an appropriate diagonal matrix
     !! diag(1,e^{i \phy_1}, ... , e^{i \phy_{n-1}}), the complex Hermitean
     !! matrix can be transformed into a real symmetric matrix and complex
     !! arithmetic can be entirely avoided.)
     !! While the eigenvectors of the real symmetric tridiagonal matrix are real,
     !! the eigenvectors of original complex Hermitean matrix have complex entries
     !! in general.
     !! Since LAPACK drivers overwrite the matrix data with the eigenvectors,
     !! ZSTEMR accepts complex workspace to facilitate interoperability
     !! with ZUNMTR or ZUPMTR.
               isuppz, tryrac, work, lwork,iwork, liwork, 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 
           character, intent(in) :: jobz, range
           logical(lk), intent(inout) :: tryrac
           integer(${ik}$), intent(in) :: il, iu, ldz, nzc, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(dp), intent(in) :: vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: w(*), work(*)
           complex(dp), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(dp), parameter :: minrgp = 1.0e-3_dp
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, lquery, valeig, wantz, zquery
           integer(${ik}$) :: i, ibegin, iend, ifirst, iil, iindbl, iindw, iindwk, iinfo, iinspl, &
           iiu, ilast, in, indd, inde2, inderr, indgp, indgrs, indwrk, itmp, itmp2, j, jblk, jj, &
                     liwmin, lwmin, nsplit, nzcmin, offset, wbegin, wend
           real(dp) :: bignum, cs, eps, pivmin, r1, r2, rmax, rmin, rtol1, rtol2, safmin, scale, &
                     smlnum, sn, thresh, tmp, tnrm, wl, wu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ).or.( liwork==-1_${ik}$ ) )
           zquery = ( nzc==-1_${ik}$ )
           ! stdlib${ii}$_dstemr needs work of size 6*n, iwork of size 3*n.
           ! in addition, stdlib${ii}$_dlarre needs work of size 6*n, iwork of size 5*n.
           ! furthermore, stdlib${ii}$_zlarrv needs work of size 12*n, iwork of size 7*n.
           if( wantz ) then
              lwmin = 18_${ik}$*n
              liwmin = 10_${ik}$*n
           else
              ! need less workspace if only the eigenvalues are wanted
              lwmin = 12_${ik}$*n
              liwmin = 8_${ik}$*n
           endif
           wl = zero
           wu = zero
           iil = 0_${ik}$
           iiu = 0_${ik}$
           nsplit = 0_${ik}$
           if( valeig ) then
              ! we do not reference vl, vu in the cases range = 'i','a'
              ! the interval (wl, wu] contains all the wanted eigenvalues.
              ! it is either given by the user or computed in stdlib${ii}$_dlarre.
              wl = vl
              wu = vu
           elseif( indeig ) then
              ! we do not reference il, iu in the cases range = 'v','a'
              iil = il
              iiu = iu
           endif
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( valeig .and. n>0_${ik}$ .and. wu<=wl ) then
              info = -7_${ik}$
           else if( indeig .and. ( iil<1_${ik}$ .or. iil>n ) ) then
              info = -8_${ik}$
           else if( indeig .and. ( iiu<iil .or. iiu>n ) ) then
              info = -9_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -13_${ik}$
           else if( lwork<lwmin .and. .not.lquery ) then
              info = -17_${ik}$
           else if( liwork<liwmin .and. .not.lquery ) then
              info = -19_${ik}$
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_dlamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_dlamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( wantz .and. alleig ) then
                 nzcmin = n
              else if( wantz .and. valeig ) then
                 call stdlib${ii}$_dlarrc( 'T', n, vl, vu, d, e, safmin,nzcmin, itmp, itmp2, info )
                           
              else if( wantz .and. indeig ) then
                 nzcmin = iiu-iil+1
              else
                 ! wantz == false.
                 nzcmin = 0_${ik}$
              endif
              if( zquery .and. info==0_${ik}$ ) then
                 z( 1_${ik}$,1_${ik}$ ) = nzcmin
              else if( nzc<nzcmin .and. .not.zquery ) then
                 info = -14_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEMR', -info )
              return
           else if( lquery .or. zquery ) then
              return
           end if
           ! handle n = 0, 1, and 2 cases immediately
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( wl<d( 1_${ik}$ ) .and. wu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz.and.(.not.zquery) ) then
                 z( 1_${ik}$, 1_${ik}$ ) = one
                 isuppz(1_${ik}$) = 1_${ik}$
                 isuppz(2_${ik}$) = 1_${ik}$
              end if
              return
           end if
           if( n==2_${ik}$ ) then
              if( .not.wantz ) then
                 call stdlib${ii}$_dlae2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2 )
              else if( wantz.and.(.not.zquery) ) then
                 call stdlib${ii}$_dlaev2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2, cs, sn )
              end if
              if( alleig.or.(valeig.and.(r2>wl).and.(r2<=wu)).or.(indeig.and.(iil==1_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r2
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = -sn
                    z( 2_${ik}$, m ) = cs
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
              if( alleig.or.(valeig.and.(r1>wl).and.(r1<=wu)).or.(indeig.and.(iiu==2_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r1
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = cs
                    z( 2_${ik}$, m ) = sn
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
           else
              ! continue with general n
              indgrs = 1_${ik}$
              inderr = 2_${ik}$*n + 1_${ik}$
              indgp = 3_${ik}$*n + 1_${ik}$
              indd = 4_${ik}$*n + 1_${ik}$
              inde2 = 5_${ik}$*n + 1_${ik}$
              indwrk = 6_${ik}$*n + 1_${ik}$
              iinspl = 1_${ik}$
              iindbl = n + 1_${ik}$
              iindw = 2_${ik}$*n + 1_${ik}$
              iindwk = 3_${ik}$*n + 1_${ik}$
              ! scale matrix to allowable range, if necessary.
              ! the allowable range is related to the pivmin parameter; see the
              ! comments in stdlib${ii}$_dlarrd.  the preference for scaling small values
              ! up is heuristic; we expect users' matrices not to be close to the
              ! rmax threshold.
              scale = one
              tnrm = stdlib${ii}$_dlanst( 'M', n, d, e )
              if( tnrm>zero .and. tnrm<rmin ) then
                 scale = rmin / tnrm
              else if( tnrm>rmax ) then
                 scale = rmax / tnrm
              end if
              if( scale/=one ) then
                 call stdlib${ii}$_dscal( n, scale, d, 1_${ik}$ )
                 call stdlib${ii}$_dscal( n-1, scale, e, 1_${ik}$ )
                 tnrm = tnrm*scale
                 if( valeig ) then
                    ! if eigenvalues in interval have to be found,
                    ! scale (wl, wu] accordingly
                    wl = wl*scale
                    wu = wu*scale
                 endif
              end if
              ! compute the desired eigenvalues of the tridiagonal after splitting
              ! into smaller subblocks if the corresponding off-diagonal elements
              ! are small
              ! thresh is the splitting parameter for stdlib${ii}$_dlarre
              ! a negative thresh forces the old splitting criterion based on the
              ! size of the off-diagonal. a positive thresh switches to splitting
              ! which preserves relative accuracy.
              if( tryrac ) then
                 ! test whether the matrix warrants the more expensive relative approach.
                 call stdlib${ii}$_dlarrr( n, d, e, iinfo )
              else
                 ! the user does not care about relative accurately eigenvalues
                 iinfo = -1_${ik}$
              endif
              ! set the splitting criterion
              if (iinfo==0_${ik}$) then
                 thresh = eps
              else
                 thresh = -eps
                 ! relative accuracy is desired but t does not guarantee it
                 tryrac = .false.
              endif
              if( tryrac ) then
                 ! copy original diagonal, needed to guarantee relative accuracy
                 call stdlib${ii}$_dcopy(n,d,1_${ik}$,work(indd),1_${ik}$)
              endif
              ! store the squares of the offdiagonal values of t
              do j = 1, n-1
                 work( inde2+j-1 ) = e(j)**2_${ik}$
              end do
              ! set the tolerance parameters for bisection
              if( .not.wantz ) then
                 ! stdlib${ii}$_dlarre computes the eigenvalues to full precision.
                 rtol1 = four * eps
                 rtol2 = four * eps
              else
                 ! stdlib${ii}$_dlarre computes the eigenvalues to less than full precision.
                 ! stdlib${ii}$_zlarrv will refine the eigenvalue approximations, and we only
                 ! need less accurate initial bisection in stdlib${ii}$_dlarre.
                 ! note: these settings do only affect the subset case and stdlib${ii}$_dlarre
                 rtol1 = sqrt(eps)
                 rtol2 = max( sqrt(eps)*5.0e-3_dp, four * eps )
              endif
              call stdlib${ii}$_dlarre( range, n, wl, wu, iil, iiu, d, e,work(inde2), rtol1, rtol2, &
              thresh, nsplit,iwork( iinspl ), m, w, work( inderr ),work( indgp ), iwork( iindbl ),&
              iwork( iindw ), work( indgrs ), pivmin,work( indwrk ), iwork( iindwk ), iinfo )
                        
              if( iinfo/=0_${ik}$ ) then
                 info = 10_${ik}$ + abs( iinfo )
                 return
              end if
              ! note that if range /= 'v', stdlib${ii}$_dlarre computes bounds on the desired
              ! part of the spectrum. all desired eigenvalues are contained in
              ! (wl,wu]
              if( wantz ) then
                 ! compute the desired eigenvectors corresponding to the computed
                 ! eigenvalues
                 call stdlib${ii}$_zlarrv( n, wl, wu, d, e,pivmin, iwork( iinspl ), m,1_${ik}$, m, minrgp, &
                 rtol1, rtol2,w, work( inderr ), work( indgp ), iwork( iindbl ),iwork( iindw ), &
                           work( indgrs ), z, ldz,isuppz, work( indwrk ), iwork( iindwk ), iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 20_${ik}$ + abs( iinfo )
                    return
                 end if
              else
                 ! stdlib${ii}$_dlarre computes eigenvalues of the (shifted) root representation
                 ! stdlib${ii}$_zlarrv returns the eigenvalues of the unshifted matrix.
                 ! however, if the eigenvectors are not desired by the user, we need
                 ! to apply the corresponding shifts from stdlib${ii}$_dlarre to obtain the
                 ! eigenvalues of the original matrix.
                 do j = 1, m
                    itmp = iwork( iindbl+j-1 )
                    w( j ) = w( j ) + e( iwork( iinspl+itmp-1 ) )
                 end do
              end if
              if ( tryrac ) then
                 ! refine computed eigenvalues so that they are relatively accurate
                 ! with respect to the original matrix t.
                 ibegin = 1_${ik}$
                 wbegin = 1_${ik}$
                 loop_39: do jblk = 1, iwork( iindbl+m-1 )
                    iend = iwork( iinspl+jblk-1 )
                    in = iend - ibegin + 1_${ik}$
                    wend = wbegin - 1_${ik}$
                    ! check if any eigenvalues have to be refined in this block
                    36 continue
                    if( wend<m ) then
                       if( iwork( iindbl+wend )==jblk ) then
                          wend = wend + 1_${ik}$
                          go to 36
                       end if
                    end if
                    if( wend<wbegin ) then
                       ibegin = iend + 1_${ik}$
                       cycle loop_39
                    end if
                    offset = iwork(iindw+wbegin-1)-1_${ik}$
                    ifirst = iwork(iindw+wbegin-1)
                    ilast = iwork(iindw+wend-1)
                    rtol2 = four * eps
                    call stdlib${ii}$_dlarrj( in,work(indd+ibegin-1), work(inde2+ibegin-1),ifirst, &
                    ilast, rtol2, offset, w(wbegin),work( inderr+wbegin-1 ),work( indwrk ), iwork(&
                               iindwk ), pivmin,tnrm, iinfo )
                    ibegin = iend + 1_${ik}$
                    wbegin = wend + 1_${ik}$
                 end do loop_39
              endif
              ! if matrix was scaled, then rescale eigenvalues appropriately.
              if( scale/=one ) then
                 call stdlib${ii}$_dscal( m, one / scale, w, 1_${ik}$ )
              end if
           end if
           ! if eigenvalues are not in increasing order, then sort them,
           ! possibly along with eigenvectors.
           if( nsplit>1_${ik}$ .or. n==2_${ik}$ ) then
              if( .not. wantz ) then
                 call stdlib${ii}$_dlasrt( 'I', m, w, iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 3_${ik}$
                    return
                 end if
              else
                 do j = 1, m - 1
                    i = 0_${ik}$
                    tmp = w( j )
                    do jj = j + 1, m
                       if( w( jj )<tmp ) then
                          i = jj
                          tmp = w( jj )
                       end if
                    end do
                    if( i/=0_${ik}$ ) then
                       w( i ) = w( j )
                       w( j ) = tmp
                       if( wantz ) then
                          call stdlib${ii}$_zswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                          itmp = isuppz( 2_${ik}$*i-1 )
                          isuppz( 2_${ik}$*i-1 ) = isuppz( 2_${ik}$*j-1 )
                          isuppz( 2_${ik}$*j-1 ) = itmp
                          itmp = isuppz( 2_${ik}$*i )
                          isuppz( 2_${ik}$*i ) = isuppz( 2_${ik}$*j )
                          isuppz( 2_${ik}$*j ) = itmp
                       end if
                    end if
                 end do
              end if
           endif
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_zstemr

#:for ck,ct,ci in CMPLX_KINDS_TYPES
#:if not ck in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ci}$stemr( jobz, range, n, d, e, vl, vu, il, iu,m, w, z, ldz, nzc, &
     !! ZSTEMR: computes selected eigenvalues and, optionally, eigenvectors
     !! of a real symmetric tridiagonal matrix T. Any such unreduced matrix has
     !! a well defined set of pairwise different real eigenvalues, the corresponding
     !! real eigenvectors are pairwise orthogonal.
     !! The spectrum may be computed either completely or partially by specifying
     !! either an interval (VL,VU] or a range of indices IL:IU for the desired
     !! eigenvalues.
     !! Depending on the number of desired eigenvalues, these are computed either
     !! by bisection or the dqds algorithm. Numerically orthogonal eigenvectors are
     !! computed by the use of various suitable L D L^T factorizations near clusters
     !! of close eigenvalues (referred to as RRRs, Relatively Robust
     !! Representations). An informal sketch of the algorithm follows.
     !! For each unreduced block (submatrix) of T,
     !! (a) Compute T - sigma I  = L D L^T, so that L and D
     !! define all the wanted eigenvalues to high relative accuracy.
     !! This means that small relative changes in the entries of D and L
     !! cause only small relative changes in the eigenvalues and
     !! eigenvectors. The standard (unfactored) representation of the
     !! tridiagonal matrix T does not have this property in general.
     !! (b) Compute the eigenvalues to suitable accuracy.
     !! If the eigenvectors are desired, the algorithm attains full
     !! accuracy of the computed eigenvalues only right before
     !! the corresponding vectors have to be computed, see steps c) and d).
     !! (c) For each cluster of close eigenvalues, select a new
     !! shift close to the cluster, find a new factorization, and refine
     !! the shifted eigenvalues to suitable accuracy.
     !! (d) For each eigenvalue with a large enough relative separation compute
     !! the corresponding eigenvector by forming a rank revealing twisted
     !! factorization. Go back to (c) for any clusters that remain.
     !! For more details, see:
     !! - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
     !! to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
     !! Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
     !! - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
     !! Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
     !! 2004.  Also LAPACK Working Note 154.
     !! - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
     !! tridiagonal eigenvalue/eigenvector problem",
     !! Computer Science Division Technical Report No. UCB/CSD-97-971,
     !! UC Berkeley, May 1997.
     !! Further Details
     !! 1.ZSTEMR works only on machines which follow IEEE-754
     !! floating-point standard in their handling of infinities and NaNs.
     !! This permits the use of efficient inner loops avoiding a check for
     !! zero divisors.
     !! 2. LAPACK routines can be used to reduce a complex Hermitean matrix to
     !! real symmetric tridiagonal form.
     !! (Any complex Hermitean tridiagonal matrix has real values on its diagonal
     !! and potentially complex numbers on its off-diagonals. By applying a
     !! similarity transform with an appropriate diagonal matrix
     !! diag(1,e^{i \phy_1}, ... , e^{i \phy_{n-1}}), the complex Hermitean
     !! matrix can be transformed into a real symmetric matrix and complex
     !! arithmetic can be entirely avoided.)
     !! While the eigenvectors of the real symmetric tridiagonal matrix are real,
     !! the eigenvectors of original complex Hermitean matrix have complex entries
     !! in general.
     !! Since LAPACK drivers overwrite the matrix data with the eigenvectors,
     !! ZSTEMR accepts complex workspace to facilitate interoperability
     !! with ZUNMTR or ZUPMTR.
               isuppz, tryrac, work, lwork,iwork, liwork, 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 
           character, intent(in) :: jobz, range
           logical(lk), intent(inout) :: tryrac
           integer(${ik}$), intent(in) :: il, iu, ldz, nzc, liwork, lwork, n
           integer(${ik}$), intent(out) :: info, m
           real(${ck}$), intent(in) :: vl, vu
           ! Array Arguments 
           integer(${ik}$), intent(out) :: isuppz(*), iwork(*)
           real(${ck}$), intent(inout) :: d(*), e(*)
           real(${ck}$), intent(out) :: w(*), work(*)
           complex(${ck}$), intent(out) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           real(${ck}$), parameter :: minrgp = 1.0e-3_${ck}$
           
           ! Local Scalars 
           logical(lk) :: alleig, indeig, lquery, valeig, wantz, zquery
           integer(${ik}$) :: i, ibegin, iend, ifirst, iil, iindbl, iindw, iindwk, iinfo, iinspl, &
           iiu, ilast, in, indd, inde2, inderr, indgp, indgrs, indwrk, itmp, itmp2, j, jblk, jj, &
                     liwmin, lwmin, nsplit, nzcmin, offset, wbegin, wend
           real(${ck}$) :: bignum, cs, eps, pivmin, r1, r2, rmax, rmin, rtol1, rtol2, safmin, scale, &
                     smlnum, sn, thresh, tmp, tnrm, wl, wu
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           wantz = stdlib_lsame( jobz, 'V' )
           alleig = stdlib_lsame( range, 'A' )
           valeig = stdlib_lsame( range, 'V' )
           indeig = stdlib_lsame( range, 'I' )
           lquery = ( ( lwork==-1_${ik}$ ).or.( liwork==-1_${ik}$ ) )
           zquery = ( nzc==-1_${ik}$ )
           ! stdlib${ii}$_${c2ri(ci)}$stemr needs work of size 6*n, iwork of size 3*n.
           ! in addition, stdlib${ii}$_${c2ri(ci)}$larre needs work of size 6*n, iwork of size 5*n.
           ! furthermore, stdlib${ii}$_${ci}$larrv needs work of size 12*n, iwork of size 7*n.
           if( wantz ) then
              lwmin = 18_${ik}$*n
              liwmin = 10_${ik}$*n
           else
              ! need less workspace if only the eigenvalues are wanted
              lwmin = 12_${ik}$*n
              liwmin = 8_${ik}$*n
           endif
           wl = zero
           wu = zero
           iil = 0_${ik}$
           iiu = 0_${ik}$
           nsplit = 0_${ik}$
           if( valeig ) then
              ! we do not reference vl, vu in the cases range = 'i','a'
              ! the interval (wl, wu] contains all the wanted eigenvalues.
              ! it is either given by the user or computed in stdlib${ii}$_${c2ri(ci)}$larre.
              wl = vl
              wu = vu
           elseif( indeig ) then
              ! we do not reference il, iu in the cases range = 'v','a'
              iil = il
              iiu = iu
           endif
           info = 0_${ik}$
           if( .not.( wantz .or. stdlib_lsame( jobz, 'N' ) ) ) then
              info = -1_${ik}$
           else if( .not.( alleig .or. valeig .or. indeig ) ) then
              info = -2_${ik}$
           else if( n<0_${ik}$ ) then
              info = -3_${ik}$
           else if( valeig .and. n>0_${ik}$ .and. wu<=wl ) then
              info = -7_${ik}$
           else if( indeig .and. ( iil<1_${ik}$ .or. iil>n ) ) then
              info = -8_${ik}$
           else if( indeig .and. ( iiu<iil .or. iiu>n ) ) then
              info = -9_${ik}$
           else if( ldz<1_${ik}$ .or. ( wantz .and. ldz<n ) ) then
              info = -13_${ik}$
           else if( lwork<lwmin .and. .not.lquery ) then
              info = -17_${ik}$
           else if( liwork<liwmin .and. .not.lquery ) then
              info = -19_${ik}$
           end if
           ! get machine constants.
           safmin = stdlib${ii}$_${c2ri(ci)}$lamch( 'SAFE MINIMUM' )
           eps = stdlib${ii}$_${c2ri(ci)}$lamch( 'PRECISION' )
           smlnum = safmin / eps
           bignum = one / smlnum
           rmin = sqrt( smlnum )
           rmax = min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
           if( info==0_${ik}$ ) then
              work( 1_${ik}$ ) = lwmin
              iwork( 1_${ik}$ ) = liwmin
              if( wantz .and. alleig ) then
                 nzcmin = n
              else if( wantz .and. valeig ) then
                 call stdlib${ii}$_${c2ri(ci)}$larrc( 'T', n, vl, vu, d, e, safmin,nzcmin, itmp, itmp2, info )
                           
              else if( wantz .and. indeig ) then
                 nzcmin = iiu-iil+1
              else
                 ! wantz == false.
                 nzcmin = 0_${ik}$
              endif
              if( zquery .and. info==0_${ik}$ ) then
                 z( 1_${ik}$,1_${ik}$ ) = nzcmin
              else if( nzc<nzcmin .and. .not.zquery ) then
                 info = -14_${ik}$
              end if
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEMR', -info )
              return
           else if( lquery .or. zquery ) then
              return
           end if
           ! handle n = 0, 1, and 2 cases immediately
           m = 0_${ik}$
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( alleig .or. indeig ) then
                 m = 1_${ik}$
                 w( 1_${ik}$ ) = d( 1_${ik}$ )
              else
                 if( wl<d( 1_${ik}$ ) .and. wu>=d( 1_${ik}$ ) ) then
                    m = 1_${ik}$
                    w( 1_${ik}$ ) = d( 1_${ik}$ )
                 end if
              end if
              if( wantz.and.(.not.zquery) ) then
                 z( 1_${ik}$, 1_${ik}$ ) = one
                 isuppz(1_${ik}$) = 1_${ik}$
                 isuppz(2_${ik}$) = 1_${ik}$
              end if
              return
           end if
           if( n==2_${ik}$ ) then
              if( .not.wantz ) then
                 call stdlib${ii}$_${c2ri(ci)}$lae2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2 )
              else if( wantz.and.(.not.zquery) ) then
                 call stdlib${ii}$_${c2ri(ci)}$laev2( d(1_${ik}$), e(1_${ik}$), d(2_${ik}$), r1, r2, cs, sn )
              end if
              if( alleig.or.(valeig.and.(r2>wl).and.(r2<=wu)).or.(indeig.and.(iil==1_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r2
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = -sn
                    z( 2_${ik}$, m ) = cs
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
              if( alleig.or.(valeig.and.(r1>wl).and.(r1<=wu)).or.(indeig.and.(iiu==2_${ik}$)) ) &
                        then
                 m = m+1
                 w( m ) = r1
                 if( wantz.and.(.not.zquery) ) then
                    z( 1_${ik}$, m ) = cs
                    z( 2_${ik}$, m ) = sn
                    ! note: at most one of sn and cs can be zero.
                    if (sn/=zero) then
                       if (cs/=zero) then
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 2_${ik}$
                       else
                          isuppz(2_${ik}$*m-1) = 1_${ik}$
                          isuppz(2_${ik}$*m) = 1_${ik}$
                       end if
                    else
                       isuppz(2_${ik}$*m-1) = 2_${ik}$
                       isuppz(2_${ik}$*m) = 2_${ik}$
                    end if
                 endif
              endif
           else
              ! continue with general n
              indgrs = 1_${ik}$
              inderr = 2_${ik}$*n + 1_${ik}$
              indgp = 3_${ik}$*n + 1_${ik}$
              indd = 4_${ik}$*n + 1_${ik}$
              inde2 = 5_${ik}$*n + 1_${ik}$
              indwrk = 6_${ik}$*n + 1_${ik}$
              iinspl = 1_${ik}$
              iindbl = n + 1_${ik}$
              iindw = 2_${ik}$*n + 1_${ik}$
              iindwk = 3_${ik}$*n + 1_${ik}$
              ! scale matrix to allowable range, if necessary.
              ! the allowable range is related to the pivmin parameter; see the
              ! comments in stdlib${ii}$_${c2ri(ci)}$larrd.  the preference for scaling small values
              ! up is heuristic; we expect users' matrices not to be close to the
              ! rmax threshold.
              scale = one
              tnrm = stdlib${ii}$_${c2ri(ci)}$lanst( 'M', n, d, e )
              if( tnrm>zero .and. tnrm<rmin ) then
                 scale = rmin / tnrm
              else if( tnrm>rmax ) then
                 scale = rmax / tnrm
              end if
              if( scale/=one ) then
                 call stdlib${ii}$_${c2ri(ci)}$scal( n, scale, d, 1_${ik}$ )
                 call stdlib${ii}$_${c2ri(ci)}$scal( n-1, scale, e, 1_${ik}$ )
                 tnrm = tnrm*scale
                 if( valeig ) then
                    ! if eigenvalues in interval have to be found,
                    ! scale (wl, wu] accordingly
                    wl = wl*scale
                    wu = wu*scale
                 endif
              end if
              ! compute the desired eigenvalues of the tridiagonal after splitting
              ! into smaller subblocks if the corresponding off-diagonal elements
              ! are small
              ! thresh is the splitting parameter for stdlib${ii}$_${c2ri(ci)}$larre
              ! a negative thresh forces the old splitting criterion based on the
              ! size of the off-diagonal. a positive thresh switches to splitting
              ! which preserves relative accuracy.
              if( tryrac ) then
                 ! test whether the matrix warrants the more expensive relative approach.
                 call stdlib${ii}$_${c2ri(ci)}$larrr( n, d, e, iinfo )
              else
                 ! the user does not care about relative accurately eigenvalues
                 iinfo = -1_${ik}$
              endif
              ! set the splitting criterion
              if (iinfo==0_${ik}$) then
                 thresh = eps
              else
                 thresh = -eps
                 ! relative accuracy is desired but t does not guarantee it
                 tryrac = .false.
              endif
              if( tryrac ) then
                 ! copy original diagonal, needed to guarantee relative accuracy
                 call stdlib${ii}$_${c2ri(ci)}$copy(n,d,1_${ik}$,work(indd),1_${ik}$)
              endif
              ! store the squares of the offdiagonal values of t
              do j = 1, n-1
                 work( inde2+j-1 ) = e(j)**2_${ik}$
              end do
              ! set the tolerance parameters for bisection
              if( .not.wantz ) then
                 ! stdlib${ii}$_${c2ri(ci)}$larre computes the eigenvalues to full precision.
                 rtol1 = four * eps
                 rtol2 = four * eps
              else
                 ! stdlib${ii}$_${c2ri(ci)}$larre computes the eigenvalues to less than full precision.
                 ! stdlib${ii}$_${ci}$larrv will refine the eigenvalue approximations, and we only
                 ! need less accurate initial bisection in stdlib${ii}$_${c2ri(ci)}$larre.
                 ! note: these settings do only affect the subset case and stdlib${ii}$_${c2ri(ci)}$larre
                 rtol1 = sqrt(eps)
                 rtol2 = max( sqrt(eps)*5.0e-3_${ck}$, four * eps )
              endif
              call stdlib${ii}$_${c2ri(ci)}$larre( range, n, wl, wu, iil, iiu, d, e,work(inde2), rtol1, rtol2, &
              thresh, nsplit,iwork( iinspl ), m, w, work( inderr ),work( indgp ), iwork( iindbl ),&
              iwork( iindw ), work( indgrs ), pivmin,work( indwrk ), iwork( iindwk ), iinfo )
                        
              if( iinfo/=0_${ik}$ ) then
                 info = 10_${ik}$ + abs( iinfo )
                 return
              end if
              ! note that if range /= 'v', stdlib${ii}$_${c2ri(ci)}$larre computes bounds on the desired
              ! part of the spectrum. all desired eigenvalues are contained in
              ! (wl,wu]
              if( wantz ) then
                 ! compute the desired eigenvectors corresponding to the computed
                 ! eigenvalues
                 call stdlib${ii}$_${ci}$larrv( n, wl, wu, d, e,pivmin, iwork( iinspl ), m,1_${ik}$, m, minrgp, &
                 rtol1, rtol2,w, work( inderr ), work( indgp ), iwork( iindbl ),iwork( iindw ), &
                           work( indgrs ), z, ldz,isuppz, work( indwrk ), iwork( iindwk ), iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 20_${ik}$ + abs( iinfo )
                    return
                 end if
              else
                 ! stdlib${ii}$_${c2ri(ci)}$larre computes eigenvalues of the (shifted) root representation
                 ! stdlib${ii}$_${ci}$larrv returns the eigenvalues of the unshifted matrix.
                 ! however, if the eigenvectors are not desired by the user, we need
                 ! to apply the corresponding shifts from stdlib${ii}$_${c2ri(ci)}$larre to obtain the
                 ! eigenvalues of the original matrix.
                 do j = 1, m
                    itmp = iwork( iindbl+j-1 )
                    w( j ) = w( j ) + e( iwork( iinspl+itmp-1 ) )
                 end do
              end if
              if ( tryrac ) then
                 ! refine computed eigenvalues so that they are relatively accurate
                 ! with respect to the original matrix t.
                 ibegin = 1_${ik}$
                 wbegin = 1_${ik}$
                 loop_39: do jblk = 1, iwork( iindbl+m-1 )
                    iend = iwork( iinspl+jblk-1 )
                    in = iend - ibegin + 1_${ik}$
                    wend = wbegin - 1_${ik}$
                    ! check if any eigenvalues have to be refined in this block
                    36 continue
                    if( wend<m ) then
                       if( iwork( iindbl+wend )==jblk ) then
                          wend = wend + 1_${ik}$
                          go to 36
                       end if
                    end if
                    if( wend<wbegin ) then
                       ibegin = iend + 1_${ik}$
                       cycle loop_39
                    end if
                    offset = iwork(iindw+wbegin-1)-1_${ik}$
                    ifirst = iwork(iindw+wbegin-1)
                    ilast = iwork(iindw+wend-1)
                    rtol2 = four * eps
                    call stdlib${ii}$_${c2ri(ci)}$larrj( in,work(indd+ibegin-1), work(inde2+ibegin-1),ifirst, &
                    ilast, rtol2, offset, w(wbegin),work( inderr+wbegin-1 ),work( indwrk ), iwork(&
                               iindwk ), pivmin,tnrm, iinfo )
                    ibegin = iend + 1_${ik}$
                    wbegin = wend + 1_${ik}$
                 end do loop_39
              endif
              ! if matrix was scaled, then rescale eigenvalues appropriately.
              if( scale/=one ) then
                 call stdlib${ii}$_${c2ri(ci)}$scal( m, one / scale, w, 1_${ik}$ )
              end if
           end if
           ! if eigenvalues are not in increasing order, then sort them,
           ! possibly along with eigenvectors.
           if( nsplit>1_${ik}$ .or. n==2_${ik}$ ) then
              if( .not. wantz ) then
                 call stdlib${ii}$_${c2ri(ci)}$lasrt( 'I', m, w, iinfo )
                 if( iinfo/=0_${ik}$ ) then
                    info = 3_${ik}$
                    return
                 end if
              else
                 do j = 1, m - 1
                    i = 0_${ik}$
                    tmp = w( j )
                    do jj = j + 1, m
                       if( w( jj )<tmp ) then
                          i = jj
                          tmp = w( jj )
                       end if
                    end do
                    if( i/=0_${ik}$ ) then
                       w( i ) = w( j )
                       w( j ) = tmp
                       if( wantz ) then
                          call stdlib${ii}$_${ci}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, j ), 1_${ik}$ )
                          itmp = isuppz( 2_${ik}$*i-1 )
                          isuppz( 2_${ik}$*i-1 ) = isuppz( 2_${ik}$*j-1 )
                          isuppz( 2_${ik}$*j-1 ) = itmp
                          itmp = isuppz( 2_${ik}$*i )
                          isuppz( 2_${ik}$*i ) = isuppz( 2_${ik}$*j )
                          isuppz( 2_${ik}$*j ) = itmp
                       end if
                    end if
                 end do
              end if
           endif
           work( 1_${ik}$ ) = lwmin
           iwork( 1_${ik}$ ) = liwmin
           return
     end subroutine stdlib${ii}$_${ci}$stemr

#:endif
#:endfor



     pure module subroutine stdlib${ii}$_ssteqr( compz, n, d, e, z, ldz, work, info )
     !! SSTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the implicit QL or QR method.
     !! The eigenvectors of a full or band symmetric matrix can also be found
     !! if SSYTRD or SSPTRD or SSBTRD has been used to reduce this matrix to
     !! tridiagonal form.
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(sp), intent(inout) :: d(*), e(*), z(ldz,*)
           real(sp), intent(out) :: work(*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, ii, iscale, j, jtot, k, l, l1, lend, lendm1, lendp1, lendsv,&
                      lm1, lsv, m, mm, mm1, nm1, nmaxit
           real(sp) :: anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, s, safmax, safmin, ssfmax, &
                     ssfmin, tst
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'SSTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz==2_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! determine the unit roundoff and over/underflow thresholds.
           eps = stdlib${ii}$_slamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_slamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues and eigenvectors of the tridiagonal
           ! matrix.
           if( icompz==2_${ik}$ )call stdlib${ii}$_slaset( 'FULL', n, n, zero, one, z, ldz )
           nmaxit = n*maxit
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           nm1 = n - 1_${ik}$
           10 continue
           if( l1>n )go to 160
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           if( l1<=nm1 ) then
              do m = l1, nm1
                 tst = abs( e( m ) )
                 if( tst==zero )go to 30
                 if( tst<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) then
                    e( m ) = zero
                    go to 30
                 end if
              end do
           end if
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_slanst( 'M', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              40 continue
              if( l/=lend ) then
                 lendm1 = lend - 1_${ik}$
                 do m = l, lendm1
                    tst = abs( e( m ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+safmin )go to 60
                 end do
              end if
              m = lend
              60 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 80
              ! if remaining matrix is 2-by-2, use stdlib_slae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l+1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_slaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
                    work( l ) = c
                    work( n-1+l ) = s
                    call stdlib${ii}$_slasr( 'R', 'V', 'B', n, 2_${ik}$, work( l ),work( n-1+l ), z( 1_${ik}$, l ), &
                              ldz )
                 else
                    call stdlib${ii}$_slae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
                 end if
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 40
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l+1 )-p ) / ( two*e( l ) )
              r = stdlib${ii}$_slapy2( g, one )
              g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              mm1 = m - 1_${ik}$
              do i = mm1, l, -1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_slartg( g, f, c, s, r )
                 if( i/=m-1 )e( i+1 ) = r
                 g = d( i+1 ) - p
                 r = ( d( i )-g )*s + two*c*b
                 p = s*r
                 d( i+1 ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = -s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = m - l + 1_${ik}$
                 call stdlib${ii}$_slasr( 'R', 'V', 'B', n, mm, work( l ), work( n-1+l ),z( 1_${ik}$, l ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( l ) = g
              go to 40
              ! eigenvalue found.
              80 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 40
              go to 140
           else
              ! qr iteration
              ! look for small superdiagonal element.
              90 continue
              if( l/=lend ) then
                 lendp1 = lend + 1_${ik}$
                 do m = l, lendp1, -1
                    tst = abs( e( m-1 ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+safmin )go to 110
                 end do
              end if
              m = lend
              110 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 130
              ! if remaining matrix is 2-by-2, use stdlib_slae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l-1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_slaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
                    work( m ) = c
                    work( n-1+m ) = s
                    call stdlib${ii}$_slasr( 'R', 'V', 'F', n, 2_${ik}$, work( m ),work( n-1+m ), z( 1_${ik}$, l-1 ), &
                              ldz )
                 else
                    call stdlib${ii}$_slae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
                 end if
                 d( l-1 ) = rt1
                 d( l ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 90
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
              r = stdlib${ii}$_slapy2( g, one )
              g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              lm1 = l - 1_${ik}$
              do i = m, lm1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_slartg( g, f, c, s, r )
                 if( i/=m )e( i-1 ) = r
                 g = d( i ) - p
                 r = ( d( i+1 )-g )*s + two*c*b
                 p = s*r
                 d( i ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = l - m + 1_${ik}$
                 call stdlib${ii}$_slasr( 'R', 'V', 'F', n, mm, work( m ), work( n-1+m ),z( 1_${ik}$, m ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( lm1 ) = g
              go to 90
              ! eigenvalue found.
              130 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 90
              go to 140
           end if
           ! undo scaling if necessary
           140 continue
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           else if( iscale==2_${ik}$ ) then
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           end if
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot<nmaxit )go to 10
           do i = 1, n - 1
              if( e( i )/=zero )info = info + 1_${ik}$
           end do
           go to 190
           ! order eigenvalues and eigenvectors.
           160 continue
           if( icompz==0_${ik}$ ) then
              ! use quick sort
              call stdlib${ii}$_slasrt( 'I', n, d, info )
           else
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                 i = ii - 1_${ik}$
                 k = i
                 p = d( i )
                 do j = ii, n
                    if( d( j )<p ) then
                       k = j
                       p = d( j )
                    end if
                 end do
                 if( k/=i ) then
                    d( k ) = d( i )
                    d( i ) = p
                    call stdlib${ii}$_sswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                 end if
              end do
           end if
           190 continue
           return
     end subroutine stdlib${ii}$_ssteqr

     pure module subroutine stdlib${ii}$_dsteqr( compz, n, d, e, z, ldz, work, info )
     !! DSTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the implicit QL or QR method.
     !! The eigenvectors of a full or band symmetric matrix can also be found
     !! if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to
     !! tridiagonal form.
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(dp), intent(inout) :: d(*), e(*), z(ldz,*)
           real(dp), intent(out) :: work(*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, ii, iscale, j, jtot, k, l, l1, lend, lendm1, lendp1, lendsv,&
                      lm1, lsv, m, mm, mm1, nm1, nmaxit
           real(dp) :: anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, s, safmax, safmin, ssfmax, &
                     ssfmin, tst
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz==2_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! determine the unit roundoff and over/underflow thresholds.
           eps = stdlib${ii}$_dlamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_dlamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues and eigenvectors of the tridiagonal
           ! matrix.
           if( icompz==2_${ik}$ )call stdlib${ii}$_dlaset( 'FULL', n, n, zero, one, z, ldz )
           nmaxit = n*maxit
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           nm1 = n - 1_${ik}$
           10 continue
           if( l1>n )go to 160
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           if( l1<=nm1 ) then
              do m = l1, nm1
                 tst = abs( e( m ) )
                 if( tst==zero )go to 30
                 if( tst<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) then
                    e( m ) = zero
                    go to 30
                 end if
              end do
           end if
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_dlanst( 'M', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              40 continue
              if( l/=lend ) then
                 lendm1 = lend - 1_${ik}$
                 do m = l, lendm1
                    tst = abs( e( m ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+safmin )go to 60
                 end do
              end if
              m = lend
              60 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 80
              ! if remaining matrix is 2-by-2, use stdlib_dlae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l+1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_dlaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
                    work( l ) = c
                    work( n-1+l ) = s
                    call stdlib${ii}$_dlasr( 'R', 'V', 'B', n, 2_${ik}$, work( l ),work( n-1+l ), z( 1_${ik}$, l ), &
                              ldz )
                 else
                    call stdlib${ii}$_dlae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
                 end if
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 40
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l+1 )-p ) / ( two*e( l ) )
              r = stdlib${ii}$_dlapy2( g, one )
              g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              mm1 = m - 1_${ik}$
              do i = mm1, l, -1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_dlartg( g, f, c, s, r )
                 if( i/=m-1 )e( i+1 ) = r
                 g = d( i+1 ) - p
                 r = ( d( i )-g )*s + two*c*b
                 p = s*r
                 d( i+1 ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = -s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = m - l + 1_${ik}$
                 call stdlib${ii}$_dlasr( 'R', 'V', 'B', n, mm, work( l ), work( n-1+l ),z( 1_${ik}$, l ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( l ) = g
              go to 40
              ! eigenvalue found.
              80 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 40
              go to 140
           else
              ! qr iteration
              ! look for small superdiagonal element.
              90 continue
              if( l/=lend ) then
                 lendp1 = lend + 1_${ik}$
                 do m = l, lendp1, -1
                    tst = abs( e( m-1 ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+safmin )go to 110
                 end do
              end if
              m = lend
              110 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 130
              ! if remaining matrix is 2-by-2, use stdlib_dlae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l-1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_dlaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
                    work( m ) = c
                    work( n-1+m ) = s
                    call stdlib${ii}$_dlasr( 'R', 'V', 'F', n, 2_${ik}$, work( m ),work( n-1+m ), z( 1_${ik}$, l-1 ), &
                              ldz )
                 else
                    call stdlib${ii}$_dlae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
                 end if
                 d( l-1 ) = rt1
                 d( l ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 90
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
              r = stdlib${ii}$_dlapy2( g, one )
              g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              lm1 = l - 1_${ik}$
              do i = m, lm1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_dlartg( g, f, c, s, r )
                 if( i/=m )e( i-1 ) = r
                 g = d( i ) - p
                 r = ( d( i+1 )-g )*s + two*c*b
                 p = s*r
                 d( i ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = l - m + 1_${ik}$
                 call stdlib${ii}$_dlasr( 'R', 'V', 'F', n, mm, work( m ), work( n-1+m ),z( 1_${ik}$, m ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( lm1 ) = g
              go to 90
              ! eigenvalue found.
              130 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 90
              go to 140
           end if
           ! undo scaling if necessary
           140 continue
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           else if( iscale==2_${ik}$ ) then
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           end if
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot<nmaxit )go to 10
           do i = 1, n - 1
              if( e( i )/=zero )info = info + 1_${ik}$
           end do
           go to 190
           ! order eigenvalues and eigenvectors.
           160 continue
           if( icompz==0_${ik}$ ) then
              ! use quick sort
              call stdlib${ii}$_dlasrt( 'I', n, d, info )
           else
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                 i = ii - 1_${ik}$
                 k = i
                 p = d( i )
                 do j = ii, n
                    if( d( j )<p ) then
                       k = j
                       p = d( j )
                    end if
                 end do
                 if( k/=i ) then
                    d( k ) = d( i )
                    d( i ) = p
                    call stdlib${ii}$_dswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                 end if
              end do
           end if
           190 continue
           return
     end subroutine stdlib${ii}$_dsteqr

#:for rk,rt,ri in REAL_KINDS_TYPES
#:if not rk in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ri}$steqr( compz, n, d, e, z, ldz, work, info )
     !! DSTEQR: computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the implicit QL or QR method.
     !! The eigenvectors of a full or band symmetric matrix can also be found
     !! if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to
     !! tridiagonal form.
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(${rk}$), intent(inout) :: d(*), e(*), z(ldz,*)
           real(${rk}$), intent(out) :: work(*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, ii, iscale, j, jtot, k, l, l1, lend, lendm1, lendp1, lendsv,&
                      lm1, lsv, m, mm, mm1, nm1, nmaxit
           real(${rk}$) :: anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, s, safmax, safmin, ssfmax, &
                     ssfmin, tst
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'DSTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz==2_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = one
              return
           end if
           ! determine the unit roundoff and over/underflow thresholds.
           eps = stdlib${ii}$_${ri}$lamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_${ri}$lamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues and eigenvectors of the tridiagonal
           ! matrix.
           if( icompz==2_${ik}$ )call stdlib${ii}$_${ri}$laset( 'FULL', n, n, zero, one, z, ldz )
           nmaxit = n*maxit
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           nm1 = n - 1_${ik}$
           10 continue
           if( l1>n )go to 160
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           if( l1<=nm1 ) then
              do m = l1, nm1
                 tst = abs( e( m ) )
                 if( tst==zero )go to 30
                 if( tst<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) then
                    e( m ) = zero
                    go to 30
                 end if
              end do
           end if
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_${ri}$lanst( 'M', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              40 continue
              if( l/=lend ) then
                 lendm1 = lend - 1_${ik}$
                 do m = l, lendm1
                    tst = abs( e( m ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+safmin )go to 60
                 end do
              end if
              m = lend
              60 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 80
              ! if remaining matrix is 2-by-2, use stdlib_${ri}$lae2 or stdlib${ii}$_dlaev2
              ! to compute its eigensystem.
              if( m==l+1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_${ri}$laev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
                    work( l ) = c
                    work( n-1+l ) = s
                    call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'B', n, 2_${ik}$, work( l ),work( n-1+l ), z( 1_${ik}$, l ), &
                              ldz )
                 else
                    call stdlib${ii}$_${ri}$lae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
                 end if
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 40
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l+1 )-p ) / ( two*e( l ) )
              r = stdlib${ii}$_${ri}$lapy2( g, one )
              g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              mm1 = m - 1_${ik}$
              do i = mm1, l, -1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_${ri}$lartg( g, f, c, s, r )
                 if( i/=m-1 )e( i+1 ) = r
                 g = d( i+1 ) - p
                 r = ( d( i )-g )*s + two*c*b
                 p = s*r
                 d( i+1 ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = -s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = m - l + 1_${ik}$
                 call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'B', n, mm, work( l ), work( n-1+l ),z( 1_${ik}$, l ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( l ) = g
              go to 40
              ! eigenvalue found.
              80 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 40
              go to 140
           else
              ! qr iteration
              ! look for small superdiagonal element.
              90 continue
              if( l/=lend ) then
                 lendp1 = lend + 1_${ik}$
                 do m = l, lendp1, -1
                    tst = abs( e( m-1 ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+safmin )go to 110
                 end do
              end if
              m = lend
              110 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 130
              ! if remaining matrix is 2-by-2, use stdlib_${ri}$lae2 or stdlib${ii}$_dlaev2
              ! to compute its eigensystem.
              if( m==l-1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_${ri}$laev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
                    work( m ) = c
                    work( n-1+m ) = s
                    call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'F', n, 2_${ik}$, work( m ),work( n-1+m ), z( 1_${ik}$, l-1 ), &
                              ldz )
                 else
                    call stdlib${ii}$_${ri}$lae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
                 end if
                 d( l-1 ) = rt1
                 d( l ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 90
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
              r = stdlib${ii}$_${ri}$lapy2( g, one )
              g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              lm1 = l - 1_${ik}$
              do i = m, lm1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_${ri}$lartg( g, f, c, s, r )
                 if( i/=m )e( i-1 ) = r
                 g = d( i ) - p
                 r = ( d( i+1 )-g )*s + two*c*b
                 p = s*r
                 d( i ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = l - m + 1_${ik}$
                 call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'F', n, mm, work( m ), work( n-1+m ),z( 1_${ik}$, m ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( lm1 ) = g
              go to 90
              ! eigenvalue found.
              130 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 90
              go to 140
           end if
           ! undo scaling if necessary
           140 continue
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           else if( iscale==2_${ik}$ ) then
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           end if
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot<nmaxit )go to 10
           do i = 1, n - 1
              if( e( i )/=zero )info = info + 1_${ik}$
           end do
           go to 190
           ! order eigenvalues and eigenvectors.
           160 continue
           if( icompz==0_${ik}$ ) then
              ! use quick sort
              call stdlib${ii}$_${ri}$lasrt( 'I', n, d, info )
           else
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                 i = ii - 1_${ik}$
                 k = i
                 p = d( i )
                 do j = ii, n
                    if( d( j )<p ) then
                       k = j
                       p = d( j )
                    end if
                 end do
                 if( k/=i ) then
                    d( k ) = d( i )
                    d( i ) = p
                    call stdlib${ii}$_${ri}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                 end if
              end do
           end if
           190 continue
           return
     end subroutine stdlib${ii}$_${ri}$steqr

#:endif
#:endfor

     pure module subroutine stdlib${ii}$_csteqr( compz, n, d, e, z, ldz, work, info )
     !! CSTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the implicit QL or QR method.
     !! The eigenvectors of a full or band complex Hermitian matrix can also
     !! be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this
     !! matrix to tridiagonal form.
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(sp), intent(inout) :: d(*), e(*)
           real(sp), intent(out) :: work(*)
           complex(sp), intent(inout) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, ii, iscale, j, jtot, k, l, l1, lend, lendm1, lendp1, lendsv,&
                      lm1, lsv, m, mm, mm1, nm1, nmaxit
           real(sp) :: anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, s, safmax, safmin, ssfmax, &
                     ssfmin, tst
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'CSTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz==2_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           ! determine the unit roundoff and over/underflow thresholds.
           eps = stdlib${ii}$_slamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_slamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues and eigenvectors of the tridiagonal
           ! matrix.
           if( icompz==2_${ik}$ )call stdlib${ii}$_claset( 'FULL', n, n, czero, cone, z, ldz )
           nmaxit = n*maxit
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           nm1 = n - 1_${ik}$
           10 continue
           if( l1>n )go to 160
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           if( l1<=nm1 ) then
              do m = l1, nm1
                 tst = abs( e( m ) )
                 if( tst==zero )go to 30
                 if( tst<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) then
                    e( m ) = zero
                    go to 30
                 end if
              end do
           end if
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_slanst( 'I', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              40 continue
              if( l/=lend ) then
                 lendm1 = lend - 1_${ik}$
                 do m = l, lendm1
                    tst = abs( e( m ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+safmin )go to 60
                 end do
              end if
              m = lend
              60 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 80
              ! if remaining matrix is 2-by-2, use stdlib_slae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l+1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_slaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
                    work( l ) = c
                    work( n-1+l ) = s
                    call stdlib${ii}$_clasr( 'R', 'V', 'B', n, 2_${ik}$, work( l ),work( n-1+l ), z( 1_${ik}$, l ), &
                              ldz )
                 else
                    call stdlib${ii}$_slae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
                 end if
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 40
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l+1 )-p ) / ( two*e( l ) )
              r = stdlib${ii}$_slapy2( g, one )
              g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              mm1 = m - 1_${ik}$
              do i = mm1, l, -1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_slartg( g, f, c, s, r )
                 if( i/=m-1 )e( i+1 ) = r
                 g = d( i+1 ) - p
                 r = ( d( i )-g )*s + two*c*b
                 p = s*r
                 d( i+1 ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = -s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = m - l + 1_${ik}$
                 call stdlib${ii}$_clasr( 'R', 'V', 'B', n, mm, work( l ), work( n-1+l ),z( 1_${ik}$, l ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( l ) = g
              go to 40
              ! eigenvalue found.
              80 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 40
              go to 140
           else
              ! qr iteration
              ! look for small superdiagonal element.
              90 continue
              if( l/=lend ) then
                 lendp1 = lend + 1_${ik}$
                 do m = l, lendp1, -1
                    tst = abs( e( m-1 ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+safmin )go to 110
                 end do
              end if
              m = lend
              110 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 130
              ! if remaining matrix is 2-by-2, use stdlib_slae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l-1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_slaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
                    work( m ) = c
                    work( n-1+m ) = s
                    call stdlib${ii}$_clasr( 'R', 'V', 'F', n, 2_${ik}$, work( m ),work( n-1+m ), z( 1_${ik}$, l-1 ), &
                              ldz )
                 else
                    call stdlib${ii}$_slae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
                 end if
                 d( l-1 ) = rt1
                 d( l ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 90
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
              r = stdlib${ii}$_slapy2( g, one )
              g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              lm1 = l - 1_${ik}$
              do i = m, lm1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_slartg( g, f, c, s, r )
                 if( i/=m )e( i-1 ) = r
                 g = d( i ) - p
                 r = ( d( i+1 )-g )*s + two*c*b
                 p = s*r
                 d( i ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = l - m + 1_${ik}$
                 call stdlib${ii}$_clasr( 'R', 'V', 'F', n, mm, work( m ), work( n-1+m ),z( 1_${ik}$, m ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( lm1 ) = g
              go to 90
              ! eigenvalue found.
              130 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 90
              go to 140
           end if
           ! undo scaling if necessary
           140 continue
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           else if( iscale==2_${ik}$ ) then
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           end if
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot==nmaxit ) then
              do i = 1, n - 1
                 if( e( i )/=zero )info = info + 1_${ik}$
              end do
              return
           end if
           go to 10
           ! order eigenvalues and eigenvectors.
           160 continue
           if( icompz==0_${ik}$ ) then
              ! use quick sort
              call stdlib${ii}$_slasrt( 'I', n, d, info )
           else
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                 i = ii - 1_${ik}$
                 k = i
                 p = d( i )
                 do j = ii, n
                    if( d( j )<p ) then
                       k = j
                       p = d( j )
                    end if
                 end do
                 if( k/=i ) then
                    d( k ) = d( i )
                    d( i ) = p
                    call stdlib${ii}$_cswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                 end if
              end do
           end if
           return
     end subroutine stdlib${ii}$_csteqr

     pure module subroutine stdlib${ii}$_zsteqr( compz, n, d, e, z, ldz, work, info )
     !! ZSTEQR computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the implicit QL or QR method.
     !! The eigenvectors of a full or band complex Hermitian matrix can also
     !! be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this
     !! matrix to tridiagonal form.
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(dp), intent(inout) :: d(*), e(*)
           real(dp), intent(out) :: work(*)
           complex(dp), intent(inout) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, ii, iscale, j, jtot, k, l, l1, lend, lendm1, lendp1, lendsv,&
                      lm1, lsv, m, mm, mm1, nm1, nmaxit
           real(dp) :: anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, s, safmax, safmin, ssfmax, &
                     ssfmin, tst
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz==2_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           ! determine the unit roundoff and over/underflow thresholds.
           eps = stdlib${ii}$_dlamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_dlamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues and eigenvectors of the tridiagonal
           ! matrix.
           if( icompz==2_${ik}$ )call stdlib${ii}$_zlaset( 'FULL', n, n, czero, cone, z, ldz )
           nmaxit = n*maxit
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           nm1 = n - 1_${ik}$
           10 continue
           if( l1>n )go to 160
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           if( l1<=nm1 ) then
              do m = l1, nm1
                 tst = abs( e( m ) )
                 if( tst==zero )go to 30
                 if( tst<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) then
                    e( m ) = zero
                    go to 30
                 end if
              end do
           end if
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_dlanst( 'I', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              40 continue
              if( l/=lend ) then
                 lendm1 = lend - 1_${ik}$
                 do m = l, lendm1
                    tst = abs( e( m ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+safmin )go to 60
                 end do
              end if
              m = lend
              60 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 80
              ! if remaining matrix is 2-by-2, use stdlib_dlae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l+1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_dlaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
                    work( l ) = c
                    work( n-1+l ) = s
                    call stdlib${ii}$_zlasr( 'R', 'V', 'B', n, 2_${ik}$, work( l ),work( n-1+l ), z( 1_${ik}$, l ), &
                              ldz )
                 else
                    call stdlib${ii}$_dlae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
                 end if
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 40
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l+1 )-p ) / ( two*e( l ) )
              r = stdlib${ii}$_dlapy2( g, one )
              g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              mm1 = m - 1_${ik}$
              do i = mm1, l, -1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_dlartg( g, f, c, s, r )
                 if( i/=m-1 )e( i+1 ) = r
                 g = d( i+1 ) - p
                 r = ( d( i )-g )*s + two*c*b
                 p = s*r
                 d( i+1 ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = -s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = m - l + 1_${ik}$
                 call stdlib${ii}$_zlasr( 'R', 'V', 'B', n, mm, work( l ), work( n-1+l ),z( 1_${ik}$, l ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( l ) = g
              go to 40
              ! eigenvalue found.
              80 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 40
              go to 140
           else
              ! qr iteration
              ! look for small superdiagonal element.
              90 continue
              if( l/=lend ) then
                 lendp1 = lend + 1_${ik}$
                 do m = l, lendp1, -1
                    tst = abs( e( m-1 ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+safmin )go to 110
                 end do
              end if
              m = lend
              110 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 130
              ! if remaining matrix is 2-by-2, use stdlib_dlae2 or stdlib${ii}$_slaev2
              ! to compute its eigensystem.
              if( m==l-1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_dlaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
                    work( m ) = c
                    work( n-1+m ) = s
                    call stdlib${ii}$_zlasr( 'R', 'V', 'F', n, 2_${ik}$, work( m ),work( n-1+m ), z( 1_${ik}$, l-1 ), &
                              ldz )
                 else
                    call stdlib${ii}$_dlae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
                 end if
                 d( l-1 ) = rt1
                 d( l ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 90
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
              r = stdlib${ii}$_dlapy2( g, one )
              g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              lm1 = l - 1_${ik}$
              do i = m, lm1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_dlartg( g, f, c, s, r )
                 if( i/=m )e( i-1 ) = r
                 g = d( i ) - p
                 r = ( d( i+1 )-g )*s + two*c*b
                 p = s*r
                 d( i ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = l - m + 1_${ik}$
                 call stdlib${ii}$_zlasr( 'R', 'V', 'F', n, mm, work( m ), work( n-1+m ),z( 1_${ik}$, m ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( lm1 ) = g
              go to 90
              ! eigenvalue found.
              130 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 90
              go to 140
           end if
           ! undo scaling if necessary
           140 continue
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           else if( iscale==2_${ik}$ ) then
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           end if
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot==nmaxit ) then
              do i = 1, n - 1
                 if( e( i )/=zero )info = info + 1_${ik}$
              end do
              return
           end if
           go to 10
           ! order eigenvalues and eigenvectors.
           160 continue
           if( icompz==0_${ik}$ ) then
              ! use quick sort
              call stdlib${ii}$_dlasrt( 'I', n, d, info )
           else
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                 i = ii - 1_${ik}$
                 k = i
                 p = d( i )
                 do j = ii, n
                    if( d( j )<p ) then
                       k = j
                       p = d( j )
                    end if
                 end do
                 if( k/=i ) then
                    d( k ) = d( i )
                    d( i ) = p
                    call stdlib${ii}$_zswap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                 end if
              end do
           end if
           return
     end subroutine stdlib${ii}$_zsteqr

#:for ck,ct,ci in CMPLX_KINDS_TYPES
#:if not ck in ["sp","dp"]
     pure module subroutine stdlib${ii}$_${ci}$steqr( compz, n, d, e, z, ldz, work, info )
     !! ZSTEQR: computes all eigenvalues and, optionally, eigenvectors of a
     !! symmetric tridiagonal matrix using the implicit QL or QR method.
     !! The eigenvectors of a full or band complex Hermitian matrix can also
     !! be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this
     !! matrix to tridiagonal form.
        ! -- 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 
           character, intent(in) :: compz
           integer(${ik}$), intent(out) :: info
           integer(${ik}$), intent(in) :: ldz, n
           ! Array Arguments 
           real(${ck}$), intent(inout) :: d(*), e(*)
           real(${ck}$), intent(out) :: work(*)
           complex(${ck}$), intent(inout) :: z(ldz,*)
        ! =====================================================================
           ! Parameters 
           integer(${ik}$), parameter :: maxit = 30_${ik}$
           
           
           
           ! Local Scalars 
           integer(${ik}$) :: i, icompz, ii, iscale, j, jtot, k, l, l1, lend, lendm1, lendp1, lendsv,&
                      lm1, lsv, m, mm, mm1, nm1, nmaxit
           real(${ck}$) :: anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, s, safmax, safmin, ssfmax, &
                     ssfmin, tst
           ! Intrinsic Functions 
           ! Executable Statements 
           ! test the input parameters.
           info = 0_${ik}$
           if( stdlib_lsame( compz, 'N' ) ) then
              icompz = 0_${ik}$
           else if( stdlib_lsame( compz, 'V' ) ) then
              icompz = 1_${ik}$
           else if( stdlib_lsame( compz, 'I' ) ) then
              icompz = 2_${ik}$
           else
              icompz = -1_${ik}$
           end if
           if( icompz<0_${ik}$ ) then
              info = -1_${ik}$
           else if( n<0_${ik}$ ) then
              info = -2_${ik}$
           else if( ( ldz<1_${ik}$ ) .or. ( icompz>0_${ik}$ .and. ldz<max( 1_${ik}$,n ) ) ) then
              info = -6_${ik}$
           end if
           if( info/=0_${ik}$ ) then
              call stdlib${ii}$_xerbla( 'ZSTEQR', -info )
              return
           end if
           ! quick return if possible
           if( n==0 )return
           if( n==1_${ik}$ ) then
              if( icompz==2_${ik}$ )z( 1_${ik}$, 1_${ik}$ ) = cone
              return
           end if
           ! determine the unit roundoff and over/underflow thresholds.
           eps = stdlib${ii}$_${c2ri(ci)}$lamch( 'E' )
           eps2 = eps**2_${ik}$
           safmin = stdlib${ii}$_${c2ri(ci)}$lamch( 'S' )
           safmax = one / safmin
           ssfmax = sqrt( safmax ) / three
           ssfmin = sqrt( safmin ) / eps2
           ! compute the eigenvalues and eigenvectors of the tridiagonal
           ! matrix.
           if( icompz==2_${ik}$ )call stdlib${ii}$_${ci}$laset( 'FULL', n, n, czero, cone, z, ldz )
           nmaxit = n*maxit
           jtot = 0_${ik}$
           ! determine where the matrix splits and choose ql or qr iteration
           ! for each block, according to whether top or bottom diagonal
           ! element is smaller.
           l1 = 1_${ik}$
           nm1 = n - 1_${ik}$
           10 continue
           if( l1>n )go to 160
           if( l1>1_${ik}$ )e( l1-1 ) = zero
           if( l1<=nm1 ) then
              do m = l1, nm1
                 tst = abs( e( m ) )
                 if( tst==zero )go to 30
                 if( tst<=( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+1 ) ) ) )*eps ) then
                    e( m ) = zero
                    go to 30
                 end if
              end do
           end if
           m = n
           30 continue
           l = l1
           lsv = l
           lend = m
           lendsv = lend
           l1 = m + 1_${ik}$
           if( lend==l )go to 10
           ! scale submatrix in rows and columns l to lend
           anorm = stdlib${ii}$_${c2ri(ci)}$lanst( 'I', lend-l+1, d( l ), e( l ) )
           iscale = 0_${ik}$
           if( anorm==zero )go to 10
           if( anorm>ssfmax ) then
              iscale = 1_${ik}$
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmax, lend-l, 1_${ik}$, e( l ), n,info )
           else if( anorm<ssfmin ) then
              iscale = 2_${ik}$
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l+1, 1_${ik}$, d( l ), n,info )
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, anorm, ssfmin, lend-l, 1_${ik}$, e( l ), n,info )
           end if
           ! choose between ql and qr iteration
           if( abs( d( lend ) )<abs( d( l ) ) ) then
              lend = lsv
              l = lendsv
           end if
           if( lend>l ) then
              ! ql iteration
              ! look for small subdiagonal element.
              40 continue
              if( l/=lend ) then
                 lendm1 = lend - 1_${ik}$
                 do m = l, lendm1
                    tst = abs( e( m ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+safmin )go to 60
                 end do
              end if
              m = lend
              60 continue
              if( m<lend )e( m ) = zero
              p = d( l )
              if( m==l )go to 80
              ! if remaining matrix is 2-by-2, use stdlib_${c2ri(ci)}$lae2 or stdlib${ii}$_dlaev2
              ! to compute its eigensystem.
              if( m==l+1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_${c2ri(ci)}$laev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
                    work( l ) = c
                    work( n-1+l ) = s
                    call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'B', n, 2_${ik}$, work( l ),work( n-1+l ), z( 1_${ik}$, l ), &
                              ldz )
                 else
                    call stdlib${ii}$_${c2ri(ci)}$lae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
                 end if
                 d( l ) = rt1
                 d( l+1 ) = rt2
                 e( l ) = zero
                 l = l + 2_${ik}$
                 if( l<=lend )go to 40
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l+1 )-p ) / ( two*e( l ) )
              r = stdlib${ii}$_${c2ri(ci)}$lapy2( g, one )
              g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              mm1 = m - 1_${ik}$
              do i = mm1, l, -1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_${c2ri(ci)}$lartg( g, f, c, s, r )
                 if( i/=m-1 )e( i+1 ) = r
                 g = d( i+1 ) - p
                 r = ( d( i )-g )*s + two*c*b
                 p = s*r
                 d( i+1 ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = -s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = m - l + 1_${ik}$
                 call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'B', n, mm, work( l ), work( n-1+l ),z( 1_${ik}$, l ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( l ) = g
              go to 40
              ! eigenvalue found.
              80 continue
              d( l ) = p
              l = l + 1_${ik}$
              if( l<=lend )go to 40
              go to 140
           else
              ! qr iteration
              ! look for small superdiagonal element.
              90 continue
              if( l/=lend ) then
                 lendp1 = lend + 1_${ik}$
                 do m = l, lendp1, -1
                    tst = abs( e( m-1 ) )**2_${ik}$
                    if( tst<=( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+safmin )go to 110
                 end do
              end if
              m = lend
              110 continue
              if( m>lend )e( m-1 ) = zero
              p = d( l )
              if( m==l )go to 130
              ! if remaining matrix is 2-by-2, use stdlib_${c2ri(ci)}$lae2 or stdlib${ii}$_dlaev2
              ! to compute its eigensystem.
              if( m==l-1 ) then
                 if( icompz>0_${ik}$ ) then
                    call stdlib${ii}$_${c2ri(ci)}$laev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
                    work( m ) = c
                    work( n-1+m ) = s
                    call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'F', n, 2_${ik}$, work( m ),work( n-1+m ), z( 1_${ik}$, l-1 ), &
                              ldz )
                 else
                    call stdlib${ii}$_${c2ri(ci)}$lae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
                 end if
                 d( l-1 ) = rt1
                 d( l ) = rt2
                 e( l-1 ) = zero
                 l = l - 2_${ik}$
                 if( l>=lend )go to 90
                 go to 140
              end if
              if( jtot==nmaxit )go to 140
              jtot = jtot + 1_${ik}$
              ! form shift.
              g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
              r = stdlib${ii}$_${c2ri(ci)}$lapy2( g, one )
              g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
              s = one
              c = one
              p = zero
              ! inner loop
              lm1 = l - 1_${ik}$
              do i = m, lm1
                 f = s*e( i )
                 b = c*e( i )
                 call stdlib${ii}$_${c2ri(ci)}$lartg( g, f, c, s, r )
                 if( i/=m )e( i-1 ) = r
                 g = d( i ) - p
                 r = ( d( i+1 )-g )*s + two*c*b
                 p = s*r
                 d( i ) = g + p
                 g = c*r - b
                 ! if eigenvectors are desired, then save rotations.
                 if( icompz>0_${ik}$ ) then
                    work( i ) = c
                    work( n-1+i ) = s
                 end if
              end do
              ! if eigenvectors are desired, then apply saved rotations.
              if( icompz>0_${ik}$ ) then
                 mm = l - m + 1_${ik}$
                 call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'F', n, mm, work( m ), work( n-1+m ),z( 1_${ik}$, m ), ldz &
                           )
              end if
              d( l ) = d( l ) - p
              e( lm1 ) = g
              go to 90
              ! eigenvalue found.
              130 continue
              d( l ) = p
              l = l - 1_${ik}$
              if( l>=lend )go to 90
              go to 140
           end if
           ! undo scaling if necessary
           140 continue
           if( iscale==1_${ik}$ ) then
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmax, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           else if( iscale==2_${ik}$ ) then
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv+1, 1_${ik}$,d( lsv ), n, info )
                        
              call stdlib${ii}$_${c2ri(ci)}$lascl( 'G', 0_${ik}$, 0_${ik}$, ssfmin, anorm, lendsv-lsv, 1_${ik}$, e( lsv ),n, info )
                        
           end if
           ! check for no convergence to an eigenvalue after a total
           ! of n*maxit iterations.
           if( jtot==nmaxit ) then
              do i = 1, n - 1
                 if( e( i )/=zero )info = info + 1_${ik}$
              end do
              return
           end if
           go to 10
           ! order eigenvalues and eigenvectors.
           160 continue
           if( icompz==0_${ik}$ ) then
              ! use quick sort
              call stdlib${ii}$_${c2ri(ci)}$lasrt( 'I', n, d, info )
           else
              ! use selection sort to minimize swaps of eigenvectors
              do ii = 2, n
                 i = ii - 1_${ik}$
                 k = i
                 p = d( i )
                 do j = ii, n
                    if( d( j )<p ) then
                       k = j
                       p = d( j )
                    end if
                 end do
                 if( k/=i ) then
                    d( k ) = d( i )
                    d( i ) = p
                    call stdlib${ii}$_${ci}$swap( n, z( 1_${ik}$, i ), 1_${ik}$, z( 1_${ik}$, k ), 1_${ik}$ )
                 end if
              end do
           end if
           return
     end subroutine stdlib${ii}$_${ci}$steqr

#:endif
#:endfor


#:endfor
end submodule stdlib_lapack_eigv_tridiag3