#:include "common.fypp" submodule(stdlib_lapack_eig_svd_lsq) stdlib_lapack_eigv_svd_drivers3 implicit none contains #:for ik,it,ii in LINALG_INT_KINDS_TYPES pure module subroutine stdlib${ii}$_sbdsqr( uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u,ldu, c, ldc, work, & !! SBDSQR computes the singular values and, optionally, the right and/or !! left singular vectors from the singular value decomposition (SVD) of !! a real N-by-N (upper or lower) bidiagonal matrix B using the implicit !! zero-shift QR algorithm. The SVD of B has the form !! B = Q * S * P**T !! where S is the diagonal matrix of singular values, Q is an orthogonal !! matrix of left singular vectors, and P is an orthogonal matrix of !! right singular vectors. If left singular vectors are requested, this !! subroutine actually returns U*Q instead of Q, and, if right singular !! vectors are requested, this subroutine returns P**T*VT instead of !! P**T, for given real input matrices U and VT. When U and VT are the !! orthogonal matrices that reduce a general matrix A to bidiagonal !! form: A = U*B*VT, as computed by SGEBRD, then !! A = (U*Q) * S * (P**T*VT) !! is the SVD of A. Optionally, the subroutine may also compute Q**T*C !! for a given real input matrix C. !! See "Computing Small Singular Values of Bidiagonal Matrices With !! Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, !! LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, !! no. 5, pp. 873-912, Sept 1990) and !! "Accurate singular values and differential qd algorithms," by !! B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics !! Department, University of California at Berkeley, July 1992 !! for a detailed description of the algorithm. 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) :: uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldc, ldu, ldvt, n, ncc, ncvt, nru ! Array Arguments real(sp), intent(inout) :: c(ldc,*), d(*), e(*), u(ldu,*), vt(ldvt,*) real(sp), intent(out) :: work(*) ! ===================================================================== ! Parameters real(sp), parameter :: hndrth = 0.01_sp real(sp), parameter :: hndrd = 100.0_sp real(sp), parameter :: meigth = -0.125_sp integer(${ik}$), parameter :: maxitr = 6_${ik}$ ! Local Scalars logical(lk) :: lower, rotate integer(${ik}$) :: i, idir, isub, iter, iterdivn, j, ll, lll, m, maxitdivn, nm1, nm12, & nm13, oldll, oldm real(sp) :: abse, abss, cosl, cosr, cs, eps, f, g, h, mu, oldcs, oldsn, r, shift, & sigmn, sigmx, sinl, sinr, sll, smax, smin, sminl, sminoa, sn, thresh, tol, tolmul, & unfl ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ lower = stdlib_lsame( uplo, 'L' ) if( .not.stdlib_lsame( uplo, 'U' ) .and. .not.lower ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ncvt<0_${ik}$ ) then info = -3_${ik}$ else if( nru<0_${ik}$ ) then info = -4_${ik}$ else if( ncc<0_${ik}$ ) then info = -5_${ik}$ else if( ( ncvt==0_${ik}$ .and. ldvt<1_${ik}$ ) .or.( ncvt>0_${ik}$ .and. ldvt<max( 1_${ik}$, n ) ) ) then info = -9_${ik}$ else if( ldu<max( 1_${ik}$, nru ) ) then info = -11_${ik}$ else if( ( ncc==0_${ik}$ .and. ldc<1_${ik}$ ) .or.( ncc>0_${ik}$ .and. ldc<max( 1_${ik}$, n ) ) ) then info = -13_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SBDSQR', -info ) return end if if( n==0 )return if( n==1 )go to 160 ! rotate is true if any singular vectors desired, false otherwise rotate = ( ncvt>0_${ik}$ ) .or. ( nru>0_${ik}$ ) .or. ( ncc>0_${ik}$ ) ! if no singular vectors desired, use qd algorithm if( .not.rotate ) then call stdlib${ii}$_slasq1( n, d, e, work, info ) ! if info equals 2, dqds didn't finish, try to finish if( info /= 2 ) return info = 0_${ik}$ end if nm1 = n - 1_${ik}$ nm12 = nm1 + nm1 nm13 = nm12 + nm1 idir = 0_${ik}$ ! get machine constants eps = stdlib${ii}$_slamch( 'EPSILON' ) unfl = stdlib${ii}$_slamch( 'SAFE MINIMUM' ) ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left if( lower ) then do i = 1, n - 1 call stdlib${ii}$_slartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) work( i ) = cs work( nm1+i ) = sn end do ! update singular vectors if desired if( nru>0_${ik}$ )call stdlib${ii}$_slasr( 'R', 'V', 'F', nru, n, work( 1_${ik}$ ), work( n ), u,ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'F', n, ncc, work( 1_${ik}$ ), work( n ), c,ldc ) end if ! compute singular values to relative accuracy tol ! (by setting tol to be negative, algorithm will compute ! singular values to absolute accuracy abs(tol)*norm(input matrix)) tolmul = max( ten, min( hndrd, eps**meigth ) ) tol = tolmul*eps ! compute approximate maximum, minimum singular values smax = zero do i = 1, n smax = max( smax, abs( d( i ) ) ) end do do i = 1, n - 1 smax = max( smax, abs( e( i ) ) ) end do sminl = zero if( tol>=zero ) then ! relative accuracy desired sminoa = abs( d( 1_${ik}$ ) ) if( sminoa==zero )go to 50 mu = sminoa do i = 2, n mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) ) sminoa = min( sminoa, mu ) if( sminoa==zero )go to 50 end do 50 continue sminoa = sminoa / sqrt( real( n,KIND=sp) ) thresh = max( tol*sminoa, maxitr*(n*(n*unfl)) ) else ! absolute accuracy desired thresh = max( abs( tol )*smax, maxitr*(n*(n*unfl)) ) end if ! prepare for main iteration loop for the singular values ! (maxit is the maximum number of passes through the inner ! loop permitted before nonconvergence signalled.) maxitdivn = maxitr*n iterdivn = 0_${ik}$ iter = -1_${ik}$ oldll = -1_${ik}$ oldm = -1_${ik}$ ! m points to last element of unconverged part of matrix m = n ! begin main iteration loop 60 continue ! check for convergence or exceeding iteration count if( m<=1 )go to 160 if( iter>=n ) then iter = iter - n iterdivn = iterdivn + 1_${ik}$ if( iterdivn>=maxitdivn )go to 200 end if ! find diagonal block of matrix to work on if( tol<zero .and. abs( d( m ) )<=thresh )d( m ) = zero smax = abs( d( m ) ) smin = smax do lll = 1, m - 1 ll = m - lll abss = abs( d( ll ) ) abse = abs( e( ll ) ) if( tol<zero .and. abss<=thresh )d( ll ) = zero if( abse<=thresh )go to 80 smin = min( smin, abss ) smax = max( smax, abss, abse ) end do ll = 0_${ik}$ go to 90 80 continue e( ll ) = zero ! matrix splits since e(ll) = 0 if( ll==m-1 ) then ! convergence of bottom singular value, return to top of loop m = m - 1_${ik}$ go to 60 end if 90 continue ll = ll + 1_${ik}$ ! e(ll) through e(m-1) are nonzero, e(ll-1) is zero if( ll==m-1 ) then ! 2 by 2 block, handle separately call stdlib${ii}$_slasv2( d( m-1 ), e( m-1 ), d( m ), sigmn, sigmx, sinr,cosr, sinl, cosl & ) d( m-1 ) = sigmx e( m-1 ) = zero d( m ) = sigmn ! compute singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_srot( ncvt, vt( m-1, 1_${ik}$ ), ldvt, vt( m, 1_${ik}$ ), ldvt, cosr,sinr & ) if( nru>0_${ik}$ )call stdlib${ii}$_srot( nru, u( 1_${ik}$, m-1 ), 1_${ik}$, u( 1_${ik}$, m ), 1_${ik}$, cosl, sinl ) if( ncc>0_${ik}$ )call stdlib${ii}$_srot( ncc, c( m-1, 1_${ik}$ ), ldc, c( m, 1_${ik}$ ), ldc, cosl,sinl ) m = m - 2_${ik}$ go to 60 end if ! if working on new submatrix, choose shift direction ! (from larger end diagonal element towards smaller) if( ll>oldm .or. m<oldll ) then if( abs( d( ll ) )>=abs( d( m ) ) ) then ! chase bulge from top (big end) to bottom (small end) idir = 1_${ik}$ else ! chase bulge from bottom (big end) to top (small end) idir = 2_${ik}$ end if end if ! apply convergence tests if( idir==1_${ik}$ ) then ! run convergence test in forward direction ! first apply standard test to bottom of matrix if( abs( e( m-1 ) )<=abs( tol )*abs( d( m ) ) .or.( tol<zero .and. abs( e( m-1 ) )& <=thresh ) ) then e( m-1 ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion forward mu = abs( d( ll ) ) sminl = mu do lll = ll, m - 1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll+1 ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if else ! run convergence test in backward direction ! first apply standard test to top of matrix if( abs( e( ll ) )<=abs( tol )*abs( d( ll ) ) .or.( tol<zero .and. abs( e( ll ) )& <=thresh ) ) then e( ll ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion backward mu = abs( d( m ) ) sminl = mu do lll = m - 1, ll, -1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if end if oldll = ll oldm = m ! compute shift. first, test if shifting would ruin relative ! accuracy, and if so set the shift to zero. if( tol>=zero .and. n*tol*( sminl / smax )<=max( eps, hndrth*tol ) ) then ! use a zero shift to avoid loss of relative accuracy shift = zero else ! compute the shift from 2-by-2 block at end of matrix if( idir==1_${ik}$ ) then sll = abs( d( ll ) ) call stdlib${ii}$_slas2( d( m-1 ), e( m-1 ), d( m ), shift, r ) else sll = abs( d( m ) ) call stdlib${ii}$_slas2( d( ll ), e( ll ), d( ll+1 ), shift, r ) end if ! test if shift negligible, and if so set to zero if( sll>zero ) then if( ( shift / sll )**2_${ik}$<eps )shift = zero end if end if ! increment iteration count iter = iter + m - ll ! if shift = 0, do simplified qr iteration if( shift==zero ) then if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = ll, m - 1 call stdlib${ii}$_slartg( d( i )*cs, e( i ), cs, sn, r ) if( i>ll )e( i-1 ) = oldsn*r call stdlib${ii}$_slartg( oldcs*r, d( i+1 )*sn, oldcs, oldsn, d( i ) ) work( i-ll+1 ) = cs work( i-ll+1+nm1 ) = sn work( i-ll+1+nm12 ) = oldcs work( i-ll+1+nm13 ) = oldsn end do h = d( m )*cs d( m ) = h*oldcs e( m-1 ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'F', m-ll+1, ncvt, work( 1_${ik}$ ),work( n ), & vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_slasr( 'R', 'V', 'F', nru, m-ll+1, work( nm12+1 ),work( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'F', m-ll+1, ncc, work( nm12+1 ),work( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = m, ll + 1, -1 call stdlib${ii}$_slartg( d( i )*cs, e( i-1 ), cs, sn, r ) if( i<m )e( i ) = oldsn*r call stdlib${ii}$_slartg( oldcs*r, d( i-1 )*sn, oldcs, oldsn, d( i ) ) work( i-ll ) = cs work( i-ll+nm1 ) = -sn work( i-ll+nm12 ) = oldcs work( i-ll+nm13 ) = -oldsn end do h = d( ll )*cs d( ll ) = h*oldcs e( ll ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'B', m-ll+1, ncvt, work( nm12+1 ),work( & nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_slasr( 'R', 'V', 'B', nru, m-ll+1, work( 1_${ik}$ ),work( n ), u(& 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'B', m-ll+1, ncc, work( 1_${ik}$ ),work( n ), c(& ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero end if else ! use nonzero shift if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates f = ( abs( d( ll ) )-shift )*( sign( one, d( ll ) )+shift / d( ll ) ) g = e( ll ) do i = ll, m - 1 call stdlib${ii}$_slartg( f, g, cosr, sinr, r ) if( i>ll )e( i-1 ) = r f = cosr*d( i ) + sinr*e( i ) e( i ) = cosr*e( i ) - sinr*d( i ) g = sinr*d( i+1 ) d( i+1 ) = cosr*d( i+1 ) call stdlib${ii}$_slartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i ) + sinl*d( i+1 ) d( i+1 ) = cosl*d( i+1 ) - sinl*e( i ) if( i<m-1 ) then g = sinl*e( i+1 ) e( i+1 ) = cosl*e( i+1 ) end if work( i-ll+1 ) = cosr work( i-ll+1+nm1 ) = sinr work( i-ll+1+nm12 ) = cosl work( i-ll+1+nm13 ) = sinl end do e( m-1 ) = f ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'F', m-ll+1, ncvt, work( 1_${ik}$ ),work( n ), & vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_slasr( 'R', 'V', 'F', nru, m-ll+1, work( nm12+1 ),work( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'F', m-ll+1, ncc, work( nm12+1 ),work( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates f = ( abs( d( m ) )-shift )*( sign( one, d( m ) )+shift /d( m ) ) g = e( m-1 ) do i = m, ll + 1, -1 call stdlib${ii}$_slartg( f, g, cosr, sinr, r ) if( i<m )e( i ) = r f = cosr*d( i ) + sinr*e( i-1 ) e( i-1 ) = cosr*e( i-1 ) - sinr*d( i ) g = sinr*d( i-1 ) d( i-1 ) = cosr*d( i-1 ) call stdlib${ii}$_slartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i-1 ) + sinl*d( i-1 ) d( i-1 ) = cosl*d( i-1 ) - sinl*e( i-1 ) if( i>ll+1 ) then g = sinl*e( i-2 ) e( i-2 ) = cosl*e( i-2 ) end if work( i-ll ) = cosr work( i-ll+nm1 ) = -sinr work( i-ll+nm12 ) = cosl work( i-ll+nm13 ) = -sinl end do e( ll ) = f ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero ! update singular vectors if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'B', m-ll+1, ncvt, work( nm12+1 ),work( & nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_slasr( 'R', 'V', 'B', nru, m-ll+1, work( 1_${ik}$ ),work( n ), u(& 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_slasr( 'L', 'V', 'B', m-ll+1, ncc, work( 1_${ik}$ ),work( n ), c(& ll, 1_${ik}$ ), ldc ) end if end if ! qr iteration finished, go back and check convergence go to 60 ! all singular values converged, so make them positive 160 continue do i = 1, n if( d( i )<zero ) then d( i ) = -d( i ) ! change sign of singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_sscal( ncvt, negone, vt( i, 1_${ik}$ ), ldvt ) end if end do ! sort the singular values into decreasing order (insertion sort on ! singular values, but only one transposition per singular vector) do i = 1, n - 1 ! scan for smallest d(i) isub = 1_${ik}$ smin = d( 1_${ik}$ ) do j = 2, n + 1 - i if( d( j )<=smin ) then isub = j smin = d( j ) end if end do if( isub/=n+1-i ) then ! swap singular values and vectors d( isub ) = d( n+1-i ) d( n+1-i ) = smin if( ncvt>0_${ik}$ )call stdlib${ii}$_sswap( ncvt, vt( isub, 1_${ik}$ ), ldvt, vt( n+1-i, 1_${ik}$ ),ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_sswap( nru, u( 1_${ik}$, isub ), 1_${ik}$, u( 1_${ik}$, n+1-i ), 1_${ik}$ ) if( ncc>0_${ik}$ )call stdlib${ii}$_sswap( ncc, c( isub, 1_${ik}$ ), ldc, c( n+1-i, 1_${ik}$ ), ldc ) end if end do go to 220 ! maximum number of iterations exceeded, failure to converge 200 continue info = 0_${ik}$ do i = 1, n - 1 if( e( i )/=zero )info = info + 1_${ik}$ end do 220 continue return end subroutine stdlib${ii}$_sbdsqr pure module subroutine stdlib${ii}$_dbdsqr( uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u,ldu, c, ldc, work, & !! DBDSQR computes the singular values and, optionally, the right and/or !! left singular vectors from the singular value decomposition (SVD) of !! a real N-by-N (upper or lower) bidiagonal matrix B using the implicit !! zero-shift QR algorithm. The SVD of B has the form !! B = Q * S * P**T !! where S is the diagonal matrix of singular values, Q is an orthogonal !! matrix of left singular vectors, and P is an orthogonal matrix of !! right singular vectors. If left singular vectors are requested, this !! subroutine actually returns U*Q instead of Q, and, if right singular !! vectors are requested, this subroutine returns P**T*VT instead of !! P**T, for given real input matrices U and VT. When U and VT are the !! orthogonal matrices that reduce a general matrix A to bidiagonal !! form: A = U*B*VT, as computed by DGEBRD, then !! A = (U*Q) * S * (P**T*VT) !! is the SVD of A. Optionally, the subroutine may also compute Q**T*C !! for a given real input matrix C. !! See "Computing Small Singular Values of Bidiagonal Matrices With !! Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, !! LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, !! no. 5, pp. 873-912, Sept 1990) and !! "Accurate singular values and differential qd algorithms," by !! B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics !! Department, University of California at Berkeley, July 1992 !! for a detailed description of the algorithm. 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) :: uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldc, ldu, ldvt, n, ncc, ncvt, nru ! Array Arguments real(dp), intent(inout) :: c(ldc,*), d(*), e(*), u(ldu,*), vt(ldvt,*) real(dp), intent(out) :: work(*) ! ===================================================================== ! Parameters real(dp), parameter :: hndrth = 0.01_dp real(dp), parameter :: hndrd = 100.0_dp real(dp), parameter :: meigth = -0.125_dp integer(${ik}$), parameter :: maxitr = 6_${ik}$ ! Local Scalars logical(lk) :: lower, rotate integer(${ik}$) :: i, idir, isub, iter, iterdivn, j, ll, lll, m, maxitdivn, nm1, nm12, & nm13, oldll, oldm real(dp) :: abse, abss, cosl, cosr, cs, eps, f, g, h, mu, oldcs, oldsn, r, shift, & sigmn, sigmx, sinl, sinr, sll, smax, smin, sminl, sminoa, sn, thresh, tol, tolmul, & unfl ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ lower = stdlib_lsame( uplo, 'L' ) if( .not.stdlib_lsame( uplo, 'U' ) .and. .not.lower ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ncvt<0_${ik}$ ) then info = -3_${ik}$ else if( nru<0_${ik}$ ) then info = -4_${ik}$ else if( ncc<0_${ik}$ ) then info = -5_${ik}$ else if( ( ncvt==0_${ik}$ .and. ldvt<1_${ik}$ ) .or.( ncvt>0_${ik}$ .and. ldvt<max( 1_${ik}$, n ) ) ) then info = -9_${ik}$ else if( ldu<max( 1_${ik}$, nru ) ) then info = -11_${ik}$ else if( ( ncc==0_${ik}$ .and. ldc<1_${ik}$ ) .or.( ncc>0_${ik}$ .and. ldc<max( 1_${ik}$, n ) ) ) then info = -13_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DBDSQR', -info ) return end if if( n==0 )return if( n==1 )go to 160 ! rotate is true if any singular vectors desired, false otherwise rotate = ( ncvt>0_${ik}$ ) .or. ( nru>0_${ik}$ ) .or. ( ncc>0_${ik}$ ) ! if no singular vectors desired, use qd algorithm if( .not.rotate ) then call stdlib${ii}$_dlasq1( n, d, e, work, info ) ! if info equals 2, dqds didn't finish, try to finish if( info /= 2 ) return info = 0_${ik}$ end if nm1 = n - 1_${ik}$ nm12 = nm1 + nm1 nm13 = nm12 + nm1 idir = 0_${ik}$ ! get machine constants eps = stdlib${ii}$_dlamch( 'EPSILON' ) unfl = stdlib${ii}$_dlamch( 'SAFE MINIMUM' ) ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left if( lower ) then do i = 1, n - 1 call stdlib${ii}$_dlartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) work( i ) = cs work( nm1+i ) = sn end do ! update singular vectors if desired if( nru>0_${ik}$ )call stdlib${ii}$_dlasr( 'R', 'V', 'F', nru, n, work( 1_${ik}$ ), work( n ), u,ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'F', n, ncc, work( 1_${ik}$ ), work( n ), c,ldc ) end if ! compute singular values to relative accuracy tol ! (by setting tol to be negative, algorithm will compute ! singular values to absolute accuracy abs(tol)*norm(input matrix)) tolmul = max( ten, min( hndrd, eps**meigth ) ) tol = tolmul*eps ! compute approximate maximum, minimum singular values smax = zero do i = 1, n smax = max( smax, abs( d( i ) ) ) end do do i = 1, n - 1 smax = max( smax, abs( e( i ) ) ) end do sminl = zero if( tol>=zero ) then ! relative accuracy desired sminoa = abs( d( 1_${ik}$ ) ) if( sminoa==zero )go to 50 mu = sminoa do i = 2, n mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) ) sminoa = min( sminoa, mu ) if( sminoa==zero )go to 50 end do 50 continue sminoa = sminoa / sqrt( real( n,KIND=dp) ) thresh = max( tol*sminoa, maxitr*(n*(n*unfl)) ) else ! absolute accuracy desired thresh = max( abs( tol )*smax, maxitr*(n*(n*unfl)) ) end if ! prepare for main iteration loop for the singular values ! (maxit is the maximum number of passes through the inner ! loop permitted before nonconvergence signalled.) maxitdivn = maxitr*n iterdivn = 0_${ik}$ iter = -1_${ik}$ oldll = -1_${ik}$ oldm = -1_${ik}$ ! m points to last element of unconverged part of matrix m = n ! begin main iteration loop 60 continue ! check for convergence or exceeding iteration count if( m<=1 )go to 160 if( iter>=n ) then iter = iter - n iterdivn = iterdivn + 1_${ik}$ if( iterdivn>=maxitdivn )go to 200 end if ! find diagonal block of matrix to work on if( tol<zero .and. abs( d( m ) )<=thresh )d( m ) = zero smax = abs( d( m ) ) smin = smax do lll = 1, m - 1 ll = m - lll abss = abs( d( ll ) ) abse = abs( e( ll ) ) if( tol<zero .and. abss<=thresh )d( ll ) = zero if( abse<=thresh )go to 80 smin = min( smin, abss ) smax = max( smax, abss, abse ) end do ll = 0_${ik}$ go to 90 80 continue e( ll ) = zero ! matrix splits since e(ll) = 0 if( ll==m-1 ) then ! convergence of bottom singular value, return to top of loop m = m - 1_${ik}$ go to 60 end if 90 continue ll = ll + 1_${ik}$ ! e(ll) through e(m-1) are nonzero, e(ll-1) is zero if( ll==m-1 ) then ! 2 by 2 block, handle separately call stdlib${ii}$_dlasv2( d( m-1 ), e( m-1 ), d( m ), sigmn, sigmx, sinr,cosr, sinl, cosl & ) d( m-1 ) = sigmx e( m-1 ) = zero d( m ) = sigmn ! compute singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_drot( ncvt, vt( m-1, 1_${ik}$ ), ldvt, vt( m, 1_${ik}$ ), ldvt, cosr,sinr & ) if( nru>0_${ik}$ )call stdlib${ii}$_drot( nru, u( 1_${ik}$, m-1 ), 1_${ik}$, u( 1_${ik}$, m ), 1_${ik}$, cosl, sinl ) if( ncc>0_${ik}$ )call stdlib${ii}$_drot( ncc, c( m-1, 1_${ik}$ ), ldc, c( m, 1_${ik}$ ), ldc, cosl,sinl ) m = m - 2_${ik}$ go to 60 end if ! if working on new submatrix, choose shift direction ! (from larger end diagonal element towards smaller) if( ll>oldm .or. m<oldll ) then if( abs( d( ll ) )>=abs( d( m ) ) ) then ! chase bulge from top (big end) to bottom (small end) idir = 1_${ik}$ else ! chase bulge from bottom (big end) to top (small end) idir = 2_${ik}$ end if end if ! apply convergence tests if( idir==1_${ik}$ ) then ! run convergence test in forward direction ! first apply standard test to bottom of matrix if( abs( e( m-1 ) )<=abs( tol )*abs( d( m ) ) .or.( tol<zero .and. abs( e( m-1 ) )& <=thresh ) ) then e( m-1 ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion forward mu = abs( d( ll ) ) sminl = mu do lll = ll, m - 1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll+1 ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if else ! run convergence test in backward direction ! first apply standard test to top of matrix if( abs( e( ll ) )<=abs( tol )*abs( d( ll ) ) .or.( tol<zero .and. abs( e( ll ) )& <=thresh ) ) then e( ll ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion backward mu = abs( d( m ) ) sminl = mu do lll = m - 1, ll, -1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if end if oldll = ll oldm = m ! compute shift. first, test if shifting would ruin relative ! accuracy, and if so set the shift to zero. if( tol>=zero .and. n*tol*( sminl / smax )<=max( eps, hndrth*tol ) ) then ! use a zero shift to avoid loss of relative accuracy shift = zero else ! compute the shift from 2-by-2 block at end of matrix if( idir==1_${ik}$ ) then sll = abs( d( ll ) ) call stdlib${ii}$_dlas2( d( m-1 ), e( m-1 ), d( m ), shift, r ) else sll = abs( d( m ) ) call stdlib${ii}$_dlas2( d( ll ), e( ll ), d( ll+1 ), shift, r ) end if ! test if shift negligible, and if so set to zero if( sll>zero ) then if( ( shift / sll )**2_${ik}$<eps )shift = zero end if end if ! increment iteration count iter = iter + m - ll ! if shift = 0, do simplified qr iteration if( shift==zero ) then if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = ll, m - 1 call stdlib${ii}$_dlartg( d( i )*cs, e( i ), cs, sn, r ) if( i>ll )e( i-1 ) = oldsn*r call stdlib${ii}$_dlartg( oldcs*r, d( i+1 )*sn, oldcs, oldsn, d( i ) ) work( i-ll+1 ) = cs work( i-ll+1+nm1 ) = sn work( i-ll+1+nm12 ) = oldcs work( i-ll+1+nm13 ) = oldsn end do h = d( m )*cs d( m ) = h*oldcs e( m-1 ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'F', m-ll+1, ncvt, work( 1_${ik}$ ),work( n ), & vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_dlasr( 'R', 'V', 'F', nru, m-ll+1, work( nm12+1 ),work( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'F', m-ll+1, ncc, work( nm12+1 ),work( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = m, ll + 1, -1 call stdlib${ii}$_dlartg( d( i )*cs, e( i-1 ), cs, sn, r ) if( i<m )e( i ) = oldsn*r call stdlib${ii}$_dlartg( oldcs*r, d( i-1 )*sn, oldcs, oldsn, d( i ) ) work( i-ll ) = cs work( i-ll+nm1 ) = -sn work( i-ll+nm12 ) = oldcs work( i-ll+nm13 ) = -oldsn end do h = d( ll )*cs d( ll ) = h*oldcs e( ll ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'B', m-ll+1, ncvt, work( nm12+1 ),work( & nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_dlasr( 'R', 'V', 'B', nru, m-ll+1, work( 1_${ik}$ ),work( n ), u(& 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'B', m-ll+1, ncc, work( 1_${ik}$ ),work( n ), c(& ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero end if else ! use nonzero shift if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates f = ( abs( d( ll ) )-shift )*( sign( one, d( ll ) )+shift / d( ll ) ) g = e( ll ) do i = ll, m - 1 call stdlib${ii}$_dlartg( f, g, cosr, sinr, r ) if( i>ll )e( i-1 ) = r f = cosr*d( i ) + sinr*e( i ) e( i ) = cosr*e( i ) - sinr*d( i ) g = sinr*d( i+1 ) d( i+1 ) = cosr*d( i+1 ) call stdlib${ii}$_dlartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i ) + sinl*d( i+1 ) d( i+1 ) = cosl*d( i+1 ) - sinl*e( i ) if( i<m-1 ) then g = sinl*e( i+1 ) e( i+1 ) = cosl*e( i+1 ) end if work( i-ll+1 ) = cosr work( i-ll+1+nm1 ) = sinr work( i-ll+1+nm12 ) = cosl work( i-ll+1+nm13 ) = sinl end do e( m-1 ) = f ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'F', m-ll+1, ncvt, work( 1_${ik}$ ),work( n ), & vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_dlasr( 'R', 'V', 'F', nru, m-ll+1, work( nm12+1 ),work( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'F', m-ll+1, ncc, work( nm12+1 ),work( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates f = ( abs( d( m ) )-shift )*( sign( one, d( m ) )+shift /d( m ) ) g = e( m-1 ) do i = m, ll + 1, -1 call stdlib${ii}$_dlartg( f, g, cosr, sinr, r ) if( i<m )e( i ) = r f = cosr*d( i ) + sinr*e( i-1 ) e( i-1 ) = cosr*e( i-1 ) - sinr*d( i ) g = sinr*d( i-1 ) d( i-1 ) = cosr*d( i-1 ) call stdlib${ii}$_dlartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i-1 ) + sinl*d( i-1 ) d( i-1 ) = cosl*d( i-1 ) - sinl*e( i-1 ) if( i>ll+1 ) then g = sinl*e( i-2 ) e( i-2 ) = cosl*e( i-2 ) end if work( i-ll ) = cosr work( i-ll+nm1 ) = -sinr work( i-ll+nm12 ) = cosl work( i-ll+nm13 ) = -sinl end do e( ll ) = f ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero ! update singular vectors if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'B', m-ll+1, ncvt, work( nm12+1 ),work( & nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_dlasr( 'R', 'V', 'B', nru, m-ll+1, work( 1_${ik}$ ),work( n ), u(& 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_dlasr( 'L', 'V', 'B', m-ll+1, ncc, work( 1_${ik}$ ),work( n ), c(& ll, 1_${ik}$ ), ldc ) end if end if ! qr iteration finished, go back and check convergence go to 60 ! all singular values converged, so make them positive 160 continue do i = 1, n if( d( i )<zero ) then d( i ) = -d( i ) ! change sign of singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_dscal( ncvt, negone, vt( i, 1_${ik}$ ), ldvt ) end if end do ! sort the singular values into decreasing order (insertion sort on ! singular values, but only one transposition per singular vector) do i = 1, n - 1 ! scan for smallest d(i) isub = 1_${ik}$ smin = d( 1_${ik}$ ) do j = 2, n + 1 - i if( d( j )<=smin ) then isub = j smin = d( j ) end if end do if( isub/=n+1-i ) then ! swap singular values and vectors d( isub ) = d( n+1-i ) d( n+1-i ) = smin if( ncvt>0_${ik}$ )call stdlib${ii}$_dswap( ncvt, vt( isub, 1_${ik}$ ), ldvt, vt( n+1-i, 1_${ik}$ ),ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_dswap( nru, u( 1_${ik}$, isub ), 1_${ik}$, u( 1_${ik}$, n+1-i ), 1_${ik}$ ) if( ncc>0_${ik}$ )call stdlib${ii}$_dswap( ncc, c( isub, 1_${ik}$ ), ldc, c( n+1-i, 1_${ik}$ ), ldc ) end if end do go to 220 ! maximum number of iterations exceeded, failure to converge 200 continue info = 0_${ik}$ do i = 1, n - 1 if( e( i )/=zero )info = info + 1_${ik}$ end do 220 continue return end subroutine stdlib${ii}$_dbdsqr #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$bdsqr( uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u,ldu, c, ldc, work, & !! DBDSQR: computes the singular values and, optionally, the right and/or !! left singular vectors from the singular value decomposition (SVD) of !! a real N-by-N (upper or lower) bidiagonal matrix B using the implicit !! zero-shift QR algorithm. The SVD of B has the form !! B = Q * S * P**T !! where S is the diagonal matrix of singular values, Q is an orthogonal !! matrix of left singular vectors, and P is an orthogonal matrix of !! right singular vectors. If left singular vectors are requested, this !! subroutine actually returns U*Q instead of Q, and, if right singular !! vectors are requested, this subroutine returns P**T*VT instead of !! P**T, for given real input matrices U and VT. When U and VT are the !! orthogonal matrices that reduce a general matrix A to bidiagonal !! form: A = U*B*VT, as computed by DGEBRD, then !! A = (U*Q) * S * (P**T*VT) !! is the SVD of A. Optionally, the subroutine may also compute Q**T*C !! for a given real input matrix C. !! See "Computing Small Singular Values of Bidiagonal Matrices With !! Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, !! LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, !! no. 5, pp. 873-912, Sept 1990) and !! "Accurate singular values and differential qd algorithms," by !! B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics !! Department, University of California at Berkeley, July 1992 !! for a detailed description of the algorithm. 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) :: uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldc, ldu, ldvt, n, ncc, ncvt, nru ! Array Arguments real(${rk}$), intent(inout) :: c(ldc,*), d(*), e(*), u(ldu,*), vt(ldvt,*) real(${rk}$), intent(out) :: work(*) ! ===================================================================== ! Parameters real(${rk}$), parameter :: hndrth = 0.01_${rk}$ real(${rk}$), parameter :: hndrd = 100.0_${rk}$ real(${rk}$), parameter :: meigth = -0.125_${rk}$ integer(${ik}$), parameter :: maxitr = 6_${ik}$ ! Local Scalars logical(lk) :: lower, rotate integer(${ik}$) :: i, idir, isub, iter, iterdivn, j, ll, lll, m, maxitdivn, nm1, nm12, & nm13, oldll, oldm real(${rk}$) :: abse, abss, cosl, cosr, cs, eps, f, g, h, mu, oldcs, oldsn, r, shift, & sigmn, sigmx, sinl, sinr, sll, smax, smin, sminl, sminoa, sn, thresh, tol, tolmul, & unfl ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ lower = stdlib_lsame( uplo, 'L' ) if( .not.stdlib_lsame( uplo, 'U' ) .and. .not.lower ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ncvt<0_${ik}$ ) then info = -3_${ik}$ else if( nru<0_${ik}$ ) then info = -4_${ik}$ else if( ncc<0_${ik}$ ) then info = -5_${ik}$ else if( ( ncvt==0_${ik}$ .and. ldvt<1_${ik}$ ) .or.( ncvt>0_${ik}$ .and. ldvt<max( 1_${ik}$, n ) ) ) then info = -9_${ik}$ else if( ldu<max( 1_${ik}$, nru ) ) then info = -11_${ik}$ else if( ( ncc==0_${ik}$ .and. ldc<1_${ik}$ ) .or.( ncc>0_${ik}$ .and. ldc<max( 1_${ik}$, n ) ) ) then info = -13_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DBDSQR', -info ) return end if if( n==0 )return if( n==1 )go to 160 ! rotate is true if any singular vectors desired, false otherwise rotate = ( ncvt>0_${ik}$ ) .or. ( nru>0_${ik}$ ) .or. ( ncc>0_${ik}$ ) ! if no singular vectors desired, use qd algorithm if( .not.rotate ) then call stdlib${ii}$_${ri}$lasq1( n, d, e, work, info ) ! if info equals 2, dqds didn't finish, try to finish if( info /= 2 ) return info = 0_${ik}$ end if nm1 = n - 1_${ik}$ nm12 = nm1 + nm1 nm13 = nm12 + nm1 idir = 0_${ik}$ ! get machine constants eps = stdlib${ii}$_${ri}$lamch( 'EPSILON' ) unfl = stdlib${ii}$_${ri}$lamch( 'SAFE MINIMUM' ) ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left if( lower ) then do i = 1, n - 1 call stdlib${ii}$_${ri}$lartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) work( i ) = cs work( nm1+i ) = sn end do ! update singular vectors if desired if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'F', nru, n, work( 1_${ik}$ ), work( n ), u,ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'F', n, ncc, work( 1_${ik}$ ), work( n ), c,ldc ) end if ! compute singular values to relative accuracy tol ! (by setting tol to be negative, algorithm will compute ! singular values to absolute accuracy abs(tol)*norm(input matrix)) tolmul = max( ten, min( hndrd, eps**meigth ) ) tol = tolmul*eps ! compute approximate maximum, minimum singular values smax = zero do i = 1, n smax = max( smax, abs( d( i ) ) ) end do do i = 1, n - 1 smax = max( smax, abs( e( i ) ) ) end do sminl = zero if( tol>=zero ) then ! relative accuracy desired sminoa = abs( d( 1_${ik}$ ) ) if( sminoa==zero )go to 50 mu = sminoa do i = 2, n mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) ) sminoa = min( sminoa, mu ) if( sminoa==zero )go to 50 end do 50 continue sminoa = sminoa / sqrt( real( n,KIND=${rk}$) ) thresh = max( tol*sminoa, maxitr*(n*(n*unfl)) ) else ! absolute accuracy desired thresh = max( abs( tol )*smax, maxitr*(n*(n*unfl)) ) end if ! prepare for main iteration loop for the singular values ! (maxit is the maximum number of passes through the inner ! loop permitted before nonconvergence signalled.) maxitdivn = maxitr*n iterdivn = 0_${ik}$ iter = -1_${ik}$ oldll = -1_${ik}$ oldm = -1_${ik}$ ! m points to last element of unconverged part of matrix m = n ! begin main iteration loop 60 continue ! check for convergence or exceeding iteration count if( m<=1 )go to 160 if( iter>=n ) then iter = iter - n iterdivn = iterdivn + 1_${ik}$ if( iterdivn>=maxitdivn )go to 200 end if ! find diagonal block of matrix to work on if( tol<zero .and. abs( d( m ) )<=thresh )d( m ) = zero smax = abs( d( m ) ) smin = smax do lll = 1, m - 1 ll = m - lll abss = abs( d( ll ) ) abse = abs( e( ll ) ) if( tol<zero .and. abss<=thresh )d( ll ) = zero if( abse<=thresh )go to 80 smin = min( smin, abss ) smax = max( smax, abss, abse ) end do ll = 0_${ik}$ go to 90 80 continue e( ll ) = zero ! matrix splits since e(ll) = 0 if( ll==m-1 ) then ! convergence of bottom singular value, return to top of loop m = m - 1_${ik}$ go to 60 end if 90 continue ll = ll + 1_${ik}$ ! e(ll) through e(m-1) are nonzero, e(ll-1) is zero if( ll==m-1 ) then ! 2 by 2 block, handle separately call stdlib${ii}$_${ri}$lasv2( d( m-1 ), e( m-1 ), d( m ), sigmn, sigmx, sinr,cosr, sinl, cosl & ) d( m-1 ) = sigmx e( m-1 ) = zero d( m ) = sigmn ! compute singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$rot( ncvt, vt( m-1, 1_${ik}$ ), ldvt, vt( m, 1_${ik}$ ), ldvt, cosr,sinr & ) if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$rot( nru, u( 1_${ik}$, m-1 ), 1_${ik}$, u( 1_${ik}$, m ), 1_${ik}$, cosl, sinl ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$rot( ncc, c( m-1, 1_${ik}$ ), ldc, c( m, 1_${ik}$ ), ldc, cosl,sinl ) m = m - 2_${ik}$ go to 60 end if ! if working on new submatrix, choose shift direction ! (from larger end diagonal element towards smaller) if( ll>oldm .or. m<oldll ) then if( abs( d( ll ) )>=abs( d( m ) ) ) then ! chase bulge from top (big end) to bottom (small end) idir = 1_${ik}$ else ! chase bulge from bottom (big end) to top (small end) idir = 2_${ik}$ end if end if ! apply convergence tests if( idir==1_${ik}$ ) then ! run convergence test in forward direction ! first apply standard test to bottom of matrix if( abs( e( m-1 ) )<=abs( tol )*abs( d( m ) ) .or.( tol<zero .and. abs( e( m-1 ) )& <=thresh ) ) then e( m-1 ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion forward mu = abs( d( ll ) ) sminl = mu do lll = ll, m - 1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll+1 ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if else ! run convergence test in backward direction ! first apply standard test to top of matrix if( abs( e( ll ) )<=abs( tol )*abs( d( ll ) ) .or.( tol<zero .and. abs( e( ll ) )& <=thresh ) ) then e( ll ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion backward mu = abs( d( m ) ) sminl = mu do lll = m - 1, ll, -1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if end if oldll = ll oldm = m ! compute shift. first, test if shifting would ruin relative ! accuracy, and if so set the shift to zero. if( tol>=zero .and. n*tol*( sminl / smax )<=max( eps, hndrth*tol ) ) then ! use a zero shift to avoid loss of relative accuracy shift = zero else ! compute the shift from 2-by-2 block at end of matrix if( idir==1_${ik}$ ) then sll = abs( d( ll ) ) call stdlib${ii}$_${ri}$las2( d( m-1 ), e( m-1 ), d( m ), shift, r ) else sll = abs( d( m ) ) call stdlib${ii}$_${ri}$las2( d( ll ), e( ll ), d( ll+1 ), shift, r ) end if ! test if shift negligible, and if so set to zero if( sll>zero ) then if( ( shift / sll )**2_${ik}$<eps )shift = zero end if end if ! increment iteration count iter = iter + m - ll ! if shift = 0, do simplified qr iteration if( shift==zero ) then if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = ll, m - 1 call stdlib${ii}$_${ri}$lartg( d( i )*cs, e( i ), cs, sn, r ) if( i>ll )e( i-1 ) = oldsn*r call stdlib${ii}$_${ri}$lartg( oldcs*r, d( i+1 )*sn, oldcs, oldsn, d( i ) ) work( i-ll+1 ) = cs work( i-ll+1+nm1 ) = sn work( i-ll+1+nm12 ) = oldcs work( i-ll+1+nm13 ) = oldsn end do h = d( m )*cs d( m ) = h*oldcs e( m-1 ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'F', m-ll+1, ncvt, work( 1_${ik}$ ),work( n ), & vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'F', nru, m-ll+1, work( nm12+1 ),work( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'F', m-ll+1, ncc, work( nm12+1 ),work( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = m, ll + 1, -1 call stdlib${ii}$_${ri}$lartg( d( i )*cs, e( i-1 ), cs, sn, r ) if( i<m )e( i ) = oldsn*r call stdlib${ii}$_${ri}$lartg( oldcs*r, d( i-1 )*sn, oldcs, oldsn, d( i ) ) work( i-ll ) = cs work( i-ll+nm1 ) = -sn work( i-ll+nm12 ) = oldcs work( i-ll+nm13 ) = -oldsn end do h = d( ll )*cs d( ll ) = h*oldcs e( ll ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'B', m-ll+1, ncvt, work( nm12+1 ),work( & nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'B', nru, m-ll+1, work( 1_${ik}$ ),work( n ), u(& 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'B', m-ll+1, ncc, work( 1_${ik}$ ),work( n ), c(& ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero end if else ! use nonzero shift if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates f = ( abs( d( ll ) )-shift )*( sign( one, d( ll ) )+shift / d( ll ) ) g = e( ll ) do i = ll, m - 1 call stdlib${ii}$_${ri}$lartg( f, g, cosr, sinr, r ) if( i>ll )e( i-1 ) = r f = cosr*d( i ) + sinr*e( i ) e( i ) = cosr*e( i ) - sinr*d( i ) g = sinr*d( i+1 ) d( i+1 ) = cosr*d( i+1 ) call stdlib${ii}$_${ri}$lartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i ) + sinl*d( i+1 ) d( i+1 ) = cosl*d( i+1 ) - sinl*e( i ) if( i<m-1 ) then g = sinl*e( i+1 ) e( i+1 ) = cosl*e( i+1 ) end if work( i-ll+1 ) = cosr work( i-ll+1+nm1 ) = sinr work( i-ll+1+nm12 ) = cosl work( i-ll+1+nm13 ) = sinl end do e( m-1 ) = f ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'F', m-ll+1, ncvt, work( 1_${ik}$ ),work( n ), & vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'F', nru, m-ll+1, work( nm12+1 ),work( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'F', m-ll+1, ncc, work( nm12+1 ),work( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates f = ( abs( d( m ) )-shift )*( sign( one, d( m ) )+shift /d( m ) ) g = e( m-1 ) do i = m, ll + 1, -1 call stdlib${ii}$_${ri}$lartg( f, g, cosr, sinr, r ) if( i<m )e( i ) = r f = cosr*d( i ) + sinr*e( i-1 ) e( i-1 ) = cosr*e( i-1 ) - sinr*d( i ) g = sinr*d( i-1 ) d( i-1 ) = cosr*d( i-1 ) call stdlib${ii}$_${ri}$lartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i-1 ) + sinl*d( i-1 ) d( i-1 ) = cosl*d( i-1 ) - sinl*e( i-1 ) if( i>ll+1 ) then g = sinl*e( i-2 ) e( i-2 ) = cosl*e( i-2 ) end if work( i-ll ) = cosr work( i-ll+nm1 ) = -sinr work( i-ll+nm12 ) = cosl work( i-ll+nm13 ) = -sinl end do e( ll ) = f ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero ! update singular vectors if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'B', m-ll+1, ncvt, work( nm12+1 ),work( & nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'R', 'V', 'B', nru, m-ll+1, work( 1_${ik}$ ),work( n ), u(& 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'B', m-ll+1, ncc, work( 1_${ik}$ ),work( n ), c(& ll, 1_${ik}$ ), ldc ) end if end if ! qr iteration finished, go back and check convergence go to 60 ! all singular values converged, so make them positive 160 continue do i = 1, n if( d( i )<zero ) then d( i ) = -d( i ) ! change sign of singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$scal( ncvt, negone, vt( i, 1_${ik}$ ), ldvt ) end if end do ! sort the singular values into decreasing order (insertion sort on ! singular values, but only one transposition per singular vector) do i = 1, n - 1 ! scan for smallest d(i) isub = 1_${ik}$ smin = d( 1_${ik}$ ) do j = 2, n + 1 - i if( d( j )<=smin ) then isub = j smin = d( j ) end if end do if( isub/=n+1-i ) then ! swap singular values and vectors d( isub ) = d( n+1-i ) d( n+1-i ) = smin if( ncvt>0_${ik}$ )call stdlib${ii}$_${ri}$swap( ncvt, vt( isub, 1_${ik}$ ), ldvt, vt( n+1-i, 1_${ik}$ ),ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ri}$swap( nru, u( 1_${ik}$, isub ), 1_${ik}$, u( 1_${ik}$, n+1-i ), 1_${ik}$ ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ri}$swap( ncc, c( isub, 1_${ik}$ ), ldc, c( n+1-i, 1_${ik}$ ), ldc ) end if end do go to 220 ! maximum number of iterations exceeded, failure to converge 200 continue info = 0_${ik}$ do i = 1, n - 1 if( e( i )/=zero )info = info + 1_${ik}$ end do 220 continue return end subroutine stdlib${ii}$_${ri}$bdsqr #:endif #:endfor pure module subroutine stdlib${ii}$_cbdsqr( uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u,ldu, c, ldc, rwork,& !! CBDSQR computes the singular values and, optionally, the right and/or !! left singular vectors from the singular value decomposition (SVD) of !! a real N-by-N (upper or lower) bidiagonal matrix B using the implicit !! zero-shift QR algorithm. The SVD of B has the form !! B = Q * S * P**H !! where S is the diagonal matrix of singular values, Q is an orthogonal !! matrix of left singular vectors, and P is an orthogonal matrix of !! right singular vectors. If left singular vectors are requested, this !! subroutine actually returns U*Q instead of Q, and, if right singular !! vectors are requested, this subroutine returns P**H*VT instead of !! P**H, for given complex input matrices U and VT. When U and VT are !! the unitary matrices that reduce a general matrix A to bidiagonal !! form: A = U*B*VT, as computed by CGEBRD, then !! A = (U*Q) * S * (P**H*VT) !! is the SVD of A. Optionally, the subroutine may also compute Q**H*C !! for a given complex input matrix C. !! See "Computing Small Singular Values of Bidiagonal Matrices With !! Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, !! LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, !! no. 5, pp. 873-912, Sept 1990) and !! "Accurate singular values and differential qd algorithms," by !! B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics !! Department, University of California at Berkeley, July 1992 !! for a detailed description of the algorithm. 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) :: uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldc, ldu, ldvt, n, ncc, ncvt, nru ! Array Arguments real(sp), intent(inout) :: d(*), e(*) real(sp), intent(out) :: rwork(*) complex(sp), intent(inout) :: c(ldc,*), u(ldu,*), vt(ldvt,*) ! ===================================================================== ! Parameters real(sp), parameter :: hndrth = 0.01_sp real(sp), parameter :: hndrd = 100.0_sp real(sp), parameter :: meigth = -0.125_sp integer(${ik}$), parameter :: maxitr = 6_${ik}$ ! Local Scalars logical(lk) :: lower, rotate integer(${ik}$) :: i, idir, isub, iter, j, ll, lll, m, maxit, nm1, nm12, nm13, oldll, & oldm real(sp) :: abse, abss, cosl, cosr, cs, eps, f, g, h, mu, oldcs, oldsn, r, shift, & sigmn, sigmx, sinl, sinr, sll, smax, smin, sminl, sminoa, sn, thresh, tol, tolmul, & unfl ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ lower = stdlib_lsame( uplo, 'L' ) if( .not.stdlib_lsame( uplo, 'U' ) .and. .not.lower ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ncvt<0_${ik}$ ) then info = -3_${ik}$ else if( nru<0_${ik}$ ) then info = -4_${ik}$ else if( ncc<0_${ik}$ ) then info = -5_${ik}$ else if( ( ncvt==0_${ik}$ .and. ldvt<1_${ik}$ ) .or.( ncvt>0_${ik}$ .and. ldvt<max( 1_${ik}$, n ) ) ) then info = -9_${ik}$ else if( ldu<max( 1_${ik}$, nru ) ) then info = -11_${ik}$ else if( ( ncc==0_${ik}$ .and. ldc<1_${ik}$ ) .or.( ncc>0_${ik}$ .and. ldc<max( 1_${ik}$, n ) ) ) then info = -13_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'CBDSQR', -info ) return end if if( n==0 )return if( n==1 )go to 160 ! rotate is true if any singular vectors desired, false otherwise rotate = ( ncvt>0_${ik}$ ) .or. ( nru>0_${ik}$ ) .or. ( ncc>0_${ik}$ ) ! if no singular vectors desired, use qd algorithm if( .not.rotate ) then call stdlib${ii}$_slasq1( n, d, e, rwork, info ) ! if info equals 2, dqds didn't finish, try to finish if( info /= 2 ) return info = 0_${ik}$ end if nm1 = n - 1_${ik}$ nm12 = nm1 + nm1 nm13 = nm12 + nm1 idir = 0_${ik}$ ! get machine constants eps = stdlib${ii}$_slamch( 'EPSILON' ) unfl = stdlib${ii}$_slamch( 'SAFE MINIMUM' ) ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left if( lower ) then do i = 1, n - 1 call stdlib${ii}$_slartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) rwork( i ) = cs rwork( nm1+i ) = sn end do ! update singular vectors if desired if( nru>0_${ik}$ )call stdlib${ii}$_clasr( 'R', 'V', 'F', nru, n, rwork( 1_${ik}$ ), rwork( n ),u, ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'F', n, ncc, rwork( 1_${ik}$ ), rwork( n ),c, ldc ) end if ! compute singular values to relative accuracy tol ! (by setting tol to be negative, algorithm will compute ! singular values to absolute accuracy abs(tol)*norm(input matrix)) tolmul = max( ten, min( hndrd, eps**meigth ) ) tol = tolmul*eps ! compute approximate maximum, minimum singular values smax = zero do i = 1, n smax = max( smax, abs( d( i ) ) ) end do do i = 1, n - 1 smax = max( smax, abs( e( i ) ) ) end do sminl = zero if( tol>=zero ) then ! relative accuracy desired sminoa = abs( d( 1_${ik}$ ) ) if( sminoa==zero )go to 50 mu = sminoa do i = 2, n mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) ) sminoa = min( sminoa, mu ) if( sminoa==zero )go to 50 end do 50 continue sminoa = sminoa / sqrt( real( n,KIND=sp) ) thresh = max( tol*sminoa, maxitr*n*n*unfl ) else ! absolute accuracy desired thresh = max( abs( tol )*smax, maxitr*n*n*unfl ) end if ! prepare for main iteration loop for the singular values ! (maxit is the maximum number of passes through the inner ! loop permitted before nonconvergence signalled.) maxit = maxitr*n*n iter = 0_${ik}$ oldll = -1_${ik}$ oldm = -1_${ik}$ ! m points to last element of unconverged part of matrix m = n ! begin main iteration loop 60 continue ! check for convergence or exceeding iteration count if( m<=1 )go to 160 if( iter>maxit )go to 200 ! find diagonal block of matrix to work on if( tol<zero .and. abs( d( m ) )<=thresh )d( m ) = zero smax = abs( d( m ) ) smin = smax do lll = 1, m - 1 ll = m - lll abss = abs( d( ll ) ) abse = abs( e( ll ) ) if( tol<zero .and. abss<=thresh )d( ll ) = zero if( abse<=thresh )go to 80 smin = min( smin, abss ) smax = max( smax, abss, abse ) end do ll = 0_${ik}$ go to 90 80 continue e( ll ) = zero ! matrix splits since e(ll) = 0 if( ll==m-1 ) then ! convergence of bottom singular value, return to top of loop m = m - 1_${ik}$ go to 60 end if 90 continue ll = ll + 1_${ik}$ ! e(ll) through e(m-1) are nonzero, e(ll-1) is zero if( ll==m-1 ) then ! 2 by 2 block, handle separately call stdlib${ii}$_slasv2( d( m-1 ), e( m-1 ), d( m ), sigmn, sigmx, sinr,cosr, sinl, cosl & ) d( m-1 ) = sigmx e( m-1 ) = zero d( m ) = sigmn ! compute singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_csrot( ncvt, vt( m-1, 1_${ik}$ ), ldvt, vt( m, 1_${ik}$ ), ldvt,cosr, & sinr ) if( nru>0_${ik}$ )call stdlib${ii}$_csrot( nru, u( 1_${ik}$, m-1 ), 1_${ik}$, u( 1_${ik}$, m ), 1_${ik}$, cosl, sinl ) if( ncc>0_${ik}$ )call stdlib${ii}$_csrot( ncc, c( m-1, 1_${ik}$ ), ldc, c( m, 1_${ik}$ ), ldc, cosl,sinl ) m = m - 2_${ik}$ go to 60 end if ! if working on new submatrix, choose shift direction ! (from larger end diagonal element towards smaller) if( ll>oldm .or. m<oldll ) then if( abs( d( ll ) )>=abs( d( m ) ) ) then ! chase bulge from top (big end) to bottom (small end) idir = 1_${ik}$ else ! chase bulge from bottom (big end) to top (small end) idir = 2_${ik}$ end if end if ! apply convergence tests if( idir==1_${ik}$ ) then ! run convergence test in forward direction ! first apply standard test to bottom of matrix if( abs( e( m-1 ) )<=abs( tol )*abs( d( m ) ) .or.( tol<zero .and. abs( e( m-1 ) )& <=thresh ) ) then e( m-1 ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion forward mu = abs( d( ll ) ) sminl = mu do lll = ll, m - 1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll+1 ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if else ! run convergence test in backward direction ! first apply standard test to top of matrix if( abs( e( ll ) )<=abs( tol )*abs( d( ll ) ) .or.( tol<zero .and. abs( e( ll ) )& <=thresh ) ) then e( ll ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion backward mu = abs( d( m ) ) sminl = mu do lll = m - 1, ll, -1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if end if oldll = ll oldm = m ! compute shift. first, test if shifting would ruin relative ! accuracy, and if so set the shift to zero. if( tol>=zero .and. n*tol*( sminl / smax )<=max( eps, hndrth*tol ) ) then ! use a zero shift to avoid loss of relative accuracy shift = zero else ! compute the shift from 2-by-2 block at end of matrix if( idir==1_${ik}$ ) then sll = abs( d( ll ) ) call stdlib${ii}$_slas2( d( m-1 ), e( m-1 ), d( m ), shift, r ) else sll = abs( d( m ) ) call stdlib${ii}$_slas2( d( ll ), e( ll ), d( ll+1 ), shift, r ) end if ! test if shift negligible, and if so set to zero if( sll>zero ) then if( ( shift / sll )**2_${ik}$<eps )shift = zero end if end if ! increment iteration count iter = iter + m - ll ! if shift = 0, do simplified qr iteration if( shift==zero ) then if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = ll, m - 1 call stdlib${ii}$_slartg( d( i )*cs, e( i ), cs, sn, r ) if( i>ll )e( i-1 ) = oldsn*r call stdlib${ii}$_slartg( oldcs*r, d( i+1 )*sn, oldcs, oldsn, d( i ) ) rwork( i-ll+1 ) = cs rwork( i-ll+1+nm1 ) = sn rwork( i-ll+1+nm12 ) = oldcs rwork( i-ll+1+nm13 ) = oldsn end do h = d( m )*cs d( m ) = h*oldcs e( m-1 ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'F', m-ll+1, ncvt, rwork( 1_${ik}$ ),rwork( n )& , vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_clasr( 'R', 'V', 'F', nru, m-ll+1, rwork( nm12+1 ),rwork( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'F', m-ll+1, ncc, rwork( nm12+1 ),rwork( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = m, ll + 1, -1 call stdlib${ii}$_slartg( d( i )*cs, e( i-1 ), cs, sn, r ) if( i<m )e( i ) = oldsn*r call stdlib${ii}$_slartg( oldcs*r, d( i-1 )*sn, oldcs, oldsn, d( i ) ) rwork( i-ll ) = cs rwork( i-ll+nm1 ) = -sn rwork( i-ll+nm12 ) = oldcs rwork( i-ll+nm13 ) = -oldsn end do h = d( ll )*cs d( ll ) = h*oldcs e( ll ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'B', m-ll+1, ncvt, rwork( nm12+1 ),& rwork( nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_clasr( 'R', 'V', 'B', nru, m-ll+1, rwork( 1_${ik}$ ),rwork( n ), & u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'B', m-ll+1, ncc, rwork( 1_${ik}$ ),rwork( n ), & c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero end if else ! use nonzero shift if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates f = ( abs( d( ll ) )-shift )*( sign( one, d( ll ) )+shift / d( ll ) ) g = e( ll ) do i = ll, m - 1 call stdlib${ii}$_slartg( f, g, cosr, sinr, r ) if( i>ll )e( i-1 ) = r f = cosr*d( i ) + sinr*e( i ) e( i ) = cosr*e( i ) - sinr*d( i ) g = sinr*d( i+1 ) d( i+1 ) = cosr*d( i+1 ) call stdlib${ii}$_slartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i ) + sinl*d( i+1 ) d( i+1 ) = cosl*d( i+1 ) - sinl*e( i ) if( i<m-1 ) then g = sinl*e( i+1 ) e( i+1 ) = cosl*e( i+1 ) end if rwork( i-ll+1 ) = cosr rwork( i-ll+1+nm1 ) = sinr rwork( i-ll+1+nm12 ) = cosl rwork( i-ll+1+nm13 ) = sinl end do e( m-1 ) = f ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'F', m-ll+1, ncvt, rwork( 1_${ik}$ ),rwork( n )& , vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_clasr( 'R', 'V', 'F', nru, m-ll+1, rwork( nm12+1 ),rwork( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'F', m-ll+1, ncc, rwork( nm12+1 ),rwork( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates f = ( abs( d( m ) )-shift )*( sign( one, d( m ) )+shift /d( m ) ) g = e( m-1 ) do i = m, ll + 1, -1 call stdlib${ii}$_slartg( f, g, cosr, sinr, r ) if( i<m )e( i ) = r f = cosr*d( i ) + sinr*e( i-1 ) e( i-1 ) = cosr*e( i-1 ) - sinr*d( i ) g = sinr*d( i-1 ) d( i-1 ) = cosr*d( i-1 ) call stdlib${ii}$_slartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i-1 ) + sinl*d( i-1 ) d( i-1 ) = cosl*d( i-1 ) - sinl*e( i-1 ) if( i>ll+1 ) then g = sinl*e( i-2 ) e( i-2 ) = cosl*e( i-2 ) end if rwork( i-ll ) = cosr rwork( i-ll+nm1 ) = -sinr rwork( i-ll+nm12 ) = cosl rwork( i-ll+nm13 ) = -sinl end do e( ll ) = f ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero ! update singular vectors if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'B', m-ll+1, ncvt, rwork( nm12+1 ),& rwork( nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_clasr( 'R', 'V', 'B', nru, m-ll+1, rwork( 1_${ik}$ ),rwork( n ), & u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_clasr( 'L', 'V', 'B', m-ll+1, ncc, rwork( 1_${ik}$ ),rwork( n ), & c( ll, 1_${ik}$ ), ldc ) end if end if ! qr iteration finished, go back and check convergence go to 60 ! all singular values converged, so make them positive 160 continue do i = 1, n if( d( i )<zero ) then d( i ) = -d( i ) ! change sign of singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_csscal( ncvt, negone, vt( i, 1_${ik}$ ), ldvt ) end if end do ! sort the singular values into decreasing order (insertion sort on ! singular values, but only one transposition per singular vector) do i = 1, n - 1 ! scan for smallest d(i) isub = 1_${ik}$ smin = d( 1_${ik}$ ) do j = 2, n + 1 - i if( d( j )<=smin ) then isub = j smin = d( j ) end if end do if( isub/=n+1-i ) then ! swap singular values and vectors d( isub ) = d( n+1-i ) d( n+1-i ) = smin if( ncvt>0_${ik}$ )call stdlib${ii}$_cswap( ncvt, vt( isub, 1_${ik}$ ), ldvt, vt( n+1-i, 1_${ik}$ ),ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_cswap( nru, u( 1_${ik}$, isub ), 1_${ik}$, u( 1_${ik}$, n+1-i ), 1_${ik}$ ) if( ncc>0_${ik}$ )call stdlib${ii}$_cswap( ncc, c( isub, 1_${ik}$ ), ldc, c( n+1-i, 1_${ik}$ ), ldc ) end if end do go to 220 ! maximum number of iterations exceeded, failure to converge 200 continue info = 0_${ik}$ do i = 1, n - 1 if( e( i )/=zero )info = info + 1_${ik}$ end do 220 continue return end subroutine stdlib${ii}$_cbdsqr pure module subroutine stdlib${ii}$_zbdsqr( uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u,ldu, c, ldc, rwork,& !! ZBDSQR computes the singular values and, optionally, the right and/or !! left singular vectors from the singular value decomposition (SVD) of !! a real N-by-N (upper or lower) bidiagonal matrix B using the implicit !! zero-shift QR algorithm. The SVD of B has the form !! B = Q * S * P**H !! where S is the diagonal matrix of singular values, Q is an orthogonal !! matrix of left singular vectors, and P is an orthogonal matrix of !! right singular vectors. If left singular vectors are requested, this !! subroutine actually returns U*Q instead of Q, and, if right singular !! vectors are requested, this subroutine returns P**H*VT instead of !! P**H, for given complex input matrices U and VT. When U and VT are !! the unitary matrices that reduce a general matrix A to bidiagonal !! form: A = U*B*VT, as computed by ZGEBRD, then !! A = (U*Q) * S * (P**H*VT) !! is the SVD of A. Optionally, the subroutine may also compute Q**H*C !! for a given complex input matrix C. !! See "Computing Small Singular Values of Bidiagonal Matrices With !! Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, !! LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, !! no. 5, pp. 873-912, Sept 1990) and !! "Accurate singular values and differential qd algorithms," by !! B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics !! Department, University of California at Berkeley, July 1992 !! for a detailed description of the algorithm. 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) :: uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldc, ldu, ldvt, n, ncc, ncvt, nru ! Array Arguments real(dp), intent(inout) :: d(*), e(*) real(dp), intent(out) :: rwork(*) complex(dp), intent(inout) :: c(ldc,*), u(ldu,*), vt(ldvt,*) ! ===================================================================== ! Parameters real(dp), parameter :: hndrth = 0.01_dp real(dp), parameter :: hndrd = 100.0_dp real(dp), parameter :: meigth = -0.125_dp integer(${ik}$), parameter :: maxitr = 6_${ik}$ ! Local Scalars logical(lk) :: lower, rotate integer(${ik}$) :: i, idir, isub, iter, j, ll, lll, m, maxit, nm1, nm12, nm13, oldll, & oldm real(dp) :: abse, abss, cosl, cosr, cs, eps, f, g, h, mu, oldcs, oldsn, r, shift, & sigmn, sigmx, sinl, sinr, sll, smax, smin, sminl, sminoa, sn, thresh, tol, tolmul, & unfl ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ lower = stdlib_lsame( uplo, 'L' ) if( .not.stdlib_lsame( uplo, 'U' ) .and. .not.lower ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ncvt<0_${ik}$ ) then info = -3_${ik}$ else if( nru<0_${ik}$ ) then info = -4_${ik}$ else if( ncc<0_${ik}$ ) then info = -5_${ik}$ else if( ( ncvt==0_${ik}$ .and. ldvt<1_${ik}$ ) .or.( ncvt>0_${ik}$ .and. ldvt<max( 1_${ik}$, n ) ) ) then info = -9_${ik}$ else if( ldu<max( 1_${ik}$, nru ) ) then info = -11_${ik}$ else if( ( ncc==0_${ik}$ .and. ldc<1_${ik}$ ) .or.( ncc>0_${ik}$ .and. ldc<max( 1_${ik}$, n ) ) ) then info = -13_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZBDSQR', -info ) return end if if( n==0 )return if( n==1 )go to 160 ! rotate is true if any singular vectors desired, false otherwise rotate = ( ncvt>0_${ik}$ ) .or. ( nru>0_${ik}$ ) .or. ( ncc>0_${ik}$ ) ! if no singular vectors desired, use qd algorithm if( .not.rotate ) then call stdlib${ii}$_dlasq1( n, d, e, rwork, info ) ! if info equals 2, dqds didn't finish, try to finish if( info /= 2 ) return info = 0_${ik}$ end if nm1 = n - 1_${ik}$ nm12 = nm1 + nm1 nm13 = nm12 + nm1 idir = 0_${ik}$ ! get machine constants eps = stdlib${ii}$_dlamch( 'EPSILON' ) unfl = stdlib${ii}$_dlamch( 'SAFE MINIMUM' ) ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left if( lower ) then do i = 1, n - 1 call stdlib${ii}$_dlartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) rwork( i ) = cs rwork( nm1+i ) = sn end do ! update singular vectors if desired if( nru>0_${ik}$ )call stdlib${ii}$_zlasr( 'R', 'V', 'F', nru, n, rwork( 1_${ik}$ ), rwork( n ),u, ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'F', n, ncc, rwork( 1_${ik}$ ), rwork( n ),c, ldc ) end if ! compute singular values to relative accuracy tol ! (by setting tol to be negative, algorithm will compute ! singular values to absolute accuracy abs(tol)*norm(input matrix)) tolmul = max( ten, min( hndrd, eps**meigth ) ) tol = tolmul*eps ! compute approximate maximum, minimum singular values smax = zero do i = 1, n smax = max( smax, abs( d( i ) ) ) end do do i = 1, n - 1 smax = max( smax, abs( e( i ) ) ) end do sminl = zero if( tol>=zero ) then ! relative accuracy desired sminoa = abs( d( 1_${ik}$ ) ) if( sminoa==zero )go to 50 mu = sminoa do i = 2, n mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) ) sminoa = min( sminoa, mu ) if( sminoa==zero )go to 50 end do 50 continue sminoa = sminoa / sqrt( real( n,KIND=dp) ) thresh = max( tol*sminoa, maxitr*n*n*unfl ) else ! absolute accuracy desired thresh = max( abs( tol )*smax, maxitr*n*n*unfl ) end if ! prepare for main iteration loop for the singular values ! (maxit is the maximum number of passes through the inner ! loop permitted before nonconvergence signalled.) maxit = maxitr*n*n iter = 0_${ik}$ oldll = -1_${ik}$ oldm = -1_${ik}$ ! m points to last element of unconverged part of matrix m = n ! begin main iteration loop 60 continue ! check for convergence or exceeding iteration count if( m<=1 )go to 160 if( iter>maxit )go to 200 ! find diagonal block of matrix to work on if( tol<zero .and. abs( d( m ) )<=thresh )d( m ) = zero smax = abs( d( m ) ) smin = smax do lll = 1, m - 1 ll = m - lll abss = abs( d( ll ) ) abse = abs( e( ll ) ) if( tol<zero .and. abss<=thresh )d( ll ) = zero if( abse<=thresh )go to 80 smin = min( smin, abss ) smax = max( smax, abss, abse ) end do ll = 0_${ik}$ go to 90 80 continue e( ll ) = zero ! matrix splits since e(ll) = 0 if( ll==m-1 ) then ! convergence of bottom singular value, return to top of loop m = m - 1_${ik}$ go to 60 end if 90 continue ll = ll + 1_${ik}$ ! e(ll) through e(m-1) are nonzero, e(ll-1) is zero if( ll==m-1 ) then ! 2 by 2 block, handle separately call stdlib${ii}$_dlasv2( d( m-1 ), e( m-1 ), d( m ), sigmn, sigmx, sinr,cosr, sinl, cosl & ) d( m-1 ) = sigmx e( m-1 ) = zero d( m ) = sigmn ! compute singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_zdrot( ncvt, vt( m-1, 1_${ik}$ ), ldvt, vt( m, 1_${ik}$ ), ldvt,cosr, & sinr ) if( nru>0_${ik}$ )call stdlib${ii}$_zdrot( nru, u( 1_${ik}$, m-1 ), 1_${ik}$, u( 1_${ik}$, m ), 1_${ik}$, cosl, sinl ) if( ncc>0_${ik}$ )call stdlib${ii}$_zdrot( ncc, c( m-1, 1_${ik}$ ), ldc, c( m, 1_${ik}$ ), ldc, cosl,sinl ) m = m - 2_${ik}$ go to 60 end if ! if working on new submatrix, choose shift direction ! (from larger end diagonal element towards smaller) if( ll>oldm .or. m<oldll ) then if( abs( d( ll ) )>=abs( d( m ) ) ) then ! chase bulge from top (big end) to bottom (small end) idir = 1_${ik}$ else ! chase bulge from bottom (big end) to top (small end) idir = 2_${ik}$ end if end if ! apply convergence tests if( idir==1_${ik}$ ) then ! run convergence test in forward direction ! first apply standard test to bottom of matrix if( abs( e( m-1 ) )<=abs( tol )*abs( d( m ) ) .or.( tol<zero .and. abs( e( m-1 ) )& <=thresh ) ) then e( m-1 ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion forward mu = abs( d( ll ) ) sminl = mu do lll = ll, m - 1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll+1 ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if else ! run convergence test in backward direction ! first apply standard test to top of matrix if( abs( e( ll ) )<=abs( tol )*abs( d( ll ) ) .or.( tol<zero .and. abs( e( ll ) )& <=thresh ) ) then e( ll ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion backward mu = abs( d( m ) ) sminl = mu do lll = m - 1, ll, -1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if end if oldll = ll oldm = m ! compute shift. first, test if shifting would ruin relative ! accuracy, and if so set the shift to zero. if( tol>=zero .and. n*tol*( sminl / smax )<=max( eps, hndrth*tol ) ) then ! use a zero shift to avoid loss of relative accuracy shift = zero else ! compute the shift from 2-by-2 block at end of matrix if( idir==1_${ik}$ ) then sll = abs( d( ll ) ) call stdlib${ii}$_dlas2( d( m-1 ), e( m-1 ), d( m ), shift, r ) else sll = abs( d( m ) ) call stdlib${ii}$_dlas2( d( ll ), e( ll ), d( ll+1 ), shift, r ) end if ! test if shift negligible, and if so set to zero if( sll>zero ) then if( ( shift / sll )**2_${ik}$<eps )shift = zero end if end if ! increment iteration count iter = iter + m - ll ! if shift = 0, do simplified qr iteration if( shift==zero ) then if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = ll, m - 1 call stdlib${ii}$_dlartg( d( i )*cs, e( i ), cs, sn, r ) if( i>ll )e( i-1 ) = oldsn*r call stdlib${ii}$_dlartg( oldcs*r, d( i+1 )*sn, oldcs, oldsn, d( i ) ) rwork( i-ll+1 ) = cs rwork( i-ll+1+nm1 ) = sn rwork( i-ll+1+nm12 ) = oldcs rwork( i-ll+1+nm13 ) = oldsn end do h = d( m )*cs d( m ) = h*oldcs e( m-1 ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'F', m-ll+1, ncvt, rwork( 1_${ik}$ ),rwork( n )& , vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_zlasr( 'R', 'V', 'F', nru, m-ll+1, rwork( nm12+1 ),rwork( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'F', m-ll+1, ncc, rwork( nm12+1 ),rwork( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = m, ll + 1, -1 call stdlib${ii}$_dlartg( d( i )*cs, e( i-1 ), cs, sn, r ) if( i<m )e( i ) = oldsn*r call stdlib${ii}$_dlartg( oldcs*r, d( i-1 )*sn, oldcs, oldsn, d( i ) ) rwork( i-ll ) = cs rwork( i-ll+nm1 ) = -sn rwork( i-ll+nm12 ) = oldcs rwork( i-ll+nm13 ) = -oldsn end do h = d( ll )*cs d( ll ) = h*oldcs e( ll ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'B', m-ll+1, ncvt, rwork( nm12+1 ),& rwork( nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_zlasr( 'R', 'V', 'B', nru, m-ll+1, rwork( 1_${ik}$ ),rwork( n ), & u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'B', m-ll+1, ncc, rwork( 1_${ik}$ ),rwork( n ), & c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero end if else ! use nonzero shift if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates f = ( abs( d( ll ) )-shift )*( sign( one, d( ll ) )+shift / d( ll ) ) g = e( ll ) do i = ll, m - 1 call stdlib${ii}$_dlartg( f, g, cosr, sinr, r ) if( i>ll )e( i-1 ) = r f = cosr*d( i ) + sinr*e( i ) e( i ) = cosr*e( i ) - sinr*d( i ) g = sinr*d( i+1 ) d( i+1 ) = cosr*d( i+1 ) call stdlib${ii}$_dlartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i ) + sinl*d( i+1 ) d( i+1 ) = cosl*d( i+1 ) - sinl*e( i ) if( i<m-1 ) then g = sinl*e( i+1 ) e( i+1 ) = cosl*e( i+1 ) end if rwork( i-ll+1 ) = cosr rwork( i-ll+1+nm1 ) = sinr rwork( i-ll+1+nm12 ) = cosl rwork( i-ll+1+nm13 ) = sinl end do e( m-1 ) = f ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'F', m-ll+1, ncvt, rwork( 1_${ik}$ ),rwork( n )& , vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_zlasr( 'R', 'V', 'F', nru, m-ll+1, rwork( nm12+1 ),rwork( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'F', m-ll+1, ncc, rwork( nm12+1 ),rwork( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates f = ( abs( d( m ) )-shift )*( sign( one, d( m ) )+shift /d( m ) ) g = e( m-1 ) do i = m, ll + 1, -1 call stdlib${ii}$_dlartg( f, g, cosr, sinr, r ) if( i<m )e( i ) = r f = cosr*d( i ) + sinr*e( i-1 ) e( i-1 ) = cosr*e( i-1 ) - sinr*d( i ) g = sinr*d( i-1 ) d( i-1 ) = cosr*d( i-1 ) call stdlib${ii}$_dlartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i-1 ) + sinl*d( i-1 ) d( i-1 ) = cosl*d( i-1 ) - sinl*e( i-1 ) if( i>ll+1 ) then g = sinl*e( i-2 ) e( i-2 ) = cosl*e( i-2 ) end if rwork( i-ll ) = cosr rwork( i-ll+nm1 ) = -sinr rwork( i-ll+nm12 ) = cosl rwork( i-ll+nm13 ) = -sinl end do e( ll ) = f ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero ! update singular vectors if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'B', m-ll+1, ncvt, rwork( nm12+1 ),& rwork( nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_zlasr( 'R', 'V', 'B', nru, m-ll+1, rwork( 1_${ik}$ ),rwork( n ), & u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_zlasr( 'L', 'V', 'B', m-ll+1, ncc, rwork( 1_${ik}$ ),rwork( n ), & c( ll, 1_${ik}$ ), ldc ) end if end if ! qr iteration finished, go back and check convergence go to 60 ! all singular values converged, so make them positive 160 continue do i = 1, n if( d( i )<zero ) then d( i ) = -d( i ) ! change sign of singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_zdscal( ncvt, negone, vt( i, 1_${ik}$ ), ldvt ) end if end do ! sort the singular values into decreasing order (insertion sort on ! singular values, but only one transposition per singular vector) do i = 1, n - 1 ! scan for smallest d(i) isub = 1_${ik}$ smin = d( 1_${ik}$ ) do j = 2, n + 1 - i if( d( j )<=smin ) then isub = j smin = d( j ) end if end do if( isub/=n+1-i ) then ! swap singular values and vectors d( isub ) = d( n+1-i ) d( n+1-i ) = smin if( ncvt>0_${ik}$ )call stdlib${ii}$_zswap( ncvt, vt( isub, 1_${ik}$ ), ldvt, vt( n+1-i, 1_${ik}$ ),ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_zswap( nru, u( 1_${ik}$, isub ), 1_${ik}$, u( 1_${ik}$, n+1-i ), 1_${ik}$ ) if( ncc>0_${ik}$ )call stdlib${ii}$_zswap( ncc, c( isub, 1_${ik}$ ), ldc, c( n+1-i, 1_${ik}$ ), ldc ) end if end do go to 220 ! maximum number of iterations exceeded, failure to converge 200 continue info = 0_${ik}$ do i = 1, n - 1 if( e( i )/=zero )info = info + 1_${ik}$ end do 220 continue return end subroutine stdlib${ii}$_zbdsqr #:for ck,ct,ci in CMPLX_KINDS_TYPES #:if not ck in ["sp","dp"] pure module subroutine stdlib${ii}$_${ci}$bdsqr( uplo, n, ncvt, nru, ncc, d, e, vt, ldvt, u,ldu, c, ldc, rwork,& !! ZBDSQR: computes the singular values and, optionally, the right and/or !! left singular vectors from the singular value decomposition (SVD) of !! a real N-by-N (upper or lower) bidiagonal matrix B using the implicit !! zero-shift QR algorithm. The SVD of B has the form !! B = Q * S * P**H !! where S is the diagonal matrix of singular values, Q is an orthogonal !! matrix of left singular vectors, and P is an orthogonal matrix of !! right singular vectors. If left singular vectors are requested, this !! subroutine actually returns U*Q instead of Q, and, if right singular !! vectors are requested, this subroutine returns P**H*VT instead of !! P**H, for given complex input matrices U and VT. When U and VT are !! the unitary matrices that reduce a general matrix A to bidiagonal !! form: A = U*B*VT, as computed by ZGEBRD, then !! A = (U*Q) * S * (P**H*VT) !! is the SVD of A. Optionally, the subroutine may also compute Q**H*C !! for a given complex input matrix C. !! See "Computing Small Singular Values of Bidiagonal Matrices With !! Guaranteed High Relative Accuracy," by J. Demmel and W. Kahan, !! LAPACK Working Note #3 (or SIAM J. Sci. Statist. Comput. vol. 11, !! no. 5, pp. 873-912, Sept 1990) and !! "Accurate singular values and differential qd algorithms," by !! B. Parlett and V. Fernando, Technical Report CPAM-554, Mathematics !! Department, University of California at Berkeley, July 1992 !! for a detailed description of the algorithm. 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) :: uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldc, ldu, ldvt, n, ncc, ncvt, nru ! Array Arguments real(${ck}$), intent(inout) :: d(*), e(*) real(${ck}$), intent(out) :: rwork(*) complex(${ck}$), intent(inout) :: c(ldc,*), u(ldu,*), vt(ldvt,*) ! ===================================================================== ! Parameters real(${ck}$), parameter :: hndrth = 0.01_${ck}$ real(${ck}$), parameter :: hndrd = 100.0_${ck}$ real(${ck}$), parameter :: meigth = -0.125_${ck}$ integer(${ik}$), parameter :: maxitr = 6_${ik}$ ! Local Scalars logical(lk) :: lower, rotate integer(${ik}$) :: i, idir, isub, iter, j, ll, lll, m, maxit, nm1, nm12, nm13, oldll, & oldm real(${ck}$) :: abse, abss, cosl, cosr, cs, eps, f, g, h, mu, oldcs, oldsn, r, shift, & sigmn, sigmx, sinl, sinr, sll, smax, smin, sminl, sminoa, sn, thresh, tol, tolmul, & unfl ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ lower = stdlib_lsame( uplo, 'L' ) if( .not.stdlib_lsame( uplo, 'U' ) .and. .not.lower ) then info = -1_${ik}$ else if( n<0_${ik}$ ) then info = -2_${ik}$ else if( ncvt<0_${ik}$ ) then info = -3_${ik}$ else if( nru<0_${ik}$ ) then info = -4_${ik}$ else if( ncc<0_${ik}$ ) then info = -5_${ik}$ else if( ( ncvt==0_${ik}$ .and. ldvt<1_${ik}$ ) .or.( ncvt>0_${ik}$ .and. ldvt<max( 1_${ik}$, n ) ) ) then info = -9_${ik}$ else if( ldu<max( 1_${ik}$, nru ) ) then info = -11_${ik}$ else if( ( ncc==0_${ik}$ .and. ldc<1_${ik}$ ) .or.( ncc>0_${ik}$ .and. ldc<max( 1_${ik}$, n ) ) ) then info = -13_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'ZBDSQR', -info ) return end if if( n==0 )return if( n==1 )go to 160 ! rotate is true if any singular vectors desired, false otherwise rotate = ( ncvt>0_${ik}$ ) .or. ( nru>0_${ik}$ ) .or. ( ncc>0_${ik}$ ) ! if no singular vectors desired, use qd algorithm if( .not.rotate ) then call stdlib${ii}$_${c2ri(ci)}$lasq1( n, d, e, rwork, info ) ! if info equals 2, dqds didn't finish, try to finish if( info /= 2 ) return info = 0_${ik}$ end if nm1 = n - 1_${ik}$ nm12 = nm1 + nm1 nm13 = nm12 + nm1 idir = 0_${ik}$ ! get machine constants eps = stdlib${ii}$_${c2ri(ci)}$lamch( 'EPSILON' ) unfl = stdlib${ii}$_${c2ri(ci)}$lamch( 'SAFE MINIMUM' ) ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left if( lower ) then do i = 1, n - 1 call stdlib${ii}$_${c2ri(ci)}$lartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) rwork( i ) = cs rwork( nm1+i ) = sn end do ! update singular vectors if desired if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'F', nru, n, rwork( 1_${ik}$ ), rwork( n ),u, ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'F', n, ncc, rwork( 1_${ik}$ ), rwork( n ),c, ldc ) end if ! compute singular values to relative accuracy tol ! (by setting tol to be negative, algorithm will compute ! singular values to absolute accuracy abs(tol)*norm(input matrix)) tolmul = max( ten, min( hndrd, eps**meigth ) ) tol = tolmul*eps ! compute approximate maximum, minimum singular values smax = zero do i = 1, n smax = max( smax, abs( d( i ) ) ) end do do i = 1, n - 1 smax = max( smax, abs( e( i ) ) ) end do sminl = zero if( tol>=zero ) then ! relative accuracy desired sminoa = abs( d( 1_${ik}$ ) ) if( sminoa==zero )go to 50 mu = sminoa do i = 2, n mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) ) sminoa = min( sminoa, mu ) if( sminoa==zero )go to 50 end do 50 continue sminoa = sminoa / sqrt( real( n,KIND=${ck}$) ) thresh = max( tol*sminoa, maxitr*n*n*unfl ) else ! absolute accuracy desired thresh = max( abs( tol )*smax, maxitr*n*n*unfl ) end if ! prepare for main iteration loop for the singular values ! (maxit is the maximum number of passes through the inner ! loop permitted before nonconvergence signalled.) maxit = maxitr*n*n iter = 0_${ik}$ oldll = -1_${ik}$ oldm = -1_${ik}$ ! m points to last element of unconverged part of matrix m = n ! begin main iteration loop 60 continue ! check for convergence or exceeding iteration count if( m<=1 )go to 160 if( iter>maxit )go to 200 ! find diagonal block of matrix to work on if( tol<zero .and. abs( d( m ) )<=thresh )d( m ) = zero smax = abs( d( m ) ) smin = smax do lll = 1, m - 1 ll = m - lll abss = abs( d( ll ) ) abse = abs( e( ll ) ) if( tol<zero .and. abss<=thresh )d( ll ) = zero if( abse<=thresh )go to 80 smin = min( smin, abss ) smax = max( smax, abss, abse ) end do ll = 0_${ik}$ go to 90 80 continue e( ll ) = zero ! matrix splits since e(ll) = 0 if( ll==m-1 ) then ! convergence of bottom singular value, return to top of loop m = m - 1_${ik}$ go to 60 end if 90 continue ll = ll + 1_${ik}$ ! e(ll) through e(m-1) are nonzero, e(ll-1) is zero if( ll==m-1 ) then ! 2 by 2 block, handle separately call stdlib${ii}$_${c2ri(ci)}$lasv2( d( m-1 ), e( m-1 ), d( m ), sigmn, sigmx, sinr,cosr, sinl, cosl & ) d( m-1 ) = sigmx e( m-1 ) = zero d( m ) = sigmn ! compute singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$drot( ncvt, vt( m-1, 1_${ik}$ ), ldvt, vt( m, 1_${ik}$ ), ldvt,cosr, & sinr ) if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$drot( nru, u( 1_${ik}$, m-1 ), 1_${ik}$, u( 1_${ik}$, m ), 1_${ik}$, cosl, sinl ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$drot( ncc, c( m-1, 1_${ik}$ ), ldc, c( m, 1_${ik}$ ), ldc, cosl,sinl ) m = m - 2_${ik}$ go to 60 end if ! if working on new submatrix, choose shift direction ! (from larger end diagonal element towards smaller) if( ll>oldm .or. m<oldll ) then if( abs( d( ll ) )>=abs( d( m ) ) ) then ! chase bulge from top (big end) to bottom (small end) idir = 1_${ik}$ else ! chase bulge from bottom (big end) to top (small end) idir = 2_${ik}$ end if end if ! apply convergence tests if( idir==1_${ik}$ ) then ! run convergence test in forward direction ! first apply standard test to bottom of matrix if( abs( e( m-1 ) )<=abs( tol )*abs( d( m ) ) .or.( tol<zero .and. abs( e( m-1 ) )& <=thresh ) ) then e( m-1 ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion forward mu = abs( d( ll ) ) sminl = mu do lll = ll, m - 1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll+1 ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if else ! run convergence test in backward direction ! first apply standard test to top of matrix if( abs( e( ll ) )<=abs( tol )*abs( d( ll ) ) .or.( tol<zero .and. abs( e( ll ) )& <=thresh ) ) then e( ll ) = zero go to 60 end if if( tol>=zero ) then ! if relative accuracy desired, ! apply convergence criterion backward mu = abs( d( m ) ) sminl = mu do lll = m - 1, ll, -1 if( abs( e( lll ) )<=tol*mu ) then e( lll ) = zero go to 60 end if mu = abs( d( lll ) )*( mu / ( mu+abs( e( lll ) ) ) ) sminl = min( sminl, mu ) end do end if end if oldll = ll oldm = m ! compute shift. first, test if shifting would ruin relative ! accuracy, and if so set the shift to zero. if( tol>=zero .and. n*tol*( sminl / smax )<=max( eps, hndrth*tol ) ) then ! use a zero shift to avoid loss of relative accuracy shift = zero else ! compute the shift from 2-by-2 block at end of matrix if( idir==1_${ik}$ ) then sll = abs( d( ll ) ) call stdlib${ii}$_${c2ri(ci)}$las2( d( m-1 ), e( m-1 ), d( m ), shift, r ) else sll = abs( d( m ) ) call stdlib${ii}$_${c2ri(ci)}$las2( d( ll ), e( ll ), d( ll+1 ), shift, r ) end if ! test if shift negligible, and if so set to zero if( sll>zero ) then if( ( shift / sll )**2_${ik}$<eps )shift = zero end if end if ! increment iteration count iter = iter + m - ll ! if shift = 0, do simplified qr iteration if( shift==zero ) then if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = ll, m - 1 call stdlib${ii}$_${c2ri(ci)}$lartg( d( i )*cs, e( i ), cs, sn, r ) if( i>ll )e( i-1 ) = oldsn*r call stdlib${ii}$_${c2ri(ci)}$lartg( oldcs*r, d( i+1 )*sn, oldcs, oldsn, d( i ) ) rwork( i-ll+1 ) = cs rwork( i-ll+1+nm1 ) = sn rwork( i-ll+1+nm12 ) = oldcs rwork( i-ll+1+nm13 ) = oldsn end do h = d( m )*cs d( m ) = h*oldcs e( m-1 ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'F', m-ll+1, ncvt, rwork( 1_${ik}$ ),rwork( n )& , vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'F', nru, m-ll+1, rwork( nm12+1 ),rwork( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'F', m-ll+1, ncc, rwork( nm12+1 ),rwork( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates cs = one oldcs = one do i = m, ll + 1, -1 call stdlib${ii}$_${c2ri(ci)}$lartg( d( i )*cs, e( i-1 ), cs, sn, r ) if( i<m )e( i ) = oldsn*r call stdlib${ii}$_${c2ri(ci)}$lartg( oldcs*r, d( i-1 )*sn, oldcs, oldsn, d( i ) ) rwork( i-ll ) = cs rwork( i-ll+nm1 ) = -sn rwork( i-ll+nm12 ) = oldcs rwork( i-ll+nm13 ) = -oldsn end do h = d( ll )*cs d( ll ) = h*oldcs e( ll ) = h*oldsn ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'B', m-ll+1, ncvt, rwork( nm12+1 ),& rwork( nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'B', nru, m-ll+1, rwork( 1_${ik}$ ),rwork( n ), & u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'B', m-ll+1, ncc, rwork( 1_${ik}$ ),rwork( n ), & c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero end if else ! use nonzero shift if( idir==1_${ik}$ ) then ! chase bulge from top to bottom ! save cosines and sines for later singular vector updates f = ( abs( d( ll ) )-shift )*( sign( one, d( ll ) )+shift / d( ll ) ) g = e( ll ) do i = ll, m - 1 call stdlib${ii}$_${c2ri(ci)}$lartg( f, g, cosr, sinr, r ) if( i>ll )e( i-1 ) = r f = cosr*d( i ) + sinr*e( i ) e( i ) = cosr*e( i ) - sinr*d( i ) g = sinr*d( i+1 ) d( i+1 ) = cosr*d( i+1 ) call stdlib${ii}$_${c2ri(ci)}$lartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i ) + sinl*d( i+1 ) d( i+1 ) = cosl*d( i+1 ) - sinl*e( i ) if( i<m-1 ) then g = sinl*e( i+1 ) e( i+1 ) = cosl*e( i+1 ) end if rwork( i-ll+1 ) = cosr rwork( i-ll+1+nm1 ) = sinr rwork( i-ll+1+nm12 ) = cosl rwork( i-ll+1+nm13 ) = sinl end do e( m-1 ) = f ! update singular vectors if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'F', m-ll+1, ncvt, rwork( 1_${ik}$ ),rwork( n )& , vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'F', nru, m-ll+1, rwork( nm12+1 ),rwork( & nm13+1 ), u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'F', m-ll+1, ncc, rwork( nm12+1 ),rwork( & nm13+1 ), c( ll, 1_${ik}$ ), ldc ) ! test convergence if( abs( e( m-1 ) )<=thresh )e( m-1 ) = zero else ! chase bulge from bottom to top ! save cosines and sines for later singular vector updates f = ( abs( d( m ) )-shift )*( sign( one, d( m ) )+shift /d( m ) ) g = e( m-1 ) do i = m, ll + 1, -1 call stdlib${ii}$_${c2ri(ci)}$lartg( f, g, cosr, sinr, r ) if( i<m )e( i ) = r f = cosr*d( i ) + sinr*e( i-1 ) e( i-1 ) = cosr*e( i-1 ) - sinr*d( i ) g = sinr*d( i-1 ) d( i-1 ) = cosr*d( i-1 ) call stdlib${ii}$_${c2ri(ci)}$lartg( f, g, cosl, sinl, r ) d( i ) = r f = cosl*e( i-1 ) + sinl*d( i-1 ) d( i-1 ) = cosl*d( i-1 ) - sinl*e( i-1 ) if( i>ll+1 ) then g = sinl*e( i-2 ) e( i-2 ) = cosl*e( i-2 ) end if rwork( i-ll ) = cosr rwork( i-ll+nm1 ) = -sinr rwork( i-ll+nm12 ) = cosl rwork( i-ll+nm13 ) = -sinl end do e( ll ) = f ! test convergence if( abs( e( ll ) )<=thresh )e( ll ) = zero ! update singular vectors if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'B', m-ll+1, ncvt, rwork( nm12+1 ),& rwork( nm13+1 ), vt( ll, 1_${ik}$ ), ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'R', 'V', 'B', nru, m-ll+1, rwork( 1_${ik}$ ),rwork( n ), & u( 1_${ik}$, ll ), ldu ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$lasr( 'L', 'V', 'B', m-ll+1, ncc, rwork( 1_${ik}$ ),rwork( n ), & c( ll, 1_${ik}$ ), ldc ) end if end if ! qr iteration finished, go back and check convergence go to 60 ! all singular values converged, so make them positive 160 continue do i = 1, n if( d( i )<zero ) then d( i ) = -d( i ) ! change sign of singular vectors, if desired if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$dscal( ncvt, negone, vt( i, 1_${ik}$ ), ldvt ) end if end do ! sort the singular values into decreasing order (insertion sort on ! singular values, but only one transposition per singular vector) do i = 1, n - 1 ! scan for smallest d(i) isub = 1_${ik}$ smin = d( 1_${ik}$ ) do j = 2, n + 1 - i if( d( j )<=smin ) then isub = j smin = d( j ) end if end do if( isub/=n+1-i ) then ! swap singular values and vectors d( isub ) = d( n+1-i ) d( n+1-i ) = smin if( ncvt>0_${ik}$ )call stdlib${ii}$_${ci}$swap( ncvt, vt( isub, 1_${ik}$ ), ldvt, vt( n+1-i, 1_${ik}$ ),ldvt ) if( nru>0_${ik}$ )call stdlib${ii}$_${ci}$swap( nru, u( 1_${ik}$, isub ), 1_${ik}$, u( 1_${ik}$, n+1-i ), 1_${ik}$ ) if( ncc>0_${ik}$ )call stdlib${ii}$_${ci}$swap( ncc, c( isub, 1_${ik}$ ), ldc, c( n+1-i, 1_${ik}$ ), ldc ) end if end do go to 220 ! maximum number of iterations exceeded, failure to converge 200 continue info = 0_${ik}$ do i = 1, n - 1 if( e( i )/=zero )info = info + 1_${ik}$ end do 220 continue return end subroutine stdlib${ii}$_${ci}$bdsqr #:endif #:endfor pure module subroutine stdlib${ii}$_sbdsdc( uplo, compq, n, d, e, u, ldu, vt, ldvt, q, iq,work, iwork, & !! SBDSDC computes the singular value decomposition (SVD) of a real !! N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, !! using a divide and conquer method, where S is a diagonal matrix !! with non-negative diagonal elements (the singular values of B), and !! U and VT are orthogonal matrices of left and right singular vectors, !! respectively. SBDSDC can be used to compute all singular values, !! and optionally, singular vectors or singular vectors in compact 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 SLASD3 for details. !! The code currently calls SLASDQ if singular values only are desired. !! However, it can be slightly modified to compute singular values !! using the divide and conquer method. 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) :: compq, uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldu, ldvt, n ! Array Arguments integer(${ik}$), intent(out) :: iq(*), iwork(*) real(sp), intent(inout) :: d(*), e(*) real(sp), intent(out) :: q(*), u(ldu,*), vt(ldvt,*), work(*) ! ===================================================================== ! changed dimension statement in comment describing e from (n) to ! (n-1). sven, 17 feb 05. ! ===================================================================== ! Local Scalars integer(${ik}$) :: difl, difr, givcol, givnum, givptr, i, ic, icompq, ierr, ii, is, iu, & iuplo, ivt, j, k, kk, mlvl, nm1, nsize, perm, poles, qstart, smlsiz, smlszp, sqre, & start, wstart, z real(sp) :: cs, eps, orgnrm, p, r, sn ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ iuplo = 0_${ik}$ if( stdlib_lsame( uplo, 'U' ) )iuplo = 1_${ik}$ if( stdlib_lsame( uplo, 'L' ) )iuplo = 2_${ik}$ if( stdlib_lsame( compq, 'N' ) ) then icompq = 0_${ik}$ else if( stdlib_lsame( compq, 'P' ) ) then icompq = 1_${ik}$ else if( stdlib_lsame( compq, 'I' ) ) then icompq = 2_${ik}$ else icompq = -1_${ik}$ end if if( iuplo==0_${ik}$ ) then info = -1_${ik}$ else if( icompq<0_${ik}$ ) then info = -2_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( ( ldu<1_${ik}$ ) .or. ( ( icompq==2_${ik}$ ) .and. ( ldu<n ) ) ) then info = -7_${ik}$ else if( ( ldvt<1_${ik}$ ) .or. ( ( icompq==2_${ik}$ ) .and. ( ldvt<n ) ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'SBDSDC', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'SBDSDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) if( n==1_${ik}$ ) then if( icompq==1_${ik}$ ) then q( 1_${ik}$ ) = sign( one, d( 1_${ik}$ ) ) q( 1_${ik}$+smlsiz*n ) = one else if( icompq==2_${ik}$ ) then u( 1_${ik}$, 1_${ik}$ ) = sign( one, d( 1_${ik}$ ) ) vt( 1_${ik}$, 1_${ik}$ ) = one end if d( 1_${ik}$ ) = abs( d( 1_${ik}$ ) ) return end if nm1 = n - 1_${ik}$ ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left wstart = 1_${ik}$ qstart = 3_${ik}$ if( icompq==1_${ik}$ ) then call stdlib${ii}$_scopy( n, d, 1_${ik}$, q( 1_${ik}$ ), 1_${ik}$ ) call stdlib${ii}$_scopy( n-1, e, 1_${ik}$, q( n+1 ), 1_${ik}$ ) end if if( iuplo==2_${ik}$ ) then qstart = 5_${ik}$ if( icompq == 2_${ik}$ ) wstart = 2_${ik}$*n - 1_${ik}$ do i = 1, n - 1 call stdlib${ii}$_slartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) if( icompq==1_${ik}$ ) then q( i+2*n ) = cs q( i+3*n ) = sn else if( icompq==2_${ik}$ ) then work( i ) = cs work( nm1+i ) = -sn end if end do end if ! if icompq = 0, use stdlib_slasdq to compute the singular values. if( icompq==0_${ik}$ ) then ! ignore wstart, instead using work( 1 ), since the two vectors ! for cs and -sn above are added only if icompq == 2, ! and adding them exceeds documented work size of 4*n. call stdlib${ii}$_slasdq( 'U', 0_${ik}$, n, 0_${ik}$, 0_${ik}$, 0_${ik}$, d, e, vt, ldvt, u, ldu, u,ldu, work( 1_${ik}$ ), & info ) go to 40 end if ! if n is smaller than the minimum divide size smlsiz, then solve ! the problem with another solver. if( n<=smlsiz ) then if( icompq==2_${ik}$ ) then call stdlib${ii}$_slaset( 'A', n, n, zero, one, u, ldu ) call stdlib${ii}$_slaset( 'A', n, n, zero, one, vt, ldvt ) call stdlib${ii}$_slasdq( 'U', 0_${ik}$, n, n, n, 0_${ik}$, d, e, vt, ldvt, u, ldu, u,ldu, work( & wstart ), info ) else if( icompq==1_${ik}$ ) then iu = 1_${ik}$ ivt = iu + n call stdlib${ii}$_slaset( 'A', n, n, zero, one, q( iu+( qstart-1 )*n ),n ) call stdlib${ii}$_slaset( 'A', n, n, zero, one, q( ivt+( qstart-1 )*n ),n ) call stdlib${ii}$_slasdq( 'U', 0_${ik}$, n, n, n, 0_${ik}$, d, e,q( ivt+( qstart-1 )*n ), n,q( iu+( & qstart-1 )*n ), n,q( iu+( qstart-1 )*n ), n, work( wstart ),info ) end if go to 40 end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_slaset( 'A', n, n, zero, one, u, ldu ) call stdlib${ii}$_slaset( 'A', n, n, zero, one, vt, ldvt ) end if ! scale. orgnrm = stdlib${ii}$_slanst( 'M', n, d, e ) if( orgnrm==zero )return call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, n, 1_${ik}$, d, n, ierr ) call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, nm1, 1_${ik}$, e, nm1, ierr ) eps = stdlib${ii}$_slamch( 'EPSILON' ) mlvl = int( log( real( n,KIND=sp) / real( smlsiz+1,KIND=sp) ) / log( two ),KIND=${ik}$) + & 1_${ik}$ smlszp = smlsiz + 1_${ik}$ if( icompq==1_${ik}$ ) then iu = 1_${ik}$ ivt = 1_${ik}$ + smlsiz difl = ivt + smlszp difr = difl + mlvl z = difr + mlvl*2_${ik}$ ic = z + mlvl is = ic + 1_${ik}$ poles = is + 1_${ik}$ givnum = poles + 2_${ik}$*mlvl k = 1_${ik}$ givptr = 2_${ik}$ perm = 3_${ik}$ givcol = perm + mlvl end if do i = 1, n if( abs( d( i ) )<eps ) then d( i ) = sign( eps, d( i ) ) end if end do start = 1_${ik}$ sqre = 0_${ik}$ loop_30: do i = 1, nm1 if( ( abs( e( i ) )<eps ) .or. ( i==nm1 ) ) then ! subproblem found. first determine its size and then ! apply divide and conquer on it. if( i<nm1 ) then ! a subproblem with e(i) small for i < nm1. nsize = i - start + 1_${ik}$ else if( abs( e( i ) )>=eps ) then ! a subproblem with e(nm1) not too small but i = nm1. nsize = n - start + 1_${ik}$ else ! a subproblem with e(nm1) small. this implies an ! 1-by-1 subproblem at d(n). solve this 1-by-1 problem ! first. nsize = i - start + 1_${ik}$ if( icompq==2_${ik}$ ) then u( n, n ) = sign( one, d( n ) ) vt( n, n ) = one else if( icompq==1_${ik}$ ) then q( n+( qstart-1 )*n ) = sign( one, d( n ) ) q( n+( smlsiz+qstart-1 )*n ) = one end if d( n ) = abs( d( n ) ) end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_slasd0( nsize, sqre, d( start ), e( start ),u( start, start ), & ldu, vt( start, start ),ldvt, smlsiz, iwork, work( wstart ), info ) else call stdlib${ii}$_slasda( icompq, smlsiz, nsize, sqre, d( start ),e( start ), q( & start+( iu+qstart-2 )*n ), n,q( start+( ivt+qstart-2 )*n ),iq( start+k*n ), q(& start+( difl+qstart-2 )*n ), q( start+( difr+qstart-2 )*n ),q( start+( z+& qstart-2 )*n ),q( start+( poles+qstart-2 )*n ),iq( start+givptr*n ), iq( & start+givcol*n ),n, iq( start+perm*n ),q( start+( givnum+qstart-2 )*n ),q( & start+( ic+qstart-2 )*n ),q( start+( is+qstart-2 )*n ),work( wstart ), iwork,& info ) end if if( info/=0_${ik}$ ) then return end if start = i + 1_${ik}$ end if end do loop_30 ! unscale call stdlib${ii}$_slascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, n, 1_${ik}$, d, n, ierr ) 40 continue ! use selection sort to minimize swaps of singular vectors do ii = 2, n i = ii - 1_${ik}$ kk = i p = d( i ) do j = ii, n if( d( j )>p ) then kk = j p = d( j ) end if end do if( kk/=i ) then d( kk ) = d( i ) d( i ) = p if( icompq==1_${ik}$ ) then iq( i ) = kk else if( icompq==2_${ik}$ ) then call stdlib${ii}$_sswap( n, u( 1_${ik}$, i ), 1_${ik}$, u( 1_${ik}$, kk ), 1_${ik}$ ) call stdlib${ii}$_sswap( n, vt( i, 1_${ik}$ ), ldvt, vt( kk, 1_${ik}$ ), ldvt ) end if else if( icompq==1_${ik}$ ) then iq( i ) = i end if end do ! if icompq = 1, use iq(n,1) as the indicator for uplo if( icompq==1_${ik}$ ) then if( iuplo==1_${ik}$ ) then iq( n ) = 1_${ik}$ else iq( n ) = 0_${ik}$ end if end if ! if b is lower bidiagonal, update u by those givens rotations ! which rotated b to be upper bidiagonal if( ( iuplo==2_${ik}$ ) .and. ( icompq==2_${ik}$ ) )call stdlib${ii}$_slasr( 'L', 'V', 'B', n, n, work( 1_${ik}$ )& , work( n ), u, ldu ) return end subroutine stdlib${ii}$_sbdsdc pure module subroutine stdlib${ii}$_dbdsdc( uplo, compq, n, d, e, u, ldu, vt, ldvt, q, iq,work, iwork, & !! DBDSDC computes the singular value decomposition (SVD) of a real !! N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, !! using a divide and conquer method, where S is a diagonal matrix !! with non-negative diagonal elements (the singular values of B), and !! U and VT are orthogonal matrices of left and right singular vectors, !! respectively. DBDSDC can be used to compute all singular values, !! and optionally, singular vectors or singular vectors in compact 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 DLASD3 for details. !! The code currently calls DLASDQ if singular values only are desired. !! However, it can be slightly modified to compute singular values !! using the divide and conquer method. 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) :: compq, uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldu, ldvt, n ! Array Arguments integer(${ik}$), intent(out) :: iq(*), iwork(*) real(dp), intent(inout) :: d(*), e(*) real(dp), intent(out) :: q(*), u(ldu,*), vt(ldvt,*), work(*) ! ===================================================================== ! changed dimension statement in comment describing e from (n) to ! (n-1). sven, 17 feb 05. ! ===================================================================== ! Local Scalars integer(${ik}$) :: difl, difr, givcol, givnum, givptr, i, ic, icompq, ierr, ii, is, iu, & iuplo, ivt, j, k, kk, mlvl, nm1, nsize, perm, poles, qstart, smlsiz, smlszp, sqre, & start, wstart, z real(dp) :: cs, eps, orgnrm, p, r, sn ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ iuplo = 0_${ik}$ if( stdlib_lsame( uplo, 'U' ) )iuplo = 1_${ik}$ if( stdlib_lsame( uplo, 'L' ) )iuplo = 2_${ik}$ if( stdlib_lsame( compq, 'N' ) ) then icompq = 0_${ik}$ else if( stdlib_lsame( compq, 'P' ) ) then icompq = 1_${ik}$ else if( stdlib_lsame( compq, 'I' ) ) then icompq = 2_${ik}$ else icompq = -1_${ik}$ end if if( iuplo==0_${ik}$ ) then info = -1_${ik}$ else if( icompq<0_${ik}$ ) then info = -2_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( ( ldu<1_${ik}$ ) .or. ( ( icompq==2_${ik}$ ) .and. ( ldu<n ) ) ) then info = -7_${ik}$ else if( ( ldvt<1_${ik}$ ) .or. ( ( icompq==2_${ik}$ ) .and. ( ldvt<n ) ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DBDSDC', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'DBDSDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) if( n==1_${ik}$ ) then if( icompq==1_${ik}$ ) then q( 1_${ik}$ ) = sign( one, d( 1_${ik}$ ) ) q( 1_${ik}$+smlsiz*n ) = one else if( icompq==2_${ik}$ ) then u( 1_${ik}$, 1_${ik}$ ) = sign( one, d( 1_${ik}$ ) ) vt( 1_${ik}$, 1_${ik}$ ) = one end if d( 1_${ik}$ ) = abs( d( 1_${ik}$ ) ) return end if nm1 = n - 1_${ik}$ ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left wstart = 1_${ik}$ qstart = 3_${ik}$ if( icompq==1_${ik}$ ) then call stdlib${ii}$_dcopy( n, d, 1_${ik}$, q( 1_${ik}$ ), 1_${ik}$ ) call stdlib${ii}$_dcopy( n-1, e, 1_${ik}$, q( n+1 ), 1_${ik}$ ) end if if( iuplo==2_${ik}$ ) then qstart = 5_${ik}$ if( icompq == 2_${ik}$ ) wstart = 2_${ik}$*n - 1_${ik}$ do i = 1, n - 1 call stdlib${ii}$_dlartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) if( icompq==1_${ik}$ ) then q( i+2*n ) = cs q( i+3*n ) = sn else if( icompq==2_${ik}$ ) then work( i ) = cs work( nm1+i ) = -sn end if end do end if ! if icompq = 0, use stdlib_dlasdq to compute the singular values. if( icompq==0_${ik}$ ) then ! ignore wstart, instead using work( 1 ), since the two vectors ! for cs and -sn above are added only if icompq == 2, ! and adding them exceeds documented work size of 4*n. call stdlib${ii}$_dlasdq( 'U', 0_${ik}$, n, 0_${ik}$, 0_${ik}$, 0_${ik}$, d, e, vt, ldvt, u, ldu, u,ldu, work( 1_${ik}$ ), & info ) go to 40 end if ! if n is smaller than the minimum divide size smlsiz, then solve ! the problem with another solver. if( n<=smlsiz ) then if( icompq==2_${ik}$ ) then call stdlib${ii}$_dlaset( 'A', n, n, zero, one, u, ldu ) call stdlib${ii}$_dlaset( 'A', n, n, zero, one, vt, ldvt ) call stdlib${ii}$_dlasdq( 'U', 0_${ik}$, n, n, n, 0_${ik}$, d, e, vt, ldvt, u, ldu, u,ldu, work( & wstart ), info ) else if( icompq==1_${ik}$ ) then iu = 1_${ik}$ ivt = iu + n call stdlib${ii}$_dlaset( 'A', n, n, zero, one, q( iu+( qstart-1 )*n ),n ) call stdlib${ii}$_dlaset( 'A', n, n, zero, one, q( ivt+( qstart-1 )*n ),n ) call stdlib${ii}$_dlasdq( 'U', 0_${ik}$, n, n, n, 0_${ik}$, d, e,q( ivt+( qstart-1 )*n ), n,q( iu+( & qstart-1 )*n ), n,q( iu+( qstart-1 )*n ), n, work( wstart ),info ) end if go to 40 end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_dlaset( 'A', n, n, zero, one, u, ldu ) call stdlib${ii}$_dlaset( 'A', n, n, zero, one, vt, ldvt ) end if ! scale. orgnrm = stdlib${ii}$_dlanst( 'M', n, d, e ) if( orgnrm==zero )return call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, n, 1_${ik}$, d, n, ierr ) call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, nm1, 1_${ik}$, e, nm1, ierr ) eps = (0.9e+0_dp)*stdlib${ii}$_dlamch( 'EPSILON' ) mlvl = int( log( real( n,KIND=dp) / real( smlsiz+1,KIND=dp) ) / log( two ),KIND=${ik}$) + & 1_${ik}$ smlszp = smlsiz + 1_${ik}$ if( icompq==1_${ik}$ ) then iu = 1_${ik}$ ivt = 1_${ik}$ + smlsiz difl = ivt + smlszp difr = difl + mlvl z = difr + mlvl*2_${ik}$ ic = z + mlvl is = ic + 1_${ik}$ poles = is + 1_${ik}$ givnum = poles + 2_${ik}$*mlvl k = 1_${ik}$ givptr = 2_${ik}$ perm = 3_${ik}$ givcol = perm + mlvl end if do i = 1, n if( abs( d( i ) )<eps ) then d( i ) = sign( eps, d( i ) ) end if end do start = 1_${ik}$ sqre = 0_${ik}$ loop_30: do i = 1, nm1 if( ( abs( e( i ) )<eps ) .or. ( i==nm1 ) ) then ! subproblem found. first determine its size and then ! apply divide and conquer on it. if( i<nm1 ) then ! a subproblem with e(i) small for i < nm1. nsize = i - start + 1_${ik}$ else if( abs( e( i ) )>=eps ) then ! a subproblem with e(nm1) not too small but i = nm1. nsize = n - start + 1_${ik}$ else ! a subproblem with e(nm1) small. this implies an ! 1-by-1 subproblem at d(n). solve this 1-by-1 problem ! first. nsize = i - start + 1_${ik}$ if( icompq==2_${ik}$ ) then u( n, n ) = sign( one, d( n ) ) vt( n, n ) = one else if( icompq==1_${ik}$ ) then q( n+( qstart-1 )*n ) = sign( one, d( n ) ) q( n+( smlsiz+qstart-1 )*n ) = one end if d( n ) = abs( d( n ) ) end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_dlasd0( nsize, sqre, d( start ), e( start ),u( start, start ), & ldu, vt( start, start ),ldvt, smlsiz, iwork, work( wstart ), info ) else call stdlib${ii}$_dlasda( icompq, smlsiz, nsize, sqre, d( start ),e( start ), q( & start+( iu+qstart-2 )*n ), n,q( start+( ivt+qstart-2 )*n ),iq( start+k*n ), q(& start+( difl+qstart-2 )*n ), q( start+( difr+qstart-2 )*n ),q( start+( z+& qstart-2 )*n ),q( start+( poles+qstart-2 )*n ),iq( start+givptr*n ), iq( & start+givcol*n ),n, iq( start+perm*n ),q( start+( givnum+qstart-2 )*n ),q( & start+( ic+qstart-2 )*n ),q( start+( is+qstart-2 )*n ),work( wstart ), iwork,& info ) end if if( info/=0_${ik}$ ) then return end if start = i + 1_${ik}$ end if end do loop_30 ! unscale call stdlib${ii}$_dlascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, n, 1_${ik}$, d, n, ierr ) 40 continue ! use selection sort to minimize swaps of singular vectors do ii = 2, n i = ii - 1_${ik}$ kk = i p = d( i ) do j = ii, n if( d( j )>p ) then kk = j p = d( j ) end if end do if( kk/=i ) then d( kk ) = d( i ) d( i ) = p if( icompq==1_${ik}$ ) then iq( i ) = kk else if( icompq==2_${ik}$ ) then call stdlib${ii}$_dswap( n, u( 1_${ik}$, i ), 1_${ik}$, u( 1_${ik}$, kk ), 1_${ik}$ ) call stdlib${ii}$_dswap( n, vt( i, 1_${ik}$ ), ldvt, vt( kk, 1_${ik}$ ), ldvt ) end if else if( icompq==1_${ik}$ ) then iq( i ) = i end if end do ! if icompq = 1, use iq(n,1) as the indicator for uplo if( icompq==1_${ik}$ ) then if( iuplo==1_${ik}$ ) then iq( n ) = 1_${ik}$ else iq( n ) = 0_${ik}$ end if end if ! if b is lower bidiagonal, update u by those givens rotations ! which rotated b to be upper bidiagonal if( ( iuplo==2_${ik}$ ) .and. ( icompq==2_${ik}$ ) )call stdlib${ii}$_dlasr( 'L', 'V', 'B', n, n, work( 1_${ik}$ )& , work( n ), u, ldu ) return end subroutine stdlib${ii}$_dbdsdc #:for rk,rt,ri in REAL_KINDS_TYPES #:if not rk in ["sp","dp"] pure module subroutine stdlib${ii}$_${ri}$bdsdc( uplo, compq, n, d, e, u, ldu, vt, ldvt, q, iq,work, iwork, & !! DBDSDC: computes the singular value decomposition (SVD) of a real !! N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, !! using a divide and conquer method, where S is a diagonal matrix !! with non-negative diagonal elements (the singular values of B), and !! U and VT are orthogonal matrices of left and right singular vectors, !! respectively. DBDSDC can be used to compute all singular values, !! and optionally, singular vectors or singular vectors in compact 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 DLASD3 for details. !! The code currently calls DLASDQ if singular values only are desired. !! However, it can be slightly modified to compute singular values !! using the divide and conquer method. 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) :: compq, uplo integer(${ik}$), intent(out) :: info integer(${ik}$), intent(in) :: ldu, ldvt, n ! Array Arguments integer(${ik}$), intent(out) :: iq(*), iwork(*) real(${rk}$), intent(inout) :: d(*), e(*) real(${rk}$), intent(out) :: q(*), u(ldu,*), vt(ldvt,*), work(*) ! ===================================================================== ! changed dimension statement in comment describing e from (n) to ! (n-1). sven, 17 feb 05. ! ===================================================================== ! Local Scalars integer(${ik}$) :: difl, difr, givcol, givnum, givptr, i, ic, icompq, ierr, ii, is, iu, & iuplo, ivt, j, k, kk, mlvl, nm1, nsize, perm, poles, qstart, smlsiz, smlszp, sqre, & start, wstart, z real(${rk}$) :: cs, eps, orgnrm, p, r, sn ! Intrinsic Functions ! Executable Statements ! test the input parameters. info = 0_${ik}$ iuplo = 0_${ik}$ if( stdlib_lsame( uplo, 'U' ) )iuplo = 1_${ik}$ if( stdlib_lsame( uplo, 'L' ) )iuplo = 2_${ik}$ if( stdlib_lsame( compq, 'N' ) ) then icompq = 0_${ik}$ else if( stdlib_lsame( compq, 'P' ) ) then icompq = 1_${ik}$ else if( stdlib_lsame( compq, 'I' ) ) then icompq = 2_${ik}$ else icompq = -1_${ik}$ end if if( iuplo==0_${ik}$ ) then info = -1_${ik}$ else if( icompq<0_${ik}$ ) then info = -2_${ik}$ else if( n<0_${ik}$ ) then info = -3_${ik}$ else if( ( ldu<1_${ik}$ ) .or. ( ( icompq==2_${ik}$ ) .and. ( ldu<n ) ) ) then info = -7_${ik}$ else if( ( ldvt<1_${ik}$ ) .or. ( ( icompq==2_${ik}$ ) .and. ( ldvt<n ) ) ) then info = -9_${ik}$ end if if( info/=0_${ik}$ ) then call stdlib${ii}$_xerbla( 'DBDSDC', -info ) return end if ! quick return if possible if( n==0 )return smlsiz = stdlib${ii}$_ilaenv( 9_${ik}$, 'DBDSDC', ' ', 0_${ik}$, 0_${ik}$, 0_${ik}$, 0_${ik}$ ) if( n==1_${ik}$ ) then if( icompq==1_${ik}$ ) then q( 1_${ik}$ ) = sign( one, d( 1_${ik}$ ) ) q( 1_${ik}$+smlsiz*n ) = one else if( icompq==2_${ik}$ ) then u( 1_${ik}$, 1_${ik}$ ) = sign( one, d( 1_${ik}$ ) ) vt( 1_${ik}$, 1_${ik}$ ) = one end if d( 1_${ik}$ ) = abs( d( 1_${ik}$ ) ) return end if nm1 = n - 1_${ik}$ ! if matrix lower bidiagonal, rotate to be upper bidiagonal ! by applying givens rotations on the left wstart = 1_${ik}$ qstart = 3_${ik}$ if( icompq==1_${ik}$ ) then call stdlib${ii}$_${ri}$copy( n, d, 1_${ik}$, q( 1_${ik}$ ), 1_${ik}$ ) call stdlib${ii}$_${ri}$copy( n-1, e, 1_${ik}$, q( n+1 ), 1_${ik}$ ) end if if( iuplo==2_${ik}$ ) then qstart = 5_${ik}$ if( icompq == 2_${ik}$ ) wstart = 2_${ik}$*n - 1_${ik}$ do i = 1, n - 1 call stdlib${ii}$_${ri}$lartg( d( i ), e( i ), cs, sn, r ) d( i ) = r e( i ) = sn*d( i+1 ) d( i+1 ) = cs*d( i+1 ) if( icompq==1_${ik}$ ) then q( i+2*n ) = cs q( i+3*n ) = sn else if( icompq==2_${ik}$ ) then work( i ) = cs work( nm1+i ) = -sn end if end do end if ! if icompq = 0, use stdlib_${ri}$lasdq to compute the singular values. if( icompq==0_${ik}$ ) then ! ignore wstart, instead using work( 1 ), since the two vectors ! for cs and -sn above are added only if icompq == 2, ! and adding them exceeds documented work size of 4*n. call stdlib${ii}$_${ri}$lasdq( 'U', 0_${ik}$, n, 0_${ik}$, 0_${ik}$, 0_${ik}$, d, e, vt, ldvt, u, ldu, u,ldu, work( 1_${ik}$ ), & info ) go to 40 end if ! if n is smaller than the minimum divide size smlsiz, then solve ! the problem with another solver. if( n<=smlsiz ) then if( icompq==2_${ik}$ ) then call stdlib${ii}$_${ri}$laset( 'A', n, n, zero, one, u, ldu ) call stdlib${ii}$_${ri}$laset( 'A', n, n, zero, one, vt, ldvt ) call stdlib${ii}$_${ri}$lasdq( 'U', 0_${ik}$, n, n, n, 0_${ik}$, d, e, vt, ldvt, u, ldu, u,ldu, work( & wstart ), info ) else if( icompq==1_${ik}$ ) then iu = 1_${ik}$ ivt = iu + n call stdlib${ii}$_${ri}$laset( 'A', n, n, zero, one, q( iu+( qstart-1 )*n ),n ) call stdlib${ii}$_${ri}$laset( 'A', n, n, zero, one, q( ivt+( qstart-1 )*n ),n ) call stdlib${ii}$_${ri}$lasdq( 'U', 0_${ik}$, n, n, n, 0_${ik}$, d, e,q( ivt+( qstart-1 )*n ), n,q( iu+( & qstart-1 )*n ), n,q( iu+( qstart-1 )*n ), n, work( wstart ),info ) end if go to 40 end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_${ri}$laset( 'A', n, n, zero, one, u, ldu ) call stdlib${ii}$_${ri}$laset( 'A', n, n, zero, one, vt, ldvt ) end if ! scale. orgnrm = stdlib${ii}$_${ri}$lanst( 'M', n, d, e ) if( orgnrm==zero )return call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, n, 1_${ik}$, d, n, ierr ) call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, orgnrm, one, nm1, 1_${ik}$, e, nm1, ierr ) eps = (0.9e+0_${rk}$)*stdlib${ii}$_${ri}$lamch( 'EPSILON' ) mlvl = int( log( real( n,KIND=${rk}$) / real( smlsiz+1,KIND=${rk}$) ) / log( two ),KIND=${ik}$) + & 1_${ik}$ smlszp = smlsiz + 1_${ik}$ if( icompq==1_${ik}$ ) then iu = 1_${ik}$ ivt = 1_${ik}$ + smlsiz difl = ivt + smlszp difr = difl + mlvl z = difr + mlvl*2_${ik}$ ic = z + mlvl is = ic + 1_${ik}$ poles = is + 1_${ik}$ givnum = poles + 2_${ik}$*mlvl k = 1_${ik}$ givptr = 2_${ik}$ perm = 3_${ik}$ givcol = perm + mlvl end if do i = 1, n if( abs( d( i ) )<eps ) then d( i ) = sign( eps, d( i ) ) end if end do start = 1_${ik}$ sqre = 0_${ik}$ loop_30: do i = 1, nm1 if( ( abs( e( i ) )<eps ) .or. ( i==nm1 ) ) then ! subproblem found. first determine its size and then ! apply divide and conquer on it. if( i<nm1 ) then ! a subproblem with e(i) small for i < nm1. nsize = i - start + 1_${ik}$ else if( abs( e( i ) )>=eps ) then ! a subproblem with e(nm1) not too small but i = nm1. nsize = n - start + 1_${ik}$ else ! a subproblem with e(nm1) small. this implies an ! 1-by-1 subproblem at d(n). solve this 1-by-1 problem ! first. nsize = i - start + 1_${ik}$ if( icompq==2_${ik}$ ) then u( n, n ) = sign( one, d( n ) ) vt( n, n ) = one else if( icompq==1_${ik}$ ) then q( n+( qstart-1 )*n ) = sign( one, d( n ) ) q( n+( smlsiz+qstart-1 )*n ) = one end if d( n ) = abs( d( n ) ) end if if( icompq==2_${ik}$ ) then call stdlib${ii}$_${ri}$lasd0( nsize, sqre, d( start ), e( start ),u( start, start ), & ldu, vt( start, start ),ldvt, smlsiz, iwork, work( wstart ), info ) else call stdlib${ii}$_${ri}$lasda( icompq, smlsiz, nsize, sqre, d( start ),e( start ), q( & start+( iu+qstart-2 )*n ), n,q( start+( ivt+qstart-2 )*n ),iq( start+k*n ), q(& start+( difl+qstart-2 )*n ), q( start+( difr+qstart-2 )*n ),q( start+( z+& qstart-2 )*n ),q( start+( poles+qstart-2 )*n ),iq( start+givptr*n ), iq( & start+givcol*n ),n, iq( start+perm*n ),q( start+( givnum+qstart-2 )*n ),q( & start+( ic+qstart-2 )*n ),q( start+( is+qstart-2 )*n ),work( wstart ), iwork,& info ) end if if( info/=0_${ik}$ ) then return end if start = i + 1_${ik}$ end if end do loop_30 ! unscale call stdlib${ii}$_${ri}$lascl( 'G', 0_${ik}$, 0_${ik}$, one, orgnrm, n, 1_${ik}$, d, n, ierr ) 40 continue ! use selection sort to minimize swaps of singular vectors do ii = 2, n i = ii - 1_${ik}$ kk = i p = d( i ) do j = ii, n if( d( j )>p ) then kk = j p = d( j ) end if end do if( kk/=i ) then d( kk ) = d( i ) d( i ) = p if( icompq==1_${ik}$ ) then iq( i ) = kk else if( icompq==2_${ik}$ ) then call stdlib${ii}$_${ri}$swap( n, u( 1_${ik}$, i ), 1_${ik}$, u( 1_${ik}$, kk ), 1_${ik}$ ) call stdlib${ii}$_${ri}$swap( n, vt( i, 1_${ik}$ ), ldvt, vt( kk, 1_${ik}$ ), ldvt ) end if else if( icompq==1_${ik}$ ) then iq( i ) = i end if end do ! if icompq = 1, use iq(n,1) as the indicator for uplo if( icompq==1_${ik}$ ) then if( iuplo==1_${ik}$ ) then iq( n ) = 1_${ik}$ else iq( n ) = 0_${ik}$ end if end if ! if b is lower bidiagonal, update u by those givens rotations ! which rotated b to be upper bidiagonal if( ( iuplo==2_${ik}$ ) .and. ( icompq==2_${ik}$ ) )call stdlib${ii}$_${ri}$lasr( 'L', 'V', 'B', n, n, work( 1_${ik}$ )& , work( n ), u, ldu ) return end subroutine stdlib${ii}$_${ri}$bdsdc #:endif #:endfor #:endfor end submodule stdlib_lapack_eigv_svd_drivers3