File:  [local] / rpl / lapack / lapack / dgesdd.f
Revision 1.17: download - view: text, annotated - select for diffs - revision graph
Sat Aug 27 15:34:22 2016 UTC (7 years, 8 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_25, HEAD
Cohérence Lapack.

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

CVSweb interface <joel.bertrand@systella.fr>