sgesdd.f
来自「famous linear algebra library (LAPACK) p」· F 代码 · 共 1,340 行 · 第 1/4 页
F
1,340 行
SUBROUTINE SGESDD( JOBZ, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK,
$ LWORK, IWORK, INFO )
*
* -- LAPACK driver routine (version 3.1) --
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
* November 2006
*
* .. Scalar Arguments ..
CHARACTER JOBZ
INTEGER INFO, LDA, LDU, LDVT, LWORK, M, N
* ..
* .. Array Arguments ..
INTEGER IWORK( * )
REAL A( LDA, * ), S( * ), U( LDU, * ),
$ VT( LDVT, * ), WORK( * )
* ..
*
* Purpose
* =======
*
* SGESDD computes the singular value decomposition (SVD) of a real
* M-by-N matrix A, optionally computing the left and right singular
* vectors. If singular vectors are desired, it uses a
* divide-and-conquer algorithm.
*
* The SVD is written
*
* A = U * SIGMA * transpose(V)
*
* where SIGMA is an M-by-N matrix which is zero except for its
* min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and
* V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA
* are the singular values of A; they are real and non-negative, and
* are returned in descending order. The first min(m,n) columns of
* U and V are the left and right singular vectors of A.
*
* Note that the routine returns VT = V**T, not V.
*
* The divide and conquer algorithm makes very mild assumptions about
* floating point arithmetic. It will work on machines with a guard
* digit in add/subtract, or on those binary machines without guard
* digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or
* Cray-2. It could conceivably fail on hexadecimal or decimal machines
* without guard digits, but we know of none.
*
* Arguments
* =========
*
* JOBZ (input) CHARACTER*1
* Specifies options for computing all or part of the matrix U:
* = 'A': all M columns of U and all N rows of V**T are
* returned in the arrays U and VT;
* = 'S': the first min(M,N) columns of U and the first
* min(M,N) rows of V**T are returned in the arrays U
* and VT;
* = 'O': If M >= N, the first N columns of U are overwritten
* on the array A and all rows of V**T are returned in
* the array VT;
* otherwise, all columns of U are returned in the
* array U and the first M rows of V**T are overwritten
* in the array A;
* = 'N': no columns of U or rows of V**T are computed.
*
* M (input) INTEGER
* The number of rows of the input matrix A. M >= 0.
*
* N (input) INTEGER
* The number of columns of the input matrix A. N >= 0.
*
* A (input/output) REAL array, dimension (LDA,N)
* On entry, the M-by-N matrix A.
* On exit,
* if JOBZ = 'O', A is overwritten with the first N columns
* of U (the left singular vectors, stored
* columnwise) if M >= N;
* A is overwritten with the first M rows
* of V**T (the right singular vectors, stored
* rowwise) otherwise.
* if JOBZ .ne. 'O', the contents of A are destroyed.
*
* LDA (input) INTEGER
* The leading dimension of the array A. LDA >= max(1,M).
*
* S (output) REAL array, dimension (min(M,N))
* The singular values of A, sorted so that S(i) >= S(i+1).
*
* U (output) REAL array, dimension (LDU,UCOL)
* UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N;
* UCOL = min(M,N) if JOBZ = 'S'.
* If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M
* orthogonal matrix U;
* if JOBZ = 'S', U contains the first min(M,N) columns of U
* (the left singular vectors, stored columnwise);
* if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced.
*
* LDU (input) INTEGER
* The leading dimension of the array U. LDU >= 1; if
* JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M.
*
* VT (output) REAL array, dimension (LDVT,N)
* If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the
* N-by-N orthogonal matrix V**T;
* if JOBZ = 'S', VT contains the first min(M,N) rows of
* V**T (the right singular vectors, stored rowwise);
* if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced.
*
* LDVT (input) INTEGER
* The leading dimension of the array VT. LDVT >= 1; if
* JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N;
* if JOBZ = 'S', LDVT >= min(M,N).
*
* WORK (workspace/output) REAL array, dimension (MAX(1,LWORK))
* On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
*
* LWORK (input) INTEGER
* The dimension of the array WORK. LWORK >= 1.
* If JOBZ = 'N',
* LWORK >= 3*min(M,N) + max(max(M,N),6*min(M,N)).
* If JOBZ = 'O',
* LWORK >= 3*min(M,N)*min(M,N) +
* max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)).
* If JOBZ = 'S' or 'A'
* LWORK >= 3*min(M,N)*min(M,N) +
* max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)).
* For good performance, LWORK should generally be larger.
* If LWORK = -1 but other input arguments are legal, WORK(1)
* returns the optimal LWORK.
*
* IWORK (workspace) INTEGER array, dimension (8*min(M,N))
*
* INFO (output) INTEGER
* = 0: successful exit.
* < 0: if INFO = -i, the i-th argument had an illegal value.
* > 0: SBDSDC did not converge, updating process failed.
*
* Further Details
* ===============
*
* Based on contributions by
* Ming Gu and Huan Ren, Computer Science Division, University of
* California at Berkeley, USA
*
* =====================================================================
*
* .. Parameters ..
REAL ZERO, ONE
PARAMETER ( ZERO = 0.0E0, ONE = 1.0E0 )
* ..
* .. Local Scalars ..
LOGICAL LQUERY, WNTQA, WNTQAS, WNTQN, WNTQO, WNTQS
INTEGER BDSPAC, BLK, CHUNK, I, IE, IERR, IL,
$ IR, ISCL, ITAU, ITAUP, ITAUQ, IU, IVT, LDWKVT,
$ LDWRKL, LDWRKR, LDWRKU, MAXWRK, MINMN, MINWRK,
$ MNTHR, NWORK, WRKBL
REAL ANRM, BIGNUM, EPS, SMLNUM
* ..
* .. Local Arrays ..
INTEGER IDUM( 1 )
REAL DUM( 1 )
* ..
* .. External Subroutines ..
EXTERNAL SBDSDC, SGEBRD, SGELQF, SGEMM, SGEQRF, SLACPY,
$ SLASCL, SLASET, SORGBR, SORGLQ, SORGQR, SORMBR,
$ XERBLA
* ..
* .. External Functions ..
LOGICAL LSAME
INTEGER ILAENV
REAL SLAMCH, SLANGE
EXTERNAL ILAENV, LSAME, SLAMCH, SLANGE
* ..
* .. Intrinsic Functions ..
INTRINSIC INT, MAX, MIN, SQRT
* ..
* .. Executable Statements ..
*
* Test the input arguments
*
INFO = 0
MINMN = MIN( M, N )
WNTQA = LSAME( JOBZ, 'A' )
WNTQS = LSAME( JOBZ, 'S' )
WNTQAS = WNTQA .OR. WNTQS
WNTQO = LSAME( JOBZ, 'O' )
WNTQN = LSAME( JOBZ, 'N' )
LQUERY = ( LWORK.EQ.-1 )
*
IF( .NOT.( WNTQA .OR. WNTQS .OR. WNTQO .OR. WNTQN ) ) THEN
INFO = -1
ELSE IF( M.LT.0 ) THEN
INFO = -2
ELSE IF( N.LT.0 ) THEN
INFO = -3
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
INFO = -5
ELSE IF( LDU.LT.1 .OR. ( WNTQAS .AND. LDU.LT.M ) .OR.
$ ( WNTQO .AND. M.LT.N .AND. LDU.LT.M ) ) THEN
INFO = -8
ELSE IF( LDVT.LT.1 .OR. ( WNTQA .AND. LDVT.LT.N ) .OR.
$ ( WNTQS .AND. LDVT.LT.MINMN ) .OR.
$ ( WNTQO .AND. M.GE.N .AND. LDVT.LT.N ) ) THEN
INFO = -10
END IF
*
* Compute workspace
* (Note: Comments in the code beginning "Workspace:" describe the
* minimal amount of workspace needed at that point in the code,
* as well as the preferred amount for good performance.
* NB refers to the optimal block size for the immediately
* following subroutine, as returned by ILAENV.)
*
IF( INFO.EQ.0 ) THEN
MINWRK = 1
MAXWRK = 1
IF( M.GE.N .AND. MINMN.GT.0 ) THEN
*
* Compute space needed for SBDSDC
*
MNTHR = INT( MINMN*11.0E0 / 6.0E0 )
IF( WNTQN ) THEN
BDSPAC = 7*N
ELSE
BDSPAC = 3*N*N + 4*N
END IF
IF( M.GE.MNTHR ) THEN
IF( WNTQN ) THEN
*
* Path 1 (M much larger than N, JOBZ='N')
*
WRKBL = N + N*ILAENV( 1, 'SGEQRF', ' ', M, N, -1,
$ -1 )
WRKBL = MAX( WRKBL, 3*N+2*N*
$ ILAENV( 1, 'SGEBRD', ' ', N, N, -1, -1 ) )
MAXWRK = MAX( WRKBL, BDSPAC+N )
MINWRK = BDSPAC + N
ELSE IF( WNTQO ) THEN
*
* Path 2 (M much larger than N, JOBZ='O')
*
WRKBL = N + N*ILAENV( 1, 'SGEQRF', ' ', M, N, -1, -1 )
WRKBL = MAX( WRKBL, N+N*ILAENV( 1, 'SORGQR', ' ', M,
$ N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+2*N*
$ ILAENV( 1, 'SGEBRD', ' ', N, N, -1, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'QLN', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'PRT', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, BDSPAC+3*N )
MAXWRK = WRKBL + 2*N*N
MINWRK = BDSPAC + 2*N*N + 3*N
ELSE IF( WNTQS ) THEN
*
* Path 3 (M much larger than N, JOBZ='S')
*
WRKBL = N + N*ILAENV( 1, 'SGEQRF', ' ', M, N, -1, -1 )
WRKBL = MAX( WRKBL, N+N*ILAENV( 1, 'SORGQR', ' ', M,
$ N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+2*N*
$ ILAENV( 1, 'SGEBRD', ' ', N, N, -1, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'QLN', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'PRT', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, BDSPAC+3*N )
MAXWRK = WRKBL + N*N
MINWRK = BDSPAC + N*N + 3*N
ELSE IF( WNTQA ) THEN
*
* Path 4 (M much larger than N, JOBZ='A')
*
WRKBL = N + N*ILAENV( 1, 'SGEQRF', ' ', M, N, -1, -1 )
WRKBL = MAX( WRKBL, N+M*ILAENV( 1, 'SORGQR', ' ', M,
$ M, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+2*N*
$ ILAENV( 1, 'SGEBRD', ' ', N, N, -1, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'QLN', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'PRT', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, BDSPAC+3*N )
MAXWRK = WRKBL + N*N
MINWRK = BDSPAC + N*N + 3*N
END IF
ELSE
*
* Path 5 (M at least N, but not much larger)
*
WRKBL = 3*N + ( M+N )*ILAENV( 1, 'SGEBRD', ' ', M, N, -1,
$ -1 )
IF( WNTQN ) THEN
MAXWRK = MAX( WRKBL, BDSPAC+3*N )
MINWRK = 3*N + MAX( M, BDSPAC )
ELSE IF( WNTQO ) THEN
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'QLN', M, N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'PRT', N, N, N, -1 ) )
WRKBL = MAX( WRKBL, BDSPAC+3*N )
MAXWRK = WRKBL + M*N
MINWRK = 3*N + MAX( M, N*N+BDSPAC )
ELSE IF( WNTQS ) THEN
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'QLN', M, N, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'PRT', N, N, N, -1 ) )
MAXWRK = MAX( WRKBL, BDSPAC+3*N )
MINWRK = 3*N + MAX( M, BDSPAC )
ELSE IF( WNTQA ) THEN
WRKBL = MAX( WRKBL, 3*N+M*
$ ILAENV( 1, 'SORMBR', 'QLN', M, M, N, -1 ) )
WRKBL = MAX( WRKBL, 3*N+N*
$ ILAENV( 1, 'SORMBR', 'PRT', N, N, N, -1 ) )
MAXWRK = MAX( MAXWRK, BDSPAC+3*N )
MINWRK = 3*N + MAX( M, BDSPAC )
END IF
END IF
ELSE IF ( MINMN.GT.0 ) THEN
*
* Compute space needed for SBDSDC
*
MNTHR = INT( MINMN*11.0E0 / 6.0E0 )
IF( WNTQN ) THEN
BDSPAC = 7*M
ELSE
BDSPAC = 3*M*M + 4*M
END IF
IF( N.GE.MNTHR ) THEN
IF( WNTQN ) THEN
*
* Path 1t (N much larger than M, JOBZ='N')
*
WRKBL = M + M*ILAENV( 1, 'SGELQF', ' ', M, N, -1,
$ -1 )
WRKBL = MAX( WRKBL, 3*M+2*M*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?