Annotation of rpl/lapack/lapack/dgesdd.f, revision 1.22

1.8       bertrand    1: *> \brief \b DGESDD
                      2: *
                      3: *  =========== DOCUMENTATION ===========
                      4: *
1.18      bertrand    5: * Online html documentation available at
                      6: *            http://www.netlib.org/lapack/explore-html/
1.8       bertrand    7: *
                      8: *> \htmlonly
1.18      bertrand    9: *> Download DGESDD + dependencies
                     10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgesdd.f">
                     11: *> [TGZ]</a>
                     12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgesdd.f">
                     13: *> [ZIP]</a>
                     14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgesdd.f">
1.8       bertrand   15: *> [TXT]</a>
1.18      bertrand   16: *> \endhtmlonly
1.8       bertrand   17: *
                     18: *  Definition:
                     19: *  ===========
                     20: *
1.16      bertrand   21: *       SUBROUTINE DGESDD( JOBZ, M, N, A, LDA, S, U, LDU, VT, LDVT,
                     22: *                          WORK, LWORK, IWORK, INFO )
1.18      bertrand   23: *
1.8       bertrand   24: *       .. Scalar Arguments ..
                     25: *       CHARACTER          JOBZ
                     26: *       INTEGER            INFO, LDA, LDU, LDVT, LWORK, M, N
                     27: *       ..
                     28: *       .. Array Arguments ..
                     29: *       INTEGER            IWORK( * )
                     30: *       DOUBLE PRECISION   A( LDA, * ), S( * ), U( LDU, * ),
                     31: *      $                   VT( LDVT, * ), WORK( * )
                     32: *       ..
1.18      bertrand   33: *
1.8       bertrand   34: *
                     35: *> \par Purpose:
                     36: *  =============
                     37: *>
                     38: *> \verbatim
                     39: *>
                     40: *> DGESDD computes the singular value decomposition (SVD) of a real
                     41: *> M-by-N matrix A, optionally computing the left and right singular
                     42: *> vectors.  If singular vectors are desired, it uses a
                     43: *> divide-and-conquer algorithm.
                     44: *>
                     45: *> The SVD is written
                     46: *>
                     47: *>      A = U * SIGMA * transpose(V)
                     48: *>
                     49: *> where SIGMA is an M-by-N matrix which is zero except for its
                     50: *> min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and
                     51: *> V is an N-by-N orthogonal matrix.  The diagonal elements of SIGMA
                     52: *> are the singular values of A; they are real and non-negative, and
                     53: *> are returned in descending order.  The first min(m,n) columns of
                     54: *> U and V are the left and right singular vectors of A.
                     55: *>
                     56: *> Note that the routine returns VT = V**T, not V.
                     57: *>
                     58: *> The divide and conquer algorithm makes very mild assumptions about
                     59: *> floating point arithmetic. It will work on machines with a guard
                     60: *> digit in add/subtract, or on those binary machines without guard
                     61: *> digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or
                     62: *> Cray-2. It could conceivably fail on hexadecimal or decimal machines
                     63: *> without guard digits, but we know of none.
                     64: *> \endverbatim
                     65: *
                     66: *  Arguments:
                     67: *  ==========
                     68: *
                     69: *> \param[in] JOBZ
                     70: *> \verbatim
                     71: *>          JOBZ is CHARACTER*1
                     72: *>          Specifies options for computing all or part of the matrix U:
                     73: *>          = 'A':  all M columns of U and all N rows of V**T are
                     74: *>                  returned in the arrays U and VT;
                     75: *>          = 'S':  the first min(M,N) columns of U and the first
                     76: *>                  min(M,N) rows of V**T are returned in the arrays U
                     77: *>                  and VT;
                     78: *>          = 'O':  If M >= N, the first N columns of U are overwritten
                     79: *>                  on the array A and all rows of V**T are returned in
                     80: *>                  the array VT;
                     81: *>                  otherwise, all columns of U are returned in the
                     82: *>                  array U and the first M rows of V**T are overwritten
                     83: *>                  in the array A;
                     84: *>          = 'N':  no columns of U or rows of V**T are computed.
                     85: *> \endverbatim
                     86: *>
                     87: *> \param[in] M
                     88: *> \verbatim
                     89: *>          M is INTEGER
                     90: *>          The number of rows of the input matrix A.  M >= 0.
                     91: *> \endverbatim
                     92: *>
                     93: *> \param[in] N
                     94: *> \verbatim
                     95: *>          N is INTEGER
                     96: *>          The number of columns of the input matrix A.  N >= 0.
                     97: *> \endverbatim
                     98: *>
                     99: *> \param[in,out] A
                    100: *> \verbatim
                    101: *>          A is DOUBLE PRECISION array, dimension (LDA,N)
                    102: *>          On entry, the M-by-N matrix A.
                    103: *>          On exit,
                    104: *>          if JOBZ = 'O',  A is overwritten with the first N columns
                    105: *>                          of U (the left singular vectors, stored
                    106: *>                          columnwise) if M >= N;
                    107: *>                          A is overwritten with the first M rows
                    108: *>                          of V**T (the right singular vectors, stored
                    109: *>                          rowwise) otherwise.
                    110: *>          if JOBZ .ne. 'O', the contents of A are destroyed.
                    111: *> \endverbatim
                    112: *>
                    113: *> \param[in] LDA
                    114: *> \verbatim
                    115: *>          LDA is INTEGER
                    116: *>          The leading dimension of the array A.  LDA >= max(1,M).
                    117: *> \endverbatim
                    118: *>
                    119: *> \param[out] S
                    120: *> \verbatim
                    121: *>          S is DOUBLE PRECISION array, dimension (min(M,N))
                    122: *>          The singular values of A, sorted so that S(i) >= S(i+1).
                    123: *> \endverbatim
                    124: *>
                    125: *> \param[out] U
                    126: *> \verbatim
                    127: *>          U is DOUBLE PRECISION array, dimension (LDU,UCOL)
                    128: *>          UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N;
                    129: *>          UCOL = min(M,N) if JOBZ = 'S'.
                    130: *>          If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M
                    131: *>          orthogonal matrix U;
                    132: *>          if JOBZ = 'S', U contains the first min(M,N) columns of U
                    133: *>          (the left singular vectors, stored columnwise);
                    134: *>          if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced.
                    135: *> \endverbatim
                    136: *>
                    137: *> \param[in] LDU
                    138: *> \verbatim
                    139: *>          LDU is INTEGER
                    140: *>          The leading dimension of the array U.  LDU >= 1; if
                    141: *>          JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M.
                    142: *> \endverbatim
                    143: *>
                    144: *> \param[out] VT
                    145: *> \verbatim
                    146: *>          VT is DOUBLE PRECISION array, dimension (LDVT,N)
                    147: *>          If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the
                    148: *>          N-by-N orthogonal matrix V**T;
                    149: *>          if JOBZ = 'S', VT contains the first min(M,N) rows of
                    150: *>          V**T (the right singular vectors, stored rowwise);
                    151: *>          if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced.
                    152: *> \endverbatim
                    153: *>
                    154: *> \param[in] LDVT
                    155: *> \verbatim
                    156: *>          LDVT is INTEGER
1.16      bertrand  157: *>          The leading dimension of the array VT.  LDVT >= 1;
                    158: *>          if JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N;
1.8       bertrand  159: *>          if JOBZ = 'S', LDVT >= min(M,N).
                    160: *> \endverbatim
                    161: *>
                    162: *> \param[out] WORK
                    163: *> \verbatim
                    164: *>          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))
                    165: *>          On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
                    166: *> \endverbatim
                    167: *>
                    168: *> \param[in] LWORK
                    169: *> \verbatim
                    170: *>          LWORK is INTEGER
                    171: *>          The dimension of the array WORK. LWORK >= 1.
1.16      bertrand  172: *>          If LWORK = -1, a workspace query is assumed.  The optimal
                    173: *>          size for the WORK array is calculated and stored in WORK(1),
                    174: *>          and no other work except argument checking is performed.
                    175: *>
                    176: *>          Let mx = max(M,N) and mn = min(M,N).
                    177: *>          If JOBZ = 'N', LWORK >= 3*mn + max( mx, 7*mn ).
                    178: *>          If JOBZ = 'O', LWORK >= 3*mn + max( mx, 5*mn*mn + 4*mn ).
                    179: *>          If JOBZ = 'S', LWORK >= 4*mn*mn + 7*mn.
                    180: *>          If JOBZ = 'A', LWORK >= 4*mn*mn + 6*mn + mx.
                    181: *>          These are not tight minimums in all cases; see comments inside code.
                    182: *>          For good performance, LWORK should generally be larger;
                    183: *>          a query is recommended.
1.8       bertrand  184: *> \endverbatim
                    185: *>
                    186: *> \param[out] IWORK
                    187: *> \verbatim
                    188: *>          IWORK is INTEGER array, dimension (8*min(M,N))
                    189: *> \endverbatim
                    190: *>
                    191: *> \param[out] INFO
                    192: *> \verbatim
                    193: *>          INFO is INTEGER
1.22    ! bertrand  194: *>          <  0:  if INFO = -i, the i-th argument had an illegal value.
        !           195: *>          = -4:  if A had a NAN entry.
        !           196: *>          >  0:  DBDSDC did not converge, updating process failed.
        !           197: *>          =  0:  successful exit.
1.8       bertrand  198: *> \endverbatim
                    199: *
                    200: *  Authors:
                    201: *  ========
                    202: *
1.18      bertrand  203: *> \author Univ. of Tennessee
                    204: *> \author Univ. of California Berkeley
                    205: *> \author Univ. of Colorado Denver
                    206: *> \author NAG Ltd.
1.8       bertrand  207: *
                    208: *> \ingroup doubleGEsing
                    209: *
                    210: *> \par Contributors:
                    211: *  ==================
                    212: *>
                    213: *>     Ming Gu and Huan Ren, Computer Science Division, University of
                    214: *>     California at Berkeley, USA
                    215: *>
                    216: *  =====================================================================
1.16      bertrand  217:       SUBROUTINE DGESDD( JOBZ, M, N, A, LDA, S, U, LDU, VT, LDVT,
                    218:      $                   WORK, LWORK, IWORK, INFO )
                    219:       implicit none
1.1       bertrand  220: *
1.22    ! bertrand  221: *  -- LAPACK driver routine --
1.1       bertrand  222: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
                    223: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
                    224: *
                    225: *     .. Scalar Arguments ..
                    226:       CHARACTER          JOBZ
                    227:       INTEGER            INFO, LDA, LDU, LDVT, LWORK, M, N
                    228: *     ..
                    229: *     .. Array Arguments ..
                    230:       INTEGER            IWORK( * )
                    231:       DOUBLE PRECISION   A( LDA, * ), S( * ), U( LDU, * ),
                    232:      $                   VT( LDVT, * ), WORK( * )
                    233: *     ..
                    234: *
                    235: *  =====================================================================
                    236: *
                    237: *     .. Parameters ..
                    238:       DOUBLE PRECISION   ZERO, ONE
                    239:       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0 )
                    240: *     ..
                    241: *     .. Local Scalars ..
                    242:       LOGICAL            LQUERY, WNTQA, WNTQAS, WNTQN, WNTQO, WNTQS
                    243:       INTEGER            BDSPAC, BLK, CHUNK, I, IE, IERR, IL,
                    244:      $                   IR, ISCL, ITAU, ITAUP, ITAUQ, IU, IVT, LDWKVT,
                    245:      $                   LDWRKL, LDWRKR, LDWRKU, MAXWRK, MINMN, MINWRK,
                    246:      $                   MNTHR, NWORK, WRKBL
1.18      bertrand  247:       INTEGER            LWORK_DGEBRD_MN, LWORK_DGEBRD_MM,
1.16      bertrand  248:      $                   LWORK_DGEBRD_NN, LWORK_DGELQF_MN,
                    249:      $                   LWORK_DGEQRF_MN,
                    250:      $                   LWORK_DORGBR_P_MM, LWORK_DORGBR_Q_NN,
                    251:      $                   LWORK_DORGLQ_MN, LWORK_DORGLQ_NN,
                    252:      $                   LWORK_DORGQR_MM, LWORK_DORGQR_MN,
                    253:      $                   LWORK_DORMBR_PRT_MM, LWORK_DORMBR_QLN_MM,
                    254:      $                   LWORK_DORMBR_PRT_MN, LWORK_DORMBR_QLN_MN,
                    255:      $                   LWORK_DORMBR_PRT_NN, LWORK_DORMBR_QLN_NN
1.1       bertrand  256:       DOUBLE PRECISION   ANRM, BIGNUM, EPS, SMLNUM
                    257: *     ..
                    258: *     .. Local Arrays ..
                    259:       INTEGER            IDUM( 1 )
                    260:       DOUBLE PRECISION   DUM( 1 )
                    261: *     ..
                    262: *     .. External Subroutines ..
                    263:       EXTERNAL           DBDSDC, DGEBRD, DGELQF, DGEMM, DGEQRF, DLACPY,
                    264:      $                   DLASCL, DLASET, DORGBR, DORGLQ, DORGQR, DORMBR,
                    265:      $                   XERBLA
                    266: *     ..
                    267: *     .. External Functions ..
1.22    ! bertrand  268:       LOGICAL            LSAME, DISNAN
        !           269:       DOUBLE PRECISION   DLAMCH, DLANGE, DROUNDUP_LWORK
        !           270:       EXTERNAL           DLAMCH, DLANGE, LSAME, DISNAN, 
        !           271:      $                   DROUNDUP_LWORK
1.1       bertrand  272: *     ..
                    273: *     .. Intrinsic Functions ..
                    274:       INTRINSIC          INT, MAX, MIN, SQRT
                    275: *     ..
                    276: *     .. Executable Statements ..
                    277: *
                    278: *     Test the input arguments
                    279: *
1.16      bertrand  280:       INFO   = 0
                    281:       MINMN  = MIN( M, N )
                    282:       WNTQA  = LSAME( JOBZ, 'A' )
                    283:       WNTQS  = LSAME( JOBZ, 'S' )
1.1       bertrand  284:       WNTQAS = WNTQA .OR. WNTQS
1.16      bertrand  285:       WNTQO  = LSAME( JOBZ, 'O' )
                    286:       WNTQN  = LSAME( JOBZ, 'N' )
1.1       bertrand  287:       LQUERY = ( LWORK.EQ.-1 )
                    288: *
                    289:       IF( .NOT.( WNTQA .OR. WNTQS .OR. WNTQO .OR. WNTQN ) ) THEN
                    290:          INFO = -1
                    291:       ELSE IF( M.LT.0 ) THEN
                    292:          INFO = -2
                    293:       ELSE IF( N.LT.0 ) THEN
                    294:          INFO = -3
                    295:       ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
                    296:          INFO = -5
                    297:       ELSE IF( LDU.LT.1 .OR. ( WNTQAS .AND. LDU.LT.M ) .OR.
                    298:      $         ( WNTQO .AND. M.LT.N .AND. LDU.LT.M ) ) THEN
                    299:          INFO = -8
                    300:       ELSE IF( LDVT.LT.1 .OR. ( WNTQA .AND. LDVT.LT.N ) .OR.
                    301:      $         ( WNTQS .AND. LDVT.LT.MINMN ) .OR.
                    302:      $         ( WNTQO .AND. M.GE.N .AND. LDVT.LT.N ) ) THEN
                    303:          INFO = -10
                    304:       END IF
                    305: *
                    306: *     Compute workspace
1.16      bertrand  307: *       Note: Comments in the code beginning "Workspace:" describe the
                    308: *       minimal amount of workspace allocated at that point in the code,
1.1       bertrand  309: *       as well as the preferred amount for good performance.
                    310: *       NB refers to the optimal block size for the immediately
1.16      bertrand  311: *       following subroutine, as returned by ILAENV.
1.1       bertrand  312: *
                    313:       IF( INFO.EQ.0 ) THEN
                    314:          MINWRK = 1
                    315:          MAXWRK = 1
1.16      bertrand  316:          BDSPAC = 0
                    317:          MNTHR  = INT( MINMN*11.0D0 / 6.0D0 )
1.1       bertrand  318:          IF( M.GE.N .AND. MINMN.GT.0 ) THEN
                    319: *
                    320: *           Compute space needed for DBDSDC
                    321: *
                    322:             IF( WNTQN ) THEN
1.16      bertrand  323: *              dbdsdc needs only 4*N (or 6*N for uplo=L for LAPACK <= 3.6)
1.21      bertrand  324: *              keep 7*N for backwards compatibility.
1.1       bertrand  325:                BDSPAC = 7*N
                    326:             ELSE
                    327:                BDSPAC = 3*N*N + 4*N
                    328:             END IF
1.16      bertrand  329: *
                    330: *           Compute space preferred for each routine
                    331:             CALL DGEBRD( M, N, DUM(1), M, DUM(1), DUM(1), DUM(1),
                    332:      $                   DUM(1), DUM(1), -1, IERR )
                    333:             LWORK_DGEBRD_MN = INT( DUM(1) )
                    334: *
                    335:             CALL DGEBRD( N, N, DUM(1), N, DUM(1), DUM(1), DUM(1),
                    336:      $                   DUM(1), DUM(1), -1, IERR )
                    337:             LWORK_DGEBRD_NN = INT( DUM(1) )
                    338: *
                    339:             CALL DGEQRF( M, N, DUM(1), M, DUM(1), DUM(1), -1, IERR )
                    340:             LWORK_DGEQRF_MN = INT( DUM(1) )
                    341: *
                    342:             CALL DORGBR( 'Q', N, N, N, DUM(1), N, DUM(1), DUM(1), -1,
                    343:      $                   IERR )
                    344:             LWORK_DORGBR_Q_NN = INT( DUM(1) )
                    345: *
                    346:             CALL DORGQR( M, M, N, DUM(1), M, DUM(1), DUM(1), -1, IERR )
                    347:             LWORK_DORGQR_MM = INT( DUM(1) )
                    348: *
                    349:             CALL DORGQR( M, N, N, DUM(1), M, DUM(1), DUM(1), -1, IERR )
                    350:             LWORK_DORGQR_MN = INT( DUM(1) )
                    351: *
                    352:             CALL DORMBR( 'P', 'R', 'T', N, N, N, DUM(1), N,
                    353:      $                   DUM(1), DUM(1), N, DUM(1), -1, IERR )
                    354:             LWORK_DORMBR_PRT_NN = INT( DUM(1) )
                    355: *
                    356:             CALL DORMBR( 'Q', 'L', 'N', N, N, N, DUM(1), N,
                    357:      $                   DUM(1), DUM(1), N, DUM(1), -1, IERR )
                    358:             LWORK_DORMBR_QLN_NN = INT( DUM(1) )
                    359: *
                    360:             CALL DORMBR( 'Q', 'L', 'N', M, N, N, DUM(1), M,
                    361:      $                   DUM(1), DUM(1), M, DUM(1), -1, IERR )
                    362:             LWORK_DORMBR_QLN_MN = INT( DUM(1) )
                    363: *
                    364:             CALL DORMBR( 'Q', 'L', 'N', M, M, N, DUM(1), M,
                    365:      $                   DUM(1), DUM(1), M, DUM(1), -1, IERR )
                    366:             LWORK_DORMBR_QLN_MM = INT( DUM(1) )
                    367: *
1.1       bertrand  368:             IF( M.GE.MNTHR ) THEN
                    369:                IF( WNTQN ) THEN
                    370: *
1.16      bertrand  371: *                 Path 1 (M >> N, JOBZ='N')
1.1       bertrand  372: *
1.16      bertrand  373:                   WRKBL = N + LWORK_DGEQRF_MN
                    374:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DGEBRD_NN )
                    375:                   MAXWRK = MAX( WRKBL, BDSPAC + N )
1.1       bertrand  376:                   MINWRK = BDSPAC + N
                    377:                ELSE IF( WNTQO ) THEN
                    378: *
1.16      bertrand  379: *                 Path 2 (M >> N, JOBZ='O')
1.1       bertrand  380: *
1.16      bertrand  381:                   WRKBL = N + LWORK_DGEQRF_MN
                    382:                   WRKBL = MAX( WRKBL,   N + LWORK_DORGQR_MN )
                    383:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DGEBRD_NN )
                    384:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_QLN_NN )
                    385:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_PRT_NN )
                    386:                   WRKBL = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  387:                   MAXWRK = WRKBL + 2*N*N
                    388:                   MINWRK = BDSPAC + 2*N*N + 3*N
                    389:                ELSE IF( WNTQS ) THEN
                    390: *
1.16      bertrand  391: *                 Path 3 (M >> N, JOBZ='S')
1.1       bertrand  392: *
1.16      bertrand  393:                   WRKBL = N + LWORK_DGEQRF_MN
                    394:                   WRKBL = MAX( WRKBL,   N + LWORK_DORGQR_MN )
                    395:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DGEBRD_NN )
                    396:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_QLN_NN )
                    397:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_PRT_NN )
                    398:                   WRKBL = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  399:                   MAXWRK = WRKBL + N*N
                    400:                   MINWRK = BDSPAC + N*N + 3*N
                    401:                ELSE IF( WNTQA ) THEN
                    402: *
1.16      bertrand  403: *                 Path 4 (M >> N, JOBZ='A')
1.1       bertrand  404: *
1.16      bertrand  405:                   WRKBL = N + LWORK_DGEQRF_MN
                    406:                   WRKBL = MAX( WRKBL,   N + LWORK_DORGQR_MM )
                    407:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DGEBRD_NN )
                    408:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_QLN_NN )
                    409:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_PRT_NN )
                    410:                   WRKBL = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  411:                   MAXWRK = WRKBL + N*N
1.16      bertrand  412:                   MINWRK = N*N + MAX( 3*N + BDSPAC, N + M )
1.1       bertrand  413:                END IF
                    414:             ELSE
                    415: *
1.16      bertrand  416: *              Path 5 (M >= N, but not much larger)
1.1       bertrand  417: *
1.16      bertrand  418:                WRKBL = 3*N + LWORK_DGEBRD_MN
1.1       bertrand  419:                IF( WNTQN ) THEN
1.16      bertrand  420: *                 Path 5n (M >= N, jobz='N')
                    421:                   MAXWRK = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  422:                   MINWRK = 3*N + MAX( M, BDSPAC )
                    423:                ELSE IF( WNTQO ) THEN
1.16      bertrand  424: *                 Path 5o (M >= N, jobz='O')
                    425:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_PRT_NN )
                    426:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_QLN_MN )
                    427:                   WRKBL = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  428:                   MAXWRK = WRKBL + M*N
1.16      bertrand  429:                   MINWRK = 3*N + MAX( M, N*N + BDSPAC )
1.1       bertrand  430:                ELSE IF( WNTQS ) THEN
1.16      bertrand  431: *                 Path 5s (M >= N, jobz='S')
                    432:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_QLN_MN )
                    433:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_PRT_NN )
                    434:                   MAXWRK = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  435:                   MINWRK = 3*N + MAX( M, BDSPAC )
                    436:                ELSE IF( WNTQA ) THEN
1.16      bertrand  437: *                 Path 5a (M >= N, jobz='A')
                    438:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_QLN_MM )
                    439:                   WRKBL = MAX( WRKBL, 3*N + LWORK_DORMBR_PRT_NN )
                    440:                   MAXWRK = MAX( WRKBL, 3*N + BDSPAC )
1.1       bertrand  441:                   MINWRK = 3*N + MAX( M, BDSPAC )
                    442:                END IF
                    443:             END IF
                    444:          ELSE IF( MINMN.GT.0 ) THEN
                    445: *
                    446: *           Compute space needed for DBDSDC
                    447: *
                    448:             IF( WNTQN ) THEN
1.16      bertrand  449: *              dbdsdc needs only 4*N (or 6*N for uplo=L for LAPACK <= 3.6)
1.21      bertrand  450: *              keep 7*N for backwards compatibility.
1.1       bertrand  451:                BDSPAC = 7*M
                    452:             ELSE
                    453:                BDSPAC = 3*M*M + 4*M
                    454:             END IF
1.16      bertrand  455: *
                    456: *           Compute space preferred for each routine
                    457:             CALL DGEBRD( M, N, DUM(1), M, DUM(1), DUM(1), DUM(1),
                    458:      $                   DUM(1), DUM(1), -1, IERR )
                    459:             LWORK_DGEBRD_MN = INT( DUM(1) )
                    460: *
                    461:             CALL DGEBRD( M, M, A, M, S, DUM(1), DUM(1),
                    462:      $                   DUM(1), DUM(1), -1, IERR )
                    463:             LWORK_DGEBRD_MM = INT( DUM(1) )
                    464: *
                    465:             CALL DGELQF( M, N, A, M, DUM(1), DUM(1), -1, IERR )
                    466:             LWORK_DGELQF_MN = INT( DUM(1) )
                    467: *
                    468:             CALL DORGLQ( N, N, M, DUM(1), N, DUM(1), DUM(1), -1, IERR )
                    469:             LWORK_DORGLQ_NN = INT( DUM(1) )
                    470: *
                    471:             CALL DORGLQ( M, N, M, A, M, DUM(1), DUM(1), -1, IERR )
                    472:             LWORK_DORGLQ_MN = INT( DUM(1) )
                    473: *
                    474:             CALL DORGBR( 'P', M, M, M, A, N, DUM(1), DUM(1), -1, IERR )
                    475:             LWORK_DORGBR_P_MM = INT( DUM(1) )
                    476: *
                    477:             CALL DORMBR( 'P', 'R', 'T', M, M, M, DUM(1), M,
                    478:      $                   DUM(1), DUM(1), M, DUM(1), -1, IERR )
                    479:             LWORK_DORMBR_PRT_MM = INT( DUM(1) )
                    480: *
                    481:             CALL DORMBR( 'P', 'R', 'T', M, N, M, DUM(1), M,
                    482:      $                   DUM(1), DUM(1), M, DUM(1), -1, IERR )
                    483:             LWORK_DORMBR_PRT_MN = INT( DUM(1) )
                    484: *
                    485:             CALL DORMBR( 'P', 'R', 'T', N, N, M, DUM(1), N,
                    486:      $                   DUM(1), DUM(1), N, DUM(1), -1, IERR )
                    487:             LWORK_DORMBR_PRT_NN = INT( DUM(1) )
                    488: *
                    489:             CALL DORMBR( 'Q', 'L', 'N', M, M, M, DUM(1), M,
                    490:      $                   DUM(1), DUM(1), M, DUM(1), -1, IERR )
                    491:             LWORK_DORMBR_QLN_MM = INT( DUM(1) )
                    492: *
1.1       bertrand  493:             IF( N.GE.MNTHR ) THEN
                    494:                IF( WNTQN ) THEN
                    495: *
1.16      bertrand  496: *                 Path 1t (N >> M, JOBZ='N')
1.1       bertrand  497: *
1.16      bertrand  498:                   WRKBL = M + LWORK_DGELQF_MN
                    499:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DGEBRD_MM )
                    500:                   MAXWRK = MAX( WRKBL, BDSPAC + M )
1.1       bertrand  501:                   MINWRK = BDSPAC + M
                    502:                ELSE IF( WNTQO ) THEN
                    503: *
1.16      bertrand  504: *                 Path 2t (N >> M, JOBZ='O')
1.1       bertrand  505: *
1.16      bertrand  506:                   WRKBL = M + LWORK_DGELQF_MN
                    507:                   WRKBL = MAX( WRKBL,   M + LWORK_DORGLQ_MN )
                    508:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DGEBRD_MM )
                    509:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_QLN_MM )
                    510:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_PRT_MM )
                    511:                   WRKBL = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  512:                   MAXWRK = WRKBL + 2*M*M
                    513:                   MINWRK = BDSPAC + 2*M*M + 3*M
                    514:                ELSE IF( WNTQS ) THEN
                    515: *
1.16      bertrand  516: *                 Path 3t (N >> M, JOBZ='S')
1.1       bertrand  517: *
1.16      bertrand  518:                   WRKBL = M + LWORK_DGELQF_MN
                    519:                   WRKBL = MAX( WRKBL,   M + LWORK_DORGLQ_MN )
                    520:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DGEBRD_MM )
                    521:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_QLN_MM )
                    522:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_PRT_MM )
                    523:                   WRKBL = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  524:                   MAXWRK = WRKBL + M*M
                    525:                   MINWRK = BDSPAC + M*M + 3*M
                    526:                ELSE IF( WNTQA ) THEN
                    527: *
1.16      bertrand  528: *                 Path 4t (N >> M, JOBZ='A')
1.1       bertrand  529: *
1.16      bertrand  530:                   WRKBL = M + LWORK_DGELQF_MN
                    531:                   WRKBL = MAX( WRKBL,   M + LWORK_DORGLQ_NN )
                    532:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DGEBRD_MM )
                    533:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_QLN_MM )
                    534:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_PRT_MM )
                    535:                   WRKBL = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  536:                   MAXWRK = WRKBL + M*M
1.16      bertrand  537:                   MINWRK = M*M + MAX( 3*M + BDSPAC, M + N )
1.1       bertrand  538:                END IF
                    539:             ELSE
                    540: *
1.16      bertrand  541: *              Path 5t (N > M, but not much larger)
1.1       bertrand  542: *
1.16      bertrand  543:                WRKBL = 3*M + LWORK_DGEBRD_MN
1.1       bertrand  544:                IF( WNTQN ) THEN
1.16      bertrand  545: *                 Path 5tn (N > M, jobz='N')
                    546:                   MAXWRK = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  547:                   MINWRK = 3*M + MAX( N, BDSPAC )
                    548:                ELSE IF( WNTQO ) THEN
1.16      bertrand  549: *                 Path 5to (N > M, jobz='O')
                    550:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_QLN_MM )
                    551:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_PRT_MN )
                    552:                   WRKBL = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  553:                   MAXWRK = WRKBL + M*N
1.16      bertrand  554:                   MINWRK = 3*M + MAX( N, M*M + BDSPAC )
1.1       bertrand  555:                ELSE IF( WNTQS ) THEN
1.16      bertrand  556: *                 Path 5ts (N > M, jobz='S')
                    557:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_QLN_MM )
                    558:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_PRT_MN )
                    559:                   MAXWRK = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  560:                   MINWRK = 3*M + MAX( N, BDSPAC )
                    561:                ELSE IF( WNTQA ) THEN
1.16      bertrand  562: *                 Path 5ta (N > M, jobz='A')
                    563:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_QLN_MM )
                    564:                   WRKBL = MAX( WRKBL, 3*M + LWORK_DORMBR_PRT_NN )
                    565:                   MAXWRK = MAX( WRKBL, 3*M + BDSPAC )
1.1       bertrand  566:                   MINWRK = 3*M + MAX( N, BDSPAC )
                    567:                END IF
                    568:             END IF
                    569:          END IF
1.18      bertrand  570: 
1.1       bertrand  571:          MAXWRK = MAX( MAXWRK, MINWRK )
1.22    ! bertrand  572:          WORK( 1 ) = DROUNDUP_LWORK( MAXWRK )
1.1       bertrand  573: *
                    574:          IF( LWORK.LT.MINWRK .AND. .NOT.LQUERY ) THEN
                    575:             INFO = -12
                    576:          END IF
                    577:       END IF
                    578: *
                    579:       IF( INFO.NE.0 ) THEN
                    580:          CALL XERBLA( 'DGESDD', -INFO )
                    581:          RETURN
                    582:       ELSE IF( LQUERY ) THEN
                    583:          RETURN
                    584:       END IF
                    585: *
                    586: *     Quick return if possible
                    587: *
                    588:       IF( M.EQ.0 .OR. N.EQ.0 ) THEN
                    589:          RETURN
                    590:       END IF
                    591: *
                    592: *     Get machine constants
                    593: *
                    594:       EPS = DLAMCH( 'P' )
                    595:       SMLNUM = SQRT( DLAMCH( 'S' ) ) / EPS
                    596:       BIGNUM = ONE / SMLNUM
                    597: *
                    598: *     Scale A if max element outside range [SMLNUM,BIGNUM]
                    599: *
                    600:       ANRM = DLANGE( 'M', M, N, A, LDA, DUM )
1.22    ! bertrand  601:       IF( DISNAN( ANRM ) ) THEN
        !           602:           INFO = -4
        !           603:           RETURN
        !           604:       END IF
1.1       bertrand  605:       ISCL = 0
                    606:       IF( ANRM.GT.ZERO .AND. ANRM.LT.SMLNUM ) THEN
                    607:          ISCL = 1
                    608:          CALL DLASCL( 'G', 0, 0, ANRM, SMLNUM, M, N, A, LDA, IERR )
                    609:       ELSE IF( ANRM.GT.BIGNUM ) THEN
                    610:          ISCL = 1
                    611:          CALL DLASCL( 'G', 0, 0, ANRM, BIGNUM, M, N, A, LDA, IERR )
                    612:       END IF
                    613: *
                    614:       IF( M.GE.N ) THEN
                    615: *
                    616: *        A has at least as many rows as columns. If A has sufficiently
                    617: *        more rows than columns, first reduce using the QR
                    618: *        decomposition (if sufficient workspace available)
                    619: *
                    620:          IF( M.GE.MNTHR ) THEN
                    621: *
                    622:             IF( WNTQN ) THEN
                    623: *
1.16      bertrand  624: *              Path 1 (M >> N, JOBZ='N')
1.1       bertrand  625: *              No singular vectors to be computed
                    626: *
                    627:                ITAU = 1
                    628:                NWORK = ITAU + N
                    629: *
                    630: *              Compute A=Q*R
1.16      bertrand  631: *              Workspace: need   N [tau] + N    [work]
                    632: *              Workspace: prefer N [tau] + N*NB [work]
1.1       bertrand  633: *
                    634:                CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand  635:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  636: *
                    637: *              Zero out below R
                    638: *
                    639:                CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, A( 2, 1 ), LDA )
                    640:                IE = 1
                    641:                ITAUQ = IE + N
                    642:                ITAUP = ITAUQ + N
                    643:                NWORK = ITAUP + N
                    644: *
                    645: *              Bidiagonalize R in A
1.16      bertrand  646: *              Workspace: need   3*N [e, tauq, taup] + N      [work]
                    647: *              Workspace: prefer 3*N [e, tauq, taup] + 2*N*NB [work]
1.1       bertrand  648: *
                    649:                CALL DGEBRD( N, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
                    650:      $                      WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
                    651:      $                      IERR )
                    652:                NWORK = IE + N
                    653: *
                    654: *              Perform bidiagonal SVD, computing singular values only
1.16      bertrand  655: *              Workspace: need   N [e] + BDSPAC
1.1       bertrand  656: *
                    657:                CALL DBDSDC( 'U', 'N', N, S, WORK( IE ), DUM, 1, DUM, 1,
                    658:      $                      DUM, IDUM, WORK( NWORK ), IWORK, INFO )
                    659: *
                    660:             ELSE IF( WNTQO ) THEN
                    661: *
1.16      bertrand  662: *              Path 2 (M >> N, JOBZ = 'O')
1.1       bertrand  663: *              N left singular vectors to be overwritten on A and
                    664: *              N right singular vectors to be computed in VT
                    665: *
                    666:                IR = 1
                    667: *
                    668: *              WORK(IR) is LDWRKR by N
                    669: *
1.16      bertrand  670:                IF( LWORK .GE. LDA*N + N*N + 3*N + BDSPAC ) THEN
1.1       bertrand  671:                   LDWRKR = LDA
                    672:                ELSE
1.16      bertrand  673:                   LDWRKR = ( LWORK - N*N - 3*N - BDSPAC ) / N
1.1       bertrand  674:                END IF
                    675:                ITAU = IR + LDWRKR*N
                    676:                NWORK = ITAU + N
                    677: *
                    678: *              Compute A=Q*R
1.16      bertrand  679: *              Workspace: need   N*N [R] + N [tau] + N    [work]
                    680: *              Workspace: prefer N*N [R] + N [tau] + N*NB [work]
1.1       bertrand  681: *
                    682:                CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand  683:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  684: *
                    685: *              Copy R to WORK(IR), zeroing out below it
                    686: *
                    687:                CALL DLACPY( 'U', N, N, A, LDA, WORK( IR ), LDWRKR )
1.16      bertrand  688:                CALL DLASET( 'L', N - 1, N - 1, ZERO, ZERO, WORK(IR+1),
1.1       bertrand  689:      $                      LDWRKR )
                    690: *
                    691: *              Generate Q in A
1.16      bertrand  692: *              Workspace: need   N*N [R] + N [tau] + N    [work]
                    693: *              Workspace: prefer N*N [R] + N [tau] + N*NB [work]
1.1       bertrand  694: *
                    695:                CALL DORGQR( M, N, N, A, LDA, WORK( ITAU ),
1.16      bertrand  696:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand  697:                IE = ITAU
                    698:                ITAUQ = IE + N
                    699:                ITAUP = ITAUQ + N
                    700:                NWORK = ITAUP + N
                    701: *
1.16      bertrand  702: *              Bidiagonalize R in WORK(IR)
                    703: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + N      [work]
                    704: *              Workspace: prefer N*N [R] + 3*N [e, tauq, taup] + 2*N*NB [work]
1.1       bertrand  705: *
                    706:                CALL DGEBRD( N, N, WORK( IR ), LDWRKR, S, WORK( IE ),
                    707:      $                      WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
1.16      bertrand  708:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  709: *
                    710: *              WORK(IU) is N by N
                    711: *
                    712:                IU = NWORK
                    713:                NWORK = IU + N*N
                    714: *
                    715: *              Perform bidiagonal SVD, computing left singular vectors
                    716: *              of bidiagonal matrix in WORK(IU) and computing right
                    717: *              singular vectors of bidiagonal matrix in VT
1.16      bertrand  718: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + N*N [U] + BDSPAC
1.1       bertrand  719: *
                    720:                CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), WORK( IU ), N,
                    721:      $                      VT, LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                    722:      $                      INFO )
                    723: *
                    724: *              Overwrite WORK(IU) by left singular vectors of R
                    725: *              and VT by right singular vectors of R
1.16      bertrand  726: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + N*N [U] + N    [work]
                    727: *              Workspace: prefer N*N [R] + 3*N [e, tauq, taup] + N*N [U] + N*NB [work]
1.1       bertrand  728: *
                    729:                CALL DORMBR( 'Q', 'L', 'N', N, N, N, WORK( IR ), LDWRKR,
                    730:      $                      WORK( ITAUQ ), WORK( IU ), N, WORK( NWORK ),
1.16      bertrand  731:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  732:                CALL DORMBR( 'P', 'R', 'T', N, N, N, WORK( IR ), LDWRKR,
                    733:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand  734:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  735: *
                    736: *              Multiply Q in A by left singular vectors of R in
                    737: *              WORK(IU), storing result in WORK(IR) and copying to A
1.16      bertrand  738: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + N*N [U]
                    739: *              Workspace: prefer M*N [R] + 3*N [e, tauq, taup] + N*N [U]
1.1       bertrand  740: *
                    741:                DO 10 I = 1, M, LDWRKR
1.16      bertrand  742:                   CHUNK = MIN( M - I + 1, LDWRKR )
1.1       bertrand  743:                   CALL DGEMM( 'N', 'N', CHUNK, N, N, ONE, A( I, 1 ),
                    744:      $                        LDA, WORK( IU ), N, ZERO, WORK( IR ),
                    745:      $                        LDWRKR )
                    746:                   CALL DLACPY( 'F', CHUNK, N, WORK( IR ), LDWRKR,
                    747:      $                         A( I, 1 ), LDA )
                    748:    10          CONTINUE
                    749: *
                    750:             ELSE IF( WNTQS ) THEN
                    751: *
1.16      bertrand  752: *              Path 3 (M >> N, JOBZ='S')
1.1       bertrand  753: *              N left singular vectors to be computed in U and
                    754: *              N right singular vectors to be computed in VT
                    755: *
                    756:                IR = 1
                    757: *
                    758: *              WORK(IR) is N by N
                    759: *
                    760:                LDWRKR = N
                    761:                ITAU = IR + LDWRKR*N
                    762:                NWORK = ITAU + N
                    763: *
                    764: *              Compute A=Q*R
1.16      bertrand  765: *              Workspace: need   N*N [R] + N [tau] + N    [work]
                    766: *              Workspace: prefer N*N [R] + N [tau] + N*NB [work]
1.1       bertrand  767: *
                    768:                CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand  769:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  770: *
                    771: *              Copy R to WORK(IR), zeroing out below it
                    772: *
                    773:                CALL DLACPY( 'U', N, N, A, LDA, WORK( IR ), LDWRKR )
1.16      bertrand  774:                CALL DLASET( 'L', N - 1, N - 1, ZERO, ZERO, WORK(IR+1),
1.1       bertrand  775:      $                      LDWRKR )
                    776: *
                    777: *              Generate Q in A
1.16      bertrand  778: *              Workspace: need   N*N [R] + N [tau] + N    [work]
                    779: *              Workspace: prefer N*N [R] + N [tau] + N*NB [work]
1.1       bertrand  780: *
                    781:                CALL DORGQR( M, N, N, A, LDA, WORK( ITAU ),
1.16      bertrand  782:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand  783:                IE = ITAU
                    784:                ITAUQ = IE + N
                    785:                ITAUP = ITAUQ + N
                    786:                NWORK = ITAUP + N
                    787: *
                    788: *              Bidiagonalize R in WORK(IR)
1.16      bertrand  789: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + N      [work]
                    790: *              Workspace: prefer N*N [R] + 3*N [e, tauq, taup] + 2*N*NB [work]
1.1       bertrand  791: *
                    792:                CALL DGEBRD( N, N, WORK( IR ), LDWRKR, S, WORK( IE ),
                    793:      $                      WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
1.16      bertrand  794:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  795: *
                    796: *              Perform bidiagonal SVD, computing left singular vectors
                    797: *              of bidiagoal matrix in U and computing right singular
                    798: *              vectors of bidiagonal matrix in VT
1.16      bertrand  799: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + BDSPAC
1.1       bertrand  800: *
                    801:                CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), U, LDU, VT,
                    802:      $                      LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                    803:      $                      INFO )
                    804: *
                    805: *              Overwrite U by left singular vectors of R and VT
                    806: *              by right singular vectors of R
1.16      bertrand  807: *              Workspace: need   N*N [R] + 3*N [e, tauq, taup] + N    [work]
                    808: *              Workspace: prefer N*N [R] + 3*N [e, tauq, taup] + N*NB [work]
1.1       bertrand  809: *
                    810:                CALL DORMBR( 'Q', 'L', 'N', N, N, N, WORK( IR ), LDWRKR,
                    811:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand  812:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  813: *
                    814:                CALL DORMBR( 'P', 'R', 'T', N, N, N, WORK( IR ), LDWRKR,
                    815:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand  816:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  817: *
                    818: *              Multiply Q in A by left singular vectors of R in
                    819: *              WORK(IR), storing result in U
1.16      bertrand  820: *              Workspace: need   N*N [R]
1.1       bertrand  821: *
                    822:                CALL DLACPY( 'F', N, N, U, LDU, WORK( IR ), LDWRKR )
                    823:                CALL DGEMM( 'N', 'N', M, N, N, ONE, A, LDA, WORK( IR ),
                    824:      $                     LDWRKR, ZERO, U, LDU )
                    825: *
                    826:             ELSE IF( WNTQA ) THEN
                    827: *
1.16      bertrand  828: *              Path 4 (M >> N, JOBZ='A')
1.1       bertrand  829: *              M left singular vectors to be computed in U and
                    830: *              N right singular vectors to be computed in VT
                    831: *
                    832:                IU = 1
                    833: *
                    834: *              WORK(IU) is N by N
                    835: *
                    836:                LDWRKU = N
                    837:                ITAU = IU + LDWRKU*N
                    838:                NWORK = ITAU + N
                    839: *
                    840: *              Compute A=Q*R, copying result to U
1.16      bertrand  841: *              Workspace: need   N*N [U] + N [tau] + N    [work]
                    842: *              Workspace: prefer N*N [U] + N [tau] + N*NB [work]
1.1       bertrand  843: *
                    844:                CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand  845:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  846:                CALL DLACPY( 'L', M, N, A, LDA, U, LDU )
                    847: *
                    848: *              Generate Q in U
1.16      bertrand  849: *              Workspace: need   N*N [U] + N [tau] + M    [work]
                    850: *              Workspace: prefer N*N [U] + N [tau] + M*NB [work]
1.1       bertrand  851:                CALL DORGQR( M, M, N, U, LDU, WORK( ITAU ),
1.16      bertrand  852:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand  853: *
                    854: *              Produce R in A, zeroing out other entries
                    855: *
                    856:                CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, A( 2, 1 ), LDA )
                    857:                IE = ITAU
                    858:                ITAUQ = IE + N
                    859:                ITAUP = ITAUQ + N
                    860:                NWORK = ITAUP + N
                    861: *
                    862: *              Bidiagonalize R in A
1.16      bertrand  863: *              Workspace: need   N*N [U] + 3*N [e, tauq, taup] + N      [work]
                    864: *              Workspace: prefer N*N [U] + 3*N [e, tauq, taup] + 2*N*NB [work]
1.1       bertrand  865: *
                    866:                CALL DGEBRD( N, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
                    867:      $                      WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
                    868:      $                      IERR )
                    869: *
                    870: *              Perform bidiagonal SVD, computing left singular vectors
                    871: *              of bidiagonal matrix in WORK(IU) and computing right
                    872: *              singular vectors of bidiagonal matrix in VT
1.16      bertrand  873: *              Workspace: need   N*N [U] + 3*N [e, tauq, taup] + BDSPAC
1.1       bertrand  874: *
                    875:                CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), WORK( IU ), N,
                    876:      $                      VT, LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                    877:      $                      INFO )
                    878: *
                    879: *              Overwrite WORK(IU) by left singular vectors of R and VT
                    880: *              by right singular vectors of R
1.16      bertrand  881: *              Workspace: need   N*N [U] + 3*N [e, tauq, taup] + N    [work]
                    882: *              Workspace: prefer N*N [U] + 3*N [e, tauq, taup] + N*NB [work]
1.1       bertrand  883: *
                    884:                CALL DORMBR( 'Q', 'L', 'N', N, N, N, A, LDA,
                    885:      $                      WORK( ITAUQ ), WORK( IU ), LDWRKU,
1.16      bertrand  886:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand  887:                CALL DORMBR( 'P', 'R', 'T', N, N, N, A, LDA,
                    888:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand  889:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  890: *
                    891: *              Multiply Q in U by left singular vectors of R in
                    892: *              WORK(IU), storing result in A
1.16      bertrand  893: *              Workspace: need   N*N [U]
1.1       bertrand  894: *
                    895:                CALL DGEMM( 'N', 'N', M, N, N, ONE, U, LDU, WORK( IU ),
                    896:      $                     LDWRKU, ZERO, A, LDA )
                    897: *
                    898: *              Copy left singular vectors of A from A to U
                    899: *
                    900:                CALL DLACPY( 'F', M, N, A, LDA, U, LDU )
                    901: *
                    902:             END IF
                    903: *
                    904:          ELSE
                    905: *
                    906: *           M .LT. MNTHR
                    907: *
1.16      bertrand  908: *           Path 5 (M >= N, but not much larger)
1.1       bertrand  909: *           Reduce to bidiagonal form without QR decomposition
                    910: *
                    911:             IE = 1
                    912:             ITAUQ = IE + N
                    913:             ITAUP = ITAUQ + N
                    914:             NWORK = ITAUP + N
                    915: *
                    916: *           Bidiagonalize A
1.16      bertrand  917: *           Workspace: need   3*N [e, tauq, taup] + M        [work]
                    918: *           Workspace: prefer 3*N [e, tauq, taup] + (M+N)*NB [work]
1.1       bertrand  919: *
                    920:             CALL DGEBRD( M, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
                    921:      $                   WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
                    922:      $                   IERR )
                    923:             IF( WNTQN ) THEN
                    924: *
1.16      bertrand  925: *              Path 5n (M >= N, JOBZ='N')
1.1       bertrand  926: *              Perform bidiagonal SVD, only computing singular values
1.16      bertrand  927: *              Workspace: need   3*N [e, tauq, taup] + BDSPAC
1.1       bertrand  928: *
                    929:                CALL DBDSDC( 'U', 'N', N, S, WORK( IE ), DUM, 1, DUM, 1,
                    930:      $                      DUM, IDUM, WORK( NWORK ), IWORK, INFO )
                    931:             ELSE IF( WNTQO ) THEN
1.16      bertrand  932: *              Path 5o (M >= N, JOBZ='O')
1.1       bertrand  933:                IU = NWORK
1.16      bertrand  934:                IF( LWORK .GE. M*N + 3*N + BDSPAC ) THEN
1.1       bertrand  935: *
                    936: *                 WORK( IU ) is M by N
                    937: *
                    938:                   LDWRKU = M
                    939:                   NWORK = IU + LDWRKU*N
                    940:                   CALL DLASET( 'F', M, N, ZERO, ZERO, WORK( IU ),
                    941:      $                         LDWRKU )
1.16      bertrand  942: *                 IR is unused; silence compile warnings
                    943:                   IR = -1
1.1       bertrand  944:                ELSE
                    945: *
                    946: *                 WORK( IU ) is N by N
                    947: *
                    948:                   LDWRKU = N
                    949:                   NWORK = IU + LDWRKU*N
                    950: *
                    951: *                 WORK(IR) is LDWRKR by N
                    952: *
                    953:                   IR = NWORK
1.16      bertrand  954:                   LDWRKR = ( LWORK - N*N - 3*N ) / N
1.1       bertrand  955:                END IF
                    956:                NWORK = IU + LDWRKU*N
                    957: *
                    958: *              Perform bidiagonal SVD, computing left singular vectors
                    959: *              of bidiagonal matrix in WORK(IU) and computing right
                    960: *              singular vectors of bidiagonal matrix in VT
1.16      bertrand  961: *              Workspace: need   3*N [e, tauq, taup] + N*N [U] + BDSPAC
1.1       bertrand  962: *
                    963:                CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), WORK( IU ),
                    964:      $                      LDWRKU, VT, LDVT, DUM, IDUM, WORK( NWORK ),
                    965:      $                      IWORK, INFO )
                    966: *
                    967: *              Overwrite VT by right singular vectors of A
1.16      bertrand  968: *              Workspace: need   3*N [e, tauq, taup] + N*N [U] + N    [work]
                    969: *              Workspace: prefer 3*N [e, tauq, taup] + N*N [U] + N*NB [work]
1.1       bertrand  970: *
                    971:                CALL DORMBR( 'P', 'R', 'T', N, N, N, A, LDA,
                    972:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand  973:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand  974: *
1.16      bertrand  975:                IF( LWORK .GE. M*N + 3*N + BDSPAC ) THEN
1.1       bertrand  976: *
1.16      bertrand  977: *                 Path 5o-fast
1.1       bertrand  978: *                 Overwrite WORK(IU) by left singular vectors of A
1.16      bertrand  979: *                 Workspace: need   3*N [e, tauq, taup] + M*N [U] + N    [work]
                    980: *                 Workspace: prefer 3*N [e, tauq, taup] + M*N [U] + N*NB [work]
1.1       bertrand  981: *
                    982:                   CALL DORMBR( 'Q', 'L', 'N', M, N, N, A, LDA,
                    983:      $                         WORK( ITAUQ ), WORK( IU ), LDWRKU,
1.16      bertrand  984:      $                         WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand  985: *
                    986: *                 Copy left singular vectors of A from WORK(IU) to A
                    987: *
                    988:                   CALL DLACPY( 'F', M, N, WORK( IU ), LDWRKU, A, LDA )
                    989:                ELSE
                    990: *
1.16      bertrand  991: *                 Path 5o-slow
1.1       bertrand  992: *                 Generate Q in A
1.16      bertrand  993: *                 Workspace: need   3*N [e, tauq, taup] + N*N [U] + N    [work]
                    994: *                 Workspace: prefer 3*N [e, tauq, taup] + N*N [U] + N*NB [work]
1.1       bertrand  995: *
                    996:                   CALL DORGBR( 'Q', M, N, N, A, LDA, WORK( ITAUQ ),
1.16      bertrand  997:      $                         WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand  998: *
                    999: *                 Multiply Q in A by left singular vectors of
                   1000: *                 bidiagonal matrix in WORK(IU), storing result in
                   1001: *                 WORK(IR) and copying to A
1.16      bertrand 1002: *                 Workspace: need   3*N [e, tauq, taup] + N*N [U] + NB*N [R]
                   1003: *                 Workspace: prefer 3*N [e, tauq, taup] + N*N [U] + M*N  [R]
1.1       bertrand 1004: *
                   1005:                   DO 20 I = 1, M, LDWRKR
1.16      bertrand 1006:                      CHUNK = MIN( M - I + 1, LDWRKR )
1.1       bertrand 1007:                      CALL DGEMM( 'N', 'N', CHUNK, N, N, ONE, A( I, 1 ),
                   1008:      $                           LDA, WORK( IU ), LDWRKU, ZERO,
                   1009:      $                           WORK( IR ), LDWRKR )
                   1010:                      CALL DLACPY( 'F', CHUNK, N, WORK( IR ), LDWRKR,
                   1011:      $                            A( I, 1 ), LDA )
                   1012:    20             CONTINUE
                   1013:                END IF
                   1014: *
                   1015:             ELSE IF( WNTQS ) THEN
                   1016: *
1.16      bertrand 1017: *              Path 5s (M >= N, JOBZ='S')
1.1       bertrand 1018: *              Perform bidiagonal SVD, computing left singular vectors
                   1019: *              of bidiagonal matrix in U and computing right singular
                   1020: *              vectors of bidiagonal matrix in VT
1.16      bertrand 1021: *              Workspace: need   3*N [e, tauq, taup] + BDSPAC
1.1       bertrand 1022: *
                   1023:                CALL DLASET( 'F', M, N, ZERO, ZERO, U, LDU )
                   1024:                CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), U, LDU, VT,
                   1025:      $                      LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                   1026:      $                      INFO )
                   1027: *
                   1028: *              Overwrite U by left singular vectors of A and VT
                   1029: *              by right singular vectors of A
1.16      bertrand 1030: *              Workspace: need   3*N [e, tauq, taup] + N    [work]
                   1031: *              Workspace: prefer 3*N [e, tauq, taup] + N*NB [work]
1.1       bertrand 1032: *
                   1033:                CALL DORMBR( 'Q', 'L', 'N', M, N, N, A, LDA,
                   1034:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1035:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1036:                CALL DORMBR( 'P', 'R', 'T', N, N, N, A, LDA,
                   1037:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand 1038:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1039:             ELSE IF( WNTQA ) THEN
                   1040: *
1.16      bertrand 1041: *              Path 5a (M >= N, JOBZ='A')
1.1       bertrand 1042: *              Perform bidiagonal SVD, computing left singular vectors
                   1043: *              of bidiagonal matrix in U and computing right singular
                   1044: *              vectors of bidiagonal matrix in VT
1.16      bertrand 1045: *              Workspace: need   3*N [e, tauq, taup] + BDSPAC
1.1       bertrand 1046: *
                   1047:                CALL DLASET( 'F', M, M, ZERO, ZERO, U, LDU )
                   1048:                CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), U, LDU, VT,
                   1049:      $                      LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                   1050:      $                      INFO )
                   1051: *
                   1052: *              Set the right corner of U to identity matrix
                   1053: *
                   1054:                IF( M.GT.N ) THEN
1.16      bertrand 1055:                   CALL DLASET( 'F', M - N, M - N, ZERO, ONE, U(N+1,N+1),
1.1       bertrand 1056:      $                         LDU )
                   1057:                END IF
                   1058: *
                   1059: *              Overwrite U by left singular vectors of A and VT
                   1060: *              by right singular vectors of A
1.16      bertrand 1061: *              Workspace: need   3*N [e, tauq, taup] + M    [work]
                   1062: *              Workspace: prefer 3*N [e, tauq, taup] + M*NB [work]
1.1       bertrand 1063: *
                   1064:                CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
                   1065:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1066:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1067:                CALL DORMBR( 'P', 'R', 'T', N, N, M, A, LDA,
                   1068:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand 1069:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1070:             END IF
                   1071: *
                   1072:          END IF
                   1073: *
                   1074:       ELSE
                   1075: *
                   1076: *        A has more columns than rows. If A has sufficiently more
                   1077: *        columns than rows, first reduce using the LQ decomposition (if
                   1078: *        sufficient workspace available)
                   1079: *
                   1080:          IF( N.GE.MNTHR ) THEN
                   1081: *
                   1082:             IF( WNTQN ) THEN
                   1083: *
1.16      bertrand 1084: *              Path 1t (N >> M, JOBZ='N')
1.1       bertrand 1085: *              No singular vectors to be computed
                   1086: *
                   1087:                ITAU = 1
                   1088:                NWORK = ITAU + M
                   1089: *
                   1090: *              Compute A=L*Q
1.16      bertrand 1091: *              Workspace: need   M [tau] + M [work]
                   1092: *              Workspace: prefer M [tau] + M*NB [work]
1.1       bertrand 1093: *
                   1094:                CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand 1095:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1096: *
                   1097: *              Zero out above L
                   1098: *
                   1099:                CALL DLASET( 'U', M-1, M-1, ZERO, ZERO, A( 1, 2 ), LDA )
                   1100:                IE = 1
                   1101:                ITAUQ = IE + M
                   1102:                ITAUP = ITAUQ + M
                   1103:                NWORK = ITAUP + M
                   1104: *
                   1105: *              Bidiagonalize L in A
1.16      bertrand 1106: *              Workspace: need   3*M [e, tauq, taup] + M      [work]
                   1107: *              Workspace: prefer 3*M [e, tauq, taup] + 2*M*NB [work]
1.1       bertrand 1108: *
                   1109:                CALL DGEBRD( M, M, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
                   1110:      $                      WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
                   1111:      $                      IERR )
                   1112:                NWORK = IE + M
                   1113: *
                   1114: *              Perform bidiagonal SVD, computing singular values only
1.16      bertrand 1115: *              Workspace: need   M [e] + BDSPAC
1.1       bertrand 1116: *
                   1117:                CALL DBDSDC( 'U', 'N', M, S, WORK( IE ), DUM, 1, DUM, 1,
                   1118:      $                      DUM, IDUM, WORK( NWORK ), IWORK, INFO )
                   1119: *
                   1120:             ELSE IF( WNTQO ) THEN
                   1121: *
1.16      bertrand 1122: *              Path 2t (N >> M, JOBZ='O')
1.1       bertrand 1123: *              M right singular vectors to be overwritten on A and
                   1124: *              M left singular vectors to be computed in U
                   1125: *
                   1126:                IVT = 1
                   1127: *
1.16      bertrand 1128: *              WORK(IVT) is M by M
                   1129: *              WORK(IL)  is M by M; it is later resized to M by chunk for gemm
1.1       bertrand 1130: *
                   1131:                IL = IVT + M*M
1.16      bertrand 1132:                IF( LWORK .GE. M*N + M*M + 3*M + BDSPAC ) THEN
1.1       bertrand 1133:                   LDWRKL = M
                   1134:                   CHUNK = N
                   1135:                ELSE
                   1136:                   LDWRKL = M
1.16      bertrand 1137:                   CHUNK = ( LWORK - M*M ) / M
1.1       bertrand 1138:                END IF
                   1139:                ITAU = IL + LDWRKL*M
                   1140:                NWORK = ITAU + M
                   1141: *
                   1142: *              Compute A=L*Q
1.16      bertrand 1143: *              Workspace: need   M*M [VT] + M*M [L] + M [tau] + M    [work]
                   1144: *              Workspace: prefer M*M [VT] + M*M [L] + M [tau] + M*NB [work]
1.1       bertrand 1145: *
                   1146:                CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand 1147:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1148: *
                   1149: *              Copy L to WORK(IL), zeroing about above it
                   1150: *
                   1151:                CALL DLACPY( 'L', M, M, A, LDA, WORK( IL ), LDWRKL )
1.16      bertrand 1152:                CALL DLASET( 'U', M - 1, M - 1, ZERO, ZERO,
                   1153:      $                      WORK( IL + LDWRKL ), LDWRKL )
1.1       bertrand 1154: *
                   1155: *              Generate Q in A
1.16      bertrand 1156: *              Workspace: need   M*M [VT] + M*M [L] + M [tau] + M    [work]
                   1157: *              Workspace: prefer M*M [VT] + M*M [L] + M [tau] + M*NB [work]
1.1       bertrand 1158: *
                   1159:                CALL DORGLQ( M, N, M, A, LDA, WORK( ITAU ),
1.16      bertrand 1160:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1161:                IE = ITAU
                   1162:                ITAUQ = IE + M
                   1163:                ITAUP = ITAUQ + M
                   1164:                NWORK = ITAUP + M
                   1165: *
                   1166: *              Bidiagonalize L in WORK(IL)
1.16      bertrand 1167: *              Workspace: need   M*M [VT] + M*M [L] + 3*M [e, tauq, taup] + M      [work]
                   1168: *              Workspace: prefer M*M [VT] + M*M [L] + 3*M [e, tauq, taup] + 2*M*NB [work]
1.1       bertrand 1169: *
                   1170:                CALL DGEBRD( M, M, WORK( IL ), LDWRKL, S, WORK( IE ),
                   1171:      $                      WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
1.16      bertrand 1172:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1173: *
                   1174: *              Perform bidiagonal SVD, computing left singular vectors
                   1175: *              of bidiagonal matrix in U, and computing right singular
                   1176: *              vectors of bidiagonal matrix in WORK(IVT)
1.16      bertrand 1177: *              Workspace: need   M*M [VT] + M*M [L] + 3*M [e, tauq, taup] + BDSPAC
1.1       bertrand 1178: *
                   1179:                CALL DBDSDC( 'U', 'I', M, S, WORK( IE ), U, LDU,
                   1180:      $                      WORK( IVT ), M, DUM, IDUM, WORK( NWORK ),
                   1181:      $                      IWORK, INFO )
                   1182: *
                   1183: *              Overwrite U by left singular vectors of L and WORK(IVT)
                   1184: *              by right singular vectors of L
1.16      bertrand 1185: *              Workspace: need   M*M [VT] + M*M [L] + 3*M [e, tauq, taup] + M    [work]
                   1186: *              Workspace: prefer M*M [VT] + M*M [L] + 3*M [e, tauq, taup] + M*NB [work]
1.1       bertrand 1187: *
                   1188:                CALL DORMBR( 'Q', 'L', 'N', M, M, M, WORK( IL ), LDWRKL,
                   1189:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1190:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1191:                CALL DORMBR( 'P', 'R', 'T', M, M, M, WORK( IL ), LDWRKL,
                   1192:      $                      WORK( ITAUP ), WORK( IVT ), M,
1.16      bertrand 1193:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1194: *
                   1195: *              Multiply right singular vectors of L in WORK(IVT) by Q
                   1196: *              in A, storing result in WORK(IL) and copying to A
1.16      bertrand 1197: *              Workspace: need   M*M [VT] + M*M [L]
                   1198: *              Workspace: prefer M*M [VT] + M*N [L]
                   1199: *              At this point, L is resized as M by chunk.
1.1       bertrand 1200: *
                   1201:                DO 30 I = 1, N, CHUNK
1.16      bertrand 1202:                   BLK = MIN( N - I + 1, CHUNK )
1.1       bertrand 1203:                   CALL DGEMM( 'N', 'N', M, BLK, M, ONE, WORK( IVT ), M,
                   1204:      $                        A( 1, I ), LDA, ZERO, WORK( IL ), LDWRKL )
                   1205:                   CALL DLACPY( 'F', M, BLK, WORK( IL ), LDWRKL,
                   1206:      $                         A( 1, I ), LDA )
                   1207:    30          CONTINUE
                   1208: *
                   1209:             ELSE IF( WNTQS ) THEN
                   1210: *
1.16      bertrand 1211: *              Path 3t (N >> M, JOBZ='S')
1.1       bertrand 1212: *              M right singular vectors to be computed in VT and
                   1213: *              M left singular vectors to be computed in U
                   1214: *
                   1215:                IL = 1
                   1216: *
                   1217: *              WORK(IL) is M by M
                   1218: *
                   1219:                LDWRKL = M
                   1220:                ITAU = IL + LDWRKL*M
                   1221:                NWORK = ITAU + M
                   1222: *
                   1223: *              Compute A=L*Q
1.16      bertrand 1224: *              Workspace: need   M*M [L] + M [tau] + M    [work]
                   1225: *              Workspace: prefer M*M [L] + M [tau] + M*NB [work]
1.1       bertrand 1226: *
                   1227:                CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand 1228:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1229: *
                   1230: *              Copy L to WORK(IL), zeroing out above it
                   1231: *
                   1232:                CALL DLACPY( 'L', M, M, A, LDA, WORK( IL ), LDWRKL )
1.16      bertrand 1233:                CALL DLASET( 'U', M - 1, M - 1, ZERO, ZERO,
                   1234:      $                      WORK( IL + LDWRKL ), LDWRKL )
1.1       bertrand 1235: *
                   1236: *              Generate Q in A
1.16      bertrand 1237: *              Workspace: need   M*M [L] + M [tau] + M    [work]
                   1238: *              Workspace: prefer M*M [L] + M [tau] + M*NB [work]
1.1       bertrand 1239: *
                   1240:                CALL DORGLQ( M, N, M, A, LDA, WORK( ITAU ),
1.16      bertrand 1241:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1242:                IE = ITAU
                   1243:                ITAUQ = IE + M
                   1244:                ITAUP = ITAUQ + M
                   1245:                NWORK = ITAUP + M
                   1246: *
1.16      bertrand 1247: *              Bidiagonalize L in WORK(IU).
                   1248: *              Workspace: need   M*M [L] + 3*M [e, tauq, taup] + M      [work]
                   1249: *              Workspace: prefer M*M [L] + 3*M [e, tauq, taup] + 2*M*NB [work]
1.1       bertrand 1250: *
                   1251:                CALL DGEBRD( M, M, WORK( IL ), LDWRKL, S, WORK( IE ),
                   1252:      $                      WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
1.16      bertrand 1253:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1254: *
                   1255: *              Perform bidiagonal SVD, computing left singular vectors
                   1256: *              of bidiagonal matrix in U and computing right singular
                   1257: *              vectors of bidiagonal matrix in VT
1.16      bertrand 1258: *              Workspace: need   M*M [L] + 3*M [e, tauq, taup] + BDSPAC
1.1       bertrand 1259: *
                   1260:                CALL DBDSDC( 'U', 'I', M, S, WORK( IE ), U, LDU, VT,
                   1261:      $                      LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                   1262:      $                      INFO )
                   1263: *
                   1264: *              Overwrite U by left singular vectors of L and VT
                   1265: *              by right singular vectors of L
1.16      bertrand 1266: *              Workspace: need   M*M [L] + 3*M [e, tauq, taup] + M    [work]
                   1267: *              Workspace: prefer M*M [L] + 3*M [e, tauq, taup] + M*NB [work]
1.1       bertrand 1268: *
                   1269:                CALL DORMBR( 'Q', 'L', 'N', M, M, M, WORK( IL ), LDWRKL,
                   1270:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1271:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1272:                CALL DORMBR( 'P', 'R', 'T', M, M, M, WORK( IL ), LDWRKL,
                   1273:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand 1274:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1275: *
                   1276: *              Multiply right singular vectors of L in WORK(IL) by
                   1277: *              Q in A, storing result in VT
1.16      bertrand 1278: *              Workspace: need   M*M [L]
1.1       bertrand 1279: *
                   1280:                CALL DLACPY( 'F', M, M, VT, LDVT, WORK( IL ), LDWRKL )
                   1281:                CALL DGEMM( 'N', 'N', M, N, M, ONE, WORK( IL ), LDWRKL,
                   1282:      $                     A, LDA, ZERO, VT, LDVT )
                   1283: *
                   1284:             ELSE IF( WNTQA ) THEN
                   1285: *
1.16      bertrand 1286: *              Path 4t (N >> M, JOBZ='A')
1.1       bertrand 1287: *              N right singular vectors to be computed in VT and
                   1288: *              M left singular vectors to be computed in U
                   1289: *
                   1290:                IVT = 1
                   1291: *
                   1292: *              WORK(IVT) is M by M
                   1293: *
                   1294:                LDWKVT = M
                   1295:                ITAU = IVT + LDWKVT*M
                   1296:                NWORK = ITAU + M
                   1297: *
                   1298: *              Compute A=L*Q, copying result to VT
1.16      bertrand 1299: *              Workspace: need   M*M [VT] + M [tau] + M    [work]
                   1300: *              Workspace: prefer M*M [VT] + M [tau] + M*NB [work]
1.1       bertrand 1301: *
                   1302:                CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1.16      bertrand 1303:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1304:                CALL DLACPY( 'U', M, N, A, LDA, VT, LDVT )
                   1305: *
                   1306: *              Generate Q in VT
1.16      bertrand 1307: *              Workspace: need   M*M [VT] + M [tau] + N    [work]
                   1308: *              Workspace: prefer M*M [VT] + M [tau] + N*NB [work]
1.1       bertrand 1309: *
                   1310:                CALL DORGLQ( N, N, M, VT, LDVT, WORK( ITAU ),
1.16      bertrand 1311:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1312: *
                   1313: *              Produce L in A, zeroing out other entries
                   1314: *
                   1315:                CALL DLASET( 'U', M-1, M-1, ZERO, ZERO, A( 1, 2 ), LDA )
                   1316:                IE = ITAU
                   1317:                ITAUQ = IE + M
                   1318:                ITAUP = ITAUQ + M
                   1319:                NWORK = ITAUP + M
                   1320: *
                   1321: *              Bidiagonalize L in A
1.16      bertrand 1322: *              Workspace: need   M*M [VT] + 3*M [e, tauq, taup] + M      [work]
                   1323: *              Workspace: prefer M*M [VT] + 3*M [e, tauq, taup] + 2*M*NB [work]
1.1       bertrand 1324: *
                   1325:                CALL DGEBRD( M, M, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
                   1326:      $                      WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
                   1327:      $                      IERR )
                   1328: *
                   1329: *              Perform bidiagonal SVD, computing left singular vectors
                   1330: *              of bidiagonal matrix in U and computing right singular
                   1331: *              vectors of bidiagonal matrix in WORK(IVT)
1.16      bertrand 1332: *              Workspace: need   M*M [VT] + 3*M [e, tauq, taup] + BDSPAC
1.1       bertrand 1333: *
                   1334:                CALL DBDSDC( 'U', 'I', M, S, WORK( IE ), U, LDU,
                   1335:      $                      WORK( IVT ), LDWKVT, DUM, IDUM,
                   1336:      $                      WORK( NWORK ), IWORK, INFO )
                   1337: *
                   1338: *              Overwrite U by left singular vectors of L and WORK(IVT)
                   1339: *              by right singular vectors of L
1.16      bertrand 1340: *              Workspace: need   M*M [VT] + 3*M [e, tauq, taup]+ M    [work]
                   1341: *              Workspace: prefer M*M [VT] + 3*M [e, tauq, taup]+ M*NB [work]
1.1       bertrand 1342: *
                   1343:                CALL DORMBR( 'Q', 'L', 'N', M, M, M, A, LDA,
                   1344:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1345:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1346:                CALL DORMBR( 'P', 'R', 'T', M, M, M, A, LDA,
                   1347:      $                      WORK( ITAUP ), WORK( IVT ), LDWKVT,
1.16      bertrand 1348:      $                      WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1349: *
                   1350: *              Multiply right singular vectors of L in WORK(IVT) by
                   1351: *              Q in VT, storing result in A
1.16      bertrand 1352: *              Workspace: need   M*M [VT]
1.1       bertrand 1353: *
                   1354:                CALL DGEMM( 'N', 'N', M, N, M, ONE, WORK( IVT ), LDWKVT,
                   1355:      $                     VT, LDVT, ZERO, A, LDA )
                   1356: *
                   1357: *              Copy right singular vectors of A from A to VT
                   1358: *
                   1359:                CALL DLACPY( 'F', M, N, A, LDA, VT, LDVT )
                   1360: *
                   1361:             END IF
                   1362: *
                   1363:          ELSE
                   1364: *
                   1365: *           N .LT. MNTHR
                   1366: *
1.16      bertrand 1367: *           Path 5t (N > M, but not much larger)
1.1       bertrand 1368: *           Reduce to bidiagonal form without LQ decomposition
                   1369: *
                   1370:             IE = 1
                   1371:             ITAUQ = IE + M
                   1372:             ITAUP = ITAUQ + M
                   1373:             NWORK = ITAUP + M
                   1374: *
                   1375: *           Bidiagonalize A
1.16      bertrand 1376: *           Workspace: need   3*M [e, tauq, taup] + N        [work]
                   1377: *           Workspace: prefer 3*M [e, tauq, taup] + (M+N)*NB [work]
1.1       bertrand 1378: *
                   1379:             CALL DGEBRD( M, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
                   1380:      $                   WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
                   1381:      $                   IERR )
                   1382:             IF( WNTQN ) THEN
                   1383: *
1.16      bertrand 1384: *              Path 5tn (N > M, JOBZ='N')
1.1       bertrand 1385: *              Perform bidiagonal SVD, only computing singular values
1.16      bertrand 1386: *              Workspace: need   3*M [e, tauq, taup] + BDSPAC
1.1       bertrand 1387: *
                   1388:                CALL DBDSDC( 'L', 'N', M, S, WORK( IE ), DUM, 1, DUM, 1,
                   1389:      $                      DUM, IDUM, WORK( NWORK ), IWORK, INFO )
                   1390:             ELSE IF( WNTQO ) THEN
1.16      bertrand 1391: *              Path 5to (N > M, JOBZ='O')
1.1       bertrand 1392:                LDWKVT = M
                   1393:                IVT = NWORK
1.16      bertrand 1394:                IF( LWORK .GE. M*N + 3*M + BDSPAC ) THEN
1.1       bertrand 1395: *
                   1396: *                 WORK( IVT ) is M by N
                   1397: *
                   1398:                   CALL DLASET( 'F', M, N, ZERO, ZERO, WORK( IVT ),
                   1399:      $                         LDWKVT )
                   1400:                   NWORK = IVT + LDWKVT*N
1.16      bertrand 1401: *                 IL is unused; silence compile warnings
                   1402:                   IL = -1
1.1       bertrand 1403:                ELSE
                   1404: *
                   1405: *                 WORK( IVT ) is M by M
                   1406: *
                   1407:                   NWORK = IVT + LDWKVT*M
                   1408:                   IL = NWORK
                   1409: *
                   1410: *                 WORK(IL) is M by CHUNK
                   1411: *
1.16      bertrand 1412:                   CHUNK = ( LWORK - M*M - 3*M ) / M
1.1       bertrand 1413:                END IF
                   1414: *
                   1415: *              Perform bidiagonal SVD, computing left singular vectors
                   1416: *              of bidiagonal matrix in U and computing right singular
                   1417: *              vectors of bidiagonal matrix in WORK(IVT)
1.16      bertrand 1418: *              Workspace: need   3*M [e, tauq, taup] + M*M [VT] + BDSPAC
1.1       bertrand 1419: *
                   1420:                CALL DBDSDC( 'L', 'I', M, S, WORK( IE ), U, LDU,
                   1421:      $                      WORK( IVT ), LDWKVT, DUM, IDUM,
                   1422:      $                      WORK( NWORK ), IWORK, INFO )
                   1423: *
                   1424: *              Overwrite U by left singular vectors of A
1.16      bertrand 1425: *              Workspace: need   3*M [e, tauq, taup] + M*M [VT] + M    [work]
                   1426: *              Workspace: prefer 3*M [e, tauq, taup] + M*M [VT] + M*NB [work]
1.1       bertrand 1427: *
                   1428:                CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
                   1429:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1430:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1431: *
1.16      bertrand 1432:                IF( LWORK .GE. M*N + 3*M + BDSPAC ) THEN
1.1       bertrand 1433: *
1.16      bertrand 1434: *                 Path 5to-fast
1.1       bertrand 1435: *                 Overwrite WORK(IVT) by left singular vectors of A
1.16      bertrand 1436: *                 Workspace: need   3*M [e, tauq, taup] + M*N [VT] + M    [work]
                   1437: *                 Workspace: prefer 3*M [e, tauq, taup] + M*N [VT] + M*NB [work]
1.1       bertrand 1438: *
                   1439:                   CALL DORMBR( 'P', 'R', 'T', M, N, M, A, LDA,
                   1440:      $                         WORK( ITAUP ), WORK( IVT ), LDWKVT,
1.16      bertrand 1441:      $                         WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1442: *
                   1443: *                 Copy right singular vectors of A from WORK(IVT) to A
                   1444: *
                   1445:                   CALL DLACPY( 'F', M, N, WORK( IVT ), LDWKVT, A, LDA )
                   1446:                ELSE
                   1447: *
1.16      bertrand 1448: *                 Path 5to-slow
1.1       bertrand 1449: *                 Generate P**T in A
1.16      bertrand 1450: *                 Workspace: need   3*M [e, tauq, taup] + M*M [VT] + M    [work]
                   1451: *                 Workspace: prefer 3*M [e, tauq, taup] + M*M [VT] + M*NB [work]
1.1       bertrand 1452: *
                   1453:                   CALL DORGBR( 'P', M, N, M, A, LDA, WORK( ITAUP ),
1.16      bertrand 1454:      $                         WORK( NWORK ), LWORK - NWORK + 1, IERR )
1.1       bertrand 1455: *
                   1456: *                 Multiply Q in A by right singular vectors of
                   1457: *                 bidiagonal matrix in WORK(IVT), storing result in
                   1458: *                 WORK(IL) and copying to A
1.16      bertrand 1459: *                 Workspace: need   3*M [e, tauq, taup] + M*M [VT] + M*NB [L]
                   1460: *                 Workspace: prefer 3*M [e, tauq, taup] + M*M [VT] + M*N  [L]
1.1       bertrand 1461: *
                   1462:                   DO 40 I = 1, N, CHUNK
1.16      bertrand 1463:                      BLK = MIN( N - I + 1, CHUNK )
1.1       bertrand 1464:                      CALL DGEMM( 'N', 'N', M, BLK, M, ONE, WORK( IVT ),
                   1465:      $                           LDWKVT, A( 1, I ), LDA, ZERO,
                   1466:      $                           WORK( IL ), M )
                   1467:                      CALL DLACPY( 'F', M, BLK, WORK( IL ), M, A( 1, I ),
                   1468:      $                            LDA )
                   1469:    40             CONTINUE
                   1470:                END IF
                   1471:             ELSE IF( WNTQS ) THEN
                   1472: *
1.16      bertrand 1473: *              Path 5ts (N > M, JOBZ='S')
1.1       bertrand 1474: *              Perform bidiagonal SVD, computing left singular vectors
                   1475: *              of bidiagonal matrix in U and computing right singular
                   1476: *              vectors of bidiagonal matrix in VT
1.16      bertrand 1477: *              Workspace: need   3*M [e, tauq, taup] + BDSPAC
1.1       bertrand 1478: *
                   1479:                CALL DLASET( 'F', M, N, ZERO, ZERO, VT, LDVT )
                   1480:                CALL DBDSDC( 'L', 'I', M, S, WORK( IE ), U, LDU, VT,
                   1481:      $                      LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                   1482:      $                      INFO )
                   1483: *
                   1484: *              Overwrite U by left singular vectors of A and VT
                   1485: *              by right singular vectors of A
1.16      bertrand 1486: *              Workspace: need   3*M [e, tauq, taup] + M    [work]
                   1487: *              Workspace: prefer 3*M [e, tauq, taup] + M*NB [work]
1.1       bertrand 1488: *
                   1489:                CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
                   1490:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1491:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1492:                CALL DORMBR( 'P', 'R', 'T', M, N, M, A, LDA,
                   1493:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand 1494:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1495:             ELSE IF( WNTQA ) THEN
                   1496: *
1.16      bertrand 1497: *              Path 5ta (N > M, JOBZ='A')
1.1       bertrand 1498: *              Perform bidiagonal SVD, computing left singular vectors
                   1499: *              of bidiagonal matrix in U and computing right singular
                   1500: *              vectors of bidiagonal matrix in VT
1.16      bertrand 1501: *              Workspace: need   3*M [e, tauq, taup] + BDSPAC
1.1       bertrand 1502: *
                   1503:                CALL DLASET( 'F', N, N, ZERO, ZERO, VT, LDVT )
                   1504:                CALL DBDSDC( 'L', 'I', M, S, WORK( IE ), U, LDU, VT,
                   1505:      $                      LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
                   1506:      $                      INFO )
                   1507: *
                   1508: *              Set the right corner of VT to identity matrix
                   1509: *
                   1510:                IF( N.GT.M ) THEN
1.16      bertrand 1511:                   CALL DLASET( 'F', N-M, N-M, ZERO, ONE, VT(M+1,M+1),
1.1       bertrand 1512:      $                         LDVT )
                   1513:                END IF
                   1514: *
                   1515: *              Overwrite U by left singular vectors of A and VT
                   1516: *              by right singular vectors of A
1.16      bertrand 1517: *              Workspace: need   3*M [e, tauq, taup] + N    [work]
                   1518: *              Workspace: prefer 3*M [e, tauq, taup] + N*NB [work]
1.1       bertrand 1519: *
                   1520:                CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
                   1521:      $                      WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1.16      bertrand 1522:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1523:                CALL DORMBR( 'P', 'R', 'T', N, N, M, A, LDA,
                   1524:      $                      WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1.16      bertrand 1525:      $                      LWORK - NWORK + 1, IERR )
1.1       bertrand 1526:             END IF
                   1527: *
                   1528:          END IF
                   1529: *
                   1530:       END IF
                   1531: *
                   1532: *     Undo scaling if necessary
                   1533: *
                   1534:       IF( ISCL.EQ.1 ) THEN
                   1535:          IF( ANRM.GT.BIGNUM )
                   1536:      $      CALL DLASCL( 'G', 0, 0, BIGNUM, ANRM, MINMN, 1, S, MINMN,
                   1537:      $                   IERR )
                   1538:          IF( ANRM.LT.SMLNUM )
                   1539:      $      CALL DLASCL( 'G', 0, 0, SMLNUM, ANRM, MINMN, 1, S, MINMN,
                   1540:      $                   IERR )
                   1541:       END IF
                   1542: *
                   1543: *     Return optimal workspace in WORK(1)
                   1544: *
1.22    ! bertrand 1545:       WORK( 1 ) = DROUNDUP_LWORK( MAXWRK )
1.1       bertrand 1546: *
                   1547:       RETURN
                   1548: *
                   1549: *     End of DGESDD
                   1550: *
                   1551:       END

CVSweb interface <joel.bertrand@systella.fr>