File:  [local] / rpl / lapack / lapack / dgesvdx.f
Revision 1.8: download - view: text, annotated - select for diffs - revision graph
Mon Aug 7 08:38:50 2023 UTC (8 months, 3 weeks ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_35, rpl-4_1_34, HEAD
Première mise à jour de lapack et blas.

    1: *> \brief <b> DGESVDX computes the singular value decomposition (SVD) for GE matrices</b>
    2: *
    3: *  =========== DOCUMENTATION ===========
    4: *
    5: * Online html documentation available at
    6: *            http://www.netlib.org/lapack/explore-html/
    7: *
    8: *> \htmlonly
    9: *> Download DGESVDX + dependencies
   10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgesvdx.f">
   11: *> [TGZ]</a>
   12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgesvdx.f">
   13: *> [ZIP]</a>
   14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgesvdx.f">
   15: *> [TXT]</a>
   16: *> \endhtmlonly
   17: *
   18: *  Definition:
   19: *  ===========
   20: *
   21: *     SUBROUTINE DGESVDX( JOBU, JOBVT, RANGE, M, N, A, LDA, VL, VU,
   22: *    $                    IL, IU, NS, S, U, LDU, VT, LDVT, WORK,
   23: *    $                    LWORK, IWORK, INFO )
   24: *
   25: *
   26: *     .. Scalar Arguments ..
   27: *      CHARACTER          JOBU, JOBVT, RANGE
   28: *      INTEGER            IL, INFO, IU, LDA, LDU, LDVT, LWORK, M, N, NS
   29: *      DOUBLE PRECISION   VL, VU
   30: *     ..
   31: *     .. Array Arguments ..
   32: *     INTEGER            IWORK( * )
   33: *     DOUBLE PRECISION   A( LDA, * ), S( * ), U( LDU, * ),
   34: *    $                   VT( LDVT, * ), WORK( * )
   35: *     ..
   36: *
   37: *
   38: *> \par Purpose:
   39: *  =============
   40: *>
   41: *> \verbatim
   42: *>
   43: *>  DGESVDX computes the singular value decomposition (SVD) of a real
   44: *>  M-by-N matrix A, optionally computing the left and/or right singular
   45: *>  vectors. 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: *>  DGESVDX uses an eigenvalue problem for obtaining the SVD, which
   57: *>  allows for the computation of a subset of singular values and
   58: *>  vectors. See DBDSVDX for details.
   59: *>
   60: *>  Note that the routine returns V**T, not V.
   61: *> \endverbatim
   62: *
   63: *  Arguments:
   64: *  ==========
   65: *
   66: *> \param[in] JOBU
   67: *> \verbatim
   68: *>          JOBU is CHARACTER*1
   69: *>          Specifies options for computing all or part of the matrix U:
   70: *>          = 'V':  the first min(m,n) columns of U (the left singular
   71: *>                  vectors) or as specified by RANGE are returned in
   72: *>                  the array U;
   73: *>          = 'N':  no columns of U (no left singular vectors) are
   74: *>                  computed.
   75: *> \endverbatim
   76: *>
   77: *> \param[in] JOBVT
   78: *> \verbatim
   79: *>          JOBVT is CHARACTER*1
   80: *>           Specifies options for computing all or part of the matrix
   81: *>           V**T:
   82: *>           = 'V':  the first min(m,n) rows of V**T (the right singular
   83: *>                   vectors) or as specified by RANGE are returned in
   84: *>                   the array VT;
   85: *>           = 'N':  no rows of V**T (no right singular vectors) are
   86: *>                   computed.
   87: *> \endverbatim
   88: *>
   89: *> \param[in] RANGE
   90: *> \verbatim
   91: *>          RANGE is CHARACTER*1
   92: *>          = 'A': all singular values will be found.
   93: *>          = 'V': all singular values in the half-open interval (VL,VU]
   94: *>                 will be found.
   95: *>          = 'I': the IL-th through IU-th singular values will be found.
   96: *> \endverbatim
   97: *>
   98: *> \param[in] M
   99: *> \verbatim
  100: *>          M is INTEGER
  101: *>          The number of rows of the input matrix A.  M >= 0.
  102: *> \endverbatim
  103: *>
  104: *> \param[in] N
  105: *> \verbatim
  106: *>          N is INTEGER
  107: *>          The number of columns of the input matrix A.  N >= 0.
  108: *> \endverbatim
  109: *>
  110: *> \param[in,out] A
  111: *> \verbatim
  112: *>          A is DOUBLE PRECISION array, dimension (LDA,N)
  113: *>          On entry, the M-by-N matrix A.
  114: *>          On exit, the contents of A are destroyed.
  115: *> \endverbatim
  116: *>
  117: *> \param[in] LDA
  118: *> \verbatim
  119: *>          LDA is INTEGER
  120: *>          The leading dimension of the array A.  LDA >= max(1,M).
  121: *> \endverbatim
  122: *>
  123: *> \param[in] VL
  124: *> \verbatim
  125: *>          VL is DOUBLE PRECISION
  126: *>          If RANGE='V', the lower bound of the interval to
  127: *>          be searched for singular values. VU > VL.
  128: *>          Not referenced if RANGE = 'A' or 'I'.
  129: *> \endverbatim
  130: *>
  131: *> \param[in] VU
  132: *> \verbatim
  133: *>          VU is DOUBLE PRECISION
  134: *>          If RANGE='V', the upper bound of the interval to
  135: *>          be searched for singular values. VU > VL.
  136: *>          Not referenced if RANGE = 'A' or 'I'.
  137: *> \endverbatim
  138: *>
  139: *> \param[in] IL
  140: *> \verbatim
  141: *>          IL is INTEGER
  142: *>          If RANGE='I', the index of the
  143: *>          smallest singular value to be returned.
  144: *>          1 <= IL <= IU <= min(M,N), if min(M,N) > 0.
  145: *>          Not referenced if RANGE = 'A' or 'V'.
  146: *> \endverbatim
  147: *>
  148: *> \param[in] IU
  149: *> \verbatim
  150: *>          IU is INTEGER
  151: *>          If RANGE='I', the index of the
  152: *>          largest singular value to be returned.
  153: *>          1 <= IL <= IU <= min(M,N), if min(M,N) > 0.
  154: *>          Not referenced if RANGE = 'A' or 'V'.
  155: *> \endverbatim
  156: *>
  157: *> \param[out] NS
  158: *> \verbatim
  159: *>          NS is INTEGER
  160: *>          The total number of singular values found,
  161: *>          0 <= NS <= min(M,N).
  162: *>          If RANGE = 'A', NS = min(M,N); if RANGE = 'I', NS = IU-IL+1.
  163: *> \endverbatim
  164: *>
  165: *> \param[out] S
  166: *> \verbatim
  167: *>          S is DOUBLE PRECISION array, dimension (min(M,N))
  168: *>          The singular values of A, sorted so that S(i) >= S(i+1).
  169: *> \endverbatim
  170: *>
  171: *> \param[out] U
  172: *> \verbatim
  173: *>          U is DOUBLE PRECISION array, dimension (LDU,UCOL)
  174: *>          If JOBU = 'V', U contains columns of U (the left singular
  175: *>          vectors, stored columnwise) as specified by RANGE; if
  176: *>          JOBU = 'N', U is not referenced.
  177: *>          Note: The user must ensure that UCOL >= NS; if RANGE = 'V',
  178: *>          the exact value of NS is not known in advance and an upper
  179: *>          bound must be used.
  180: *> \endverbatim
  181: *>
  182: *> \param[in] LDU
  183: *> \verbatim
  184: *>          LDU is INTEGER
  185: *>          The leading dimension of the array U.  LDU >= 1; if
  186: *>          JOBU = 'V', LDU >= M.
  187: *> \endverbatim
  188: *>
  189: *> \param[out] VT
  190: *> \verbatim
  191: *>          VT is DOUBLE PRECISION array, dimension (LDVT,N)
  192: *>          If JOBVT = 'V', VT contains the rows of V**T (the right singular
  193: *>          vectors, stored rowwise) as specified by RANGE; if JOBVT = 'N',
  194: *>          VT is not referenced.
  195: *>          Note: The user must ensure that LDVT >= NS; if RANGE = 'V',
  196: *>          the exact value of NS is not known in advance and an upper
  197: *>          bound must be used.
  198: *> \endverbatim
  199: *>
  200: *> \param[in] LDVT
  201: *> \verbatim
  202: *>          LDVT is INTEGER
  203: *>          The leading dimension of the array VT.  LDVT >= 1; if
  204: *>          JOBVT = 'V', LDVT >= NS (see above).
  205: *> \endverbatim
  206: *>
  207: *> \param[out] WORK
  208: *> \verbatim
  209: *>          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))
  210: *>          On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
  211: *> \endverbatim
  212: *>
  213: *> \param[in] LWORK
  214: *> \verbatim
  215: *>          LWORK is INTEGER
  216: *>          The dimension of the array WORK.
  217: *>          LWORK >= MAX(1,MIN(M,N)*(MIN(M,N)+4)) for the paths (see
  218: *>          comments inside the code):
  219: *>             - PATH 1  (M much larger than N)
  220: *>             - PATH 1t (N much larger than M)
  221: *>          LWORK >= MAX(1,MIN(M,N)*2+MAX(M,N)) for the other paths.
  222: *>          For good performance, LWORK should generally be larger.
  223: *>
  224: *>          If LWORK = -1, then a workspace query is assumed; the routine
  225: *>          only calculates the optimal size of the WORK array, returns
  226: *>          this value as the first entry of the WORK array, and no error
  227: *>          message related to LWORK is issued by XERBLA.
  228: *> \endverbatim
  229: *>
  230: *> \param[out] IWORK
  231: *> \verbatim
  232: *>          IWORK is INTEGER array, dimension (12*MIN(M,N))
  233: *>          If INFO = 0, the first NS elements of IWORK are zero. If INFO > 0,
  234: *>          then IWORK contains the indices of the eigenvectors that failed
  235: *>          to converge in DBDSVDX/DSTEVX.
  236: *> \endverbatim
  237: *>
  238: *> \param[out] INFO
  239: *> \verbatim
  240: *>     INFO is INTEGER
  241: *>           = 0:  successful exit
  242: *>           < 0:  if INFO = -i, the i-th argument had an illegal value
  243: *>           > 0:  if INFO = i, then i eigenvectors failed to converge
  244: *>                 in DBDSVDX/DSTEVX.
  245: *>                 if INFO = N*2 + 1, an internal error occurred in
  246: *>                 DBDSVDX
  247: *> \endverbatim
  248: *
  249: *  Authors:
  250: *  ========
  251: *
  252: *> \author Univ. of Tennessee
  253: *> \author Univ. of California Berkeley
  254: *> \author Univ. of Colorado Denver
  255: *> \author NAG Ltd.
  256: *
  257: *> \ingroup doubleGEsing
  258: *
  259: *  =====================================================================
  260:       SUBROUTINE DGESVDX( JOBU, JOBVT, RANGE, M, N, A, LDA, VL, VU,
  261:      $                    IL, IU, NS, S, U, LDU, VT, LDVT, WORK,
  262:      $                    LWORK, IWORK, INFO )
  263: *
  264: *  -- LAPACK driver routine --
  265: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  266: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  267: *
  268: *     .. Scalar Arguments ..
  269:       CHARACTER          JOBU, JOBVT, RANGE
  270:       INTEGER            IL, INFO, IU, LDA, LDU, LDVT, LWORK, M, N, NS
  271:       DOUBLE PRECISION   VL, VU
  272: *     ..
  273: *     .. Array Arguments ..
  274:       INTEGER            IWORK( * )
  275:       DOUBLE PRECISION   A( LDA, * ), S( * ), U( LDU, * ),
  276:      $                   VT( LDVT, * ), WORK( * )
  277: *     ..
  278: *
  279: *  =====================================================================
  280: *
  281: *     .. Parameters ..
  282:       DOUBLE PRECISION   ZERO, ONE
  283:       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0 )
  284: *     ..
  285: *     .. Local Scalars ..
  286:       CHARACTER          JOBZ, RNGTGK
  287:       LOGICAL            ALLS, INDS, LQUERY, VALS, WANTU, WANTVT
  288:       INTEGER            I, ID, IE, IERR, ILQF, ILTGK, IQRF, ISCL,
  289:      $                   ITAU, ITAUP, ITAUQ, ITEMP, ITGKZ, IUTGK,
  290:      $                   J, MAXWRK, MINMN, MINWRK, MNTHR
  291:       DOUBLE PRECISION   ABSTOL, ANRM, BIGNUM, EPS, SMLNUM
  292: *     ..
  293: *     .. Local Arrays ..
  294:       DOUBLE PRECISION   DUM( 1 )
  295: *     ..
  296: *     .. External Subroutines ..
  297:       EXTERNAL           DBDSVDX, DGEBRD, DGELQF, DGEQRF, DLACPY,
  298:      $                   DLASCL, DLASET, DORMBR, DORMLQ, DORMQR,
  299:      $                   DCOPY, XERBLA
  300: *     ..
  301: *     .. External Functions ..
  302:       LOGICAL            LSAME
  303:       INTEGER            ILAENV
  304:       DOUBLE PRECISION   DLAMCH, DLANGE
  305:       EXTERNAL           LSAME, ILAENV, DLAMCH, DLANGE
  306: *     ..
  307: *     .. Intrinsic Functions ..
  308:       INTRINSIC          MAX, MIN, SQRT
  309: *     ..
  310: *     .. Executable Statements ..
  311: *
  312: *     Test the input arguments.
  313: *
  314:       NS = 0
  315:       INFO = 0
  316:       ABSTOL = 2*DLAMCH('S')
  317:       LQUERY = ( LWORK.EQ.-1 )
  318:       MINMN = MIN( M, N )
  319: 
  320:       WANTU = LSAME( JOBU, 'V' )
  321:       WANTVT = LSAME( JOBVT, 'V' )
  322:       IF( WANTU .OR. WANTVT ) THEN
  323:          JOBZ = 'V'
  324:       ELSE
  325:          JOBZ = 'N'
  326:       END IF
  327:       ALLS = LSAME( RANGE, 'A' )
  328:       VALS = LSAME( RANGE, 'V' )
  329:       INDS = LSAME( RANGE, 'I' )
  330: *
  331:       INFO = 0
  332:       IF( .NOT.LSAME( JOBU, 'V' ) .AND.
  333:      $    .NOT.LSAME( JOBU, 'N' ) ) THEN
  334:          INFO = -1
  335:       ELSE IF( .NOT.LSAME( JOBVT, 'V' ) .AND.
  336:      $         .NOT.LSAME( JOBVT, 'N' ) ) THEN
  337:          INFO = -2
  338:       ELSE IF( .NOT.( ALLS .OR. VALS .OR. INDS ) ) THEN
  339:          INFO = -3
  340:       ELSE IF( M.LT.0 ) THEN
  341:          INFO = -4
  342:       ELSE IF( N.LT.0 ) THEN
  343:          INFO = -5
  344:       ELSE IF( M.GT.LDA ) THEN
  345:          INFO = -7
  346:       ELSE IF( MINMN.GT.0 ) THEN
  347:          IF( VALS ) THEN
  348:             IF( VL.LT.ZERO ) THEN
  349:                INFO = -8
  350:             ELSE IF( VU.LE.VL ) THEN
  351:                INFO = -9
  352:             END IF
  353:          ELSE IF( INDS ) THEN
  354:             IF( IL.LT.1 .OR. IL.GT.MAX( 1, MINMN ) ) THEN
  355:                INFO = -10
  356:             ELSE IF( IU.LT.MIN( MINMN, IL ) .OR. IU.GT.MINMN ) THEN
  357:                INFO = -11
  358:             END IF
  359:          END IF
  360:          IF( INFO.EQ.0 ) THEN
  361:             IF( WANTU .AND. LDU.LT.M ) THEN
  362:                INFO = -15
  363:             ELSE IF( WANTVT ) THEN
  364:                IF( INDS ) THEN
  365:                    IF( LDVT.LT.IU-IL+1 ) THEN
  366:                        INFO = -17
  367:                    END IF
  368:                ELSE IF( LDVT.LT.MINMN ) THEN
  369:                    INFO = -17
  370:                END IF
  371:             END IF
  372:          END IF
  373:       END IF
  374: *
  375: *     Compute workspace
  376: *     (Note: Comments in the code beginning "Workspace:" describe the
  377: *     minimal amount of workspace needed at that point in the code,
  378: *     as well as the preferred amount for good performance.
  379: *     NB refers to the optimal block size for the immediately
  380: *     following subroutine, as returned by ILAENV.)
  381: *
  382:       IF( INFO.EQ.0 ) THEN
  383:          MINWRK = 1
  384:          MAXWRK = 1
  385:          IF( MINMN.GT.0 ) THEN
  386:             IF( M.GE.N ) THEN
  387:                MNTHR = ILAENV( 6, 'DGESVD', JOBU // JOBVT, M, N, 0, 0 )
  388:                IF( M.GE.MNTHR ) THEN
  389: *
  390: *                 Path 1 (M much larger than N)
  391: *
  392:                   MAXWRK = N +
  393:      $                     N*ILAENV( 1, 'DGEQRF', ' ', M, N, -1, -1 )
  394:                   MAXWRK = MAX( MAXWRK, N*(N+5) + 2*N*
  395:      $                     ILAENV( 1, 'DGEBRD', ' ', N, N, -1, -1 ) )
  396:                   IF (WANTU) THEN
  397:                       MAXWRK = MAX(MAXWRK,N*(N*3+6)+N*
  398:      $                     ILAENV( 1, 'DORMQR', ' ', N, N, -1, -1 ) )
  399:                   END IF
  400:                   IF (WANTVT) THEN
  401:                       MAXWRK = MAX(MAXWRK,N*(N*3+6)+N*
  402:      $                     ILAENV( 1, 'DORMLQ', ' ', N, N, -1, -1 ) )
  403:                   END IF
  404:                   MINWRK = N*(N*3+20)
  405:                ELSE
  406: *
  407: *                 Path 2 (M at least N, but not much larger)
  408: *
  409:                   MAXWRK = 4*N + ( M+N )*
  410:      $                     ILAENV( 1, 'DGEBRD', ' ', M, N, -1, -1 )
  411:                   IF (WANTU) THEN
  412:                       MAXWRK = MAX(MAXWRK,N*(N*2+5)+N*
  413:      $                     ILAENV( 1, 'DORMQR', ' ', N, N, -1, -1 ) )
  414:                   END IF
  415:                   IF (WANTVT) THEN
  416:                       MAXWRK = MAX(MAXWRK,N*(N*2+5)+N*
  417:      $                     ILAENV( 1, 'DORMLQ', ' ', N, N, -1, -1 ) )
  418:                   END IF
  419:                   MINWRK = MAX(N*(N*2+19),4*N+M)
  420:                END IF
  421:             ELSE
  422:                MNTHR = ILAENV( 6, 'DGESVD', JOBU // JOBVT, M, N, 0, 0 )
  423:                IF( N.GE.MNTHR ) THEN
  424: *
  425: *                 Path 1t (N much larger than M)
  426: *
  427:                   MAXWRK = M +
  428:      $                     M*ILAENV( 1, 'DGELQF', ' ', M, N, -1, -1 )
  429:                   MAXWRK = MAX( MAXWRK, M*(M+5) + 2*M*
  430:      $                     ILAENV( 1, 'DGEBRD', ' ', M, M, -1, -1 ) )
  431:                   IF (WANTU) THEN
  432:                       MAXWRK = MAX(MAXWRK,M*(M*3+6)+M*
  433:      $                     ILAENV( 1, 'DORMQR', ' ', M, M, -1, -1 ) )
  434:                   END IF
  435:                   IF (WANTVT) THEN
  436:                       MAXWRK = MAX(MAXWRK,M*(M*3+6)+M*
  437:      $                     ILAENV( 1, 'DORMLQ', ' ', M, M, -1, -1 ) )
  438:                   END IF
  439:                   MINWRK = M*(M*3+20)
  440:                ELSE
  441: *
  442: *                 Path 2t (N at least M, but not much larger)
  443: *
  444:                   MAXWRK = 4*M + ( M+N )*
  445:      $                     ILAENV( 1, 'DGEBRD', ' ', M, N, -1, -1 )
  446:                   IF (WANTU) THEN
  447:                       MAXWRK = MAX(MAXWRK,M*(M*2+5)+M*
  448:      $                     ILAENV( 1, 'DORMQR', ' ', M, M, -1, -1 ) )
  449:                   END IF
  450:                   IF (WANTVT) THEN
  451:                       MAXWRK = MAX(MAXWRK,M*(M*2+5)+M*
  452:      $                     ILAENV( 1, 'DORMLQ', ' ', M, M, -1, -1 ) )
  453:                   END IF
  454:                   MINWRK = MAX(M*(M*2+19),4*M+N)
  455:                END IF
  456:             END IF
  457:          END IF
  458:          MAXWRK = MAX( MAXWRK, MINWRK )
  459:          WORK( 1 ) = DBLE( MAXWRK )
  460: *
  461:          IF( LWORK.LT.MINWRK .AND. .NOT.LQUERY ) THEN
  462:              INFO = -19
  463:          END IF
  464:       END IF
  465: *
  466:       IF( INFO.NE.0 ) THEN
  467:          CALL XERBLA( 'DGESVDX', -INFO )
  468:          RETURN
  469:       ELSE IF( LQUERY ) THEN
  470:          RETURN
  471:       END IF
  472: *
  473: *     Quick return if possible
  474: *
  475:       IF( M.EQ.0 .OR. N.EQ.0 ) THEN
  476:          RETURN
  477:       END IF
  478: *
  479: *     Set singular values indices accord to RANGE.
  480: *
  481:       IF( ALLS ) THEN
  482:          RNGTGK = 'I'
  483:          ILTGK = 1
  484:          IUTGK = MIN( M, N )
  485:       ELSE IF( INDS ) THEN
  486:          RNGTGK = 'I'
  487:          ILTGK = IL
  488:          IUTGK = IU
  489:       ELSE
  490:          RNGTGK = 'V'
  491:          ILTGK = 0
  492:          IUTGK = 0
  493:       END IF
  494: *
  495: *     Get machine constants
  496: *
  497:       EPS = DLAMCH( 'P' )
  498:       SMLNUM = SQRT( DLAMCH( 'S' ) ) / EPS
  499:       BIGNUM = ONE / SMLNUM
  500: *
  501: *     Scale A if max element outside range [SMLNUM,BIGNUM]
  502: *
  503:       ANRM = DLANGE( 'M', M, N, A, LDA, DUM )
  504:       ISCL = 0
  505:       IF( ANRM.GT.ZERO .AND. ANRM.LT.SMLNUM ) THEN
  506:          ISCL = 1
  507:          CALL DLASCL( 'G', 0, 0, ANRM, SMLNUM, M, N, A, LDA, INFO )
  508:       ELSE IF( ANRM.GT.BIGNUM ) THEN
  509:          ISCL = 1
  510:          CALL DLASCL( 'G', 0, 0, ANRM, BIGNUM, M, N, A, LDA, INFO )
  511:       END IF
  512: *
  513:       IF( M.GE.N ) THEN
  514: *
  515: *        A has at least as many rows as columns. If A has sufficiently
  516: *        more rows than columns, first reduce A using the QR
  517: *        decomposition.
  518: *
  519:          IF( M.GE.MNTHR ) THEN
  520: *
  521: *           Path 1 (M much larger than N):
  522: *           A = Q * R = Q * ( QB * B * PB**T )
  523: *                     = Q * ( QB * ( UB * S * VB**T ) * PB**T )
  524: *           U = Q * QB * UB; V**T = VB**T * PB**T
  525: *
  526: *           Compute A=Q*R
  527: *           (Workspace: need 2*N, prefer N+N*NB)
  528: *
  529:             ITAU = 1
  530:             ITEMP = ITAU + N
  531:             CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( ITEMP ),
  532:      $                   LWORK-ITEMP+1, INFO )
  533: *
  534: *           Copy R into WORK and bidiagonalize it:
  535: *           (Workspace: need N*N+5*N, prefer N*N+4*N+2*N*NB)
  536: *
  537:             IQRF = ITEMP
  538:             ID = IQRF + N*N
  539:             IE = ID + N
  540:             ITAUQ = IE + N
  541:             ITAUP = ITAUQ + N
  542:             ITEMP = ITAUP + N
  543:             CALL DLACPY( 'U', N, N, A, LDA, WORK( IQRF ), N )
  544:             CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, WORK( IQRF+1 ), N )
  545:             CALL DGEBRD( N, N, WORK( IQRF ), N, WORK( ID ), WORK( IE ),
  546:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
  547:      $                   LWORK-ITEMP+1, INFO )
  548: *
  549: *           Solve eigenvalue problem TGK*Z=Z*S.
  550: *           (Workspace: need 14*N + 2*N*(N+1))
  551: *
  552:             ITGKZ = ITEMP
  553:             ITEMP = ITGKZ + N*(N*2+1)
  554:             CALL DBDSVDX( 'U', JOBZ, RNGTGK, N, WORK( ID ), WORK( IE ),
  555:      $                    VL, VU, ILTGK, IUTGK, NS, S, WORK( ITGKZ ),
  556:      $                    N*2, WORK( ITEMP ), IWORK, INFO)
  557: *
  558: *           If needed, compute left singular vectors.
  559: *
  560:             IF( WANTU ) THEN
  561:                J = ITGKZ
  562:                DO I = 1, NS
  563:                   CALL DCOPY( N, WORK( J ), 1, U( 1,I ), 1 )
  564:                   J = J + N*2
  565:                END DO
  566:                CALL DLASET( 'A', M-N, NS, ZERO, ZERO, U( N+1,1 ), LDU )
  567: *
  568: *              Call DORMBR to compute QB*UB.
  569: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
  570: *
  571:                CALL DORMBR( 'Q', 'L', 'N', N, NS, N, WORK( IQRF ), N,
  572:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
  573:      $                      LWORK-ITEMP+1, INFO )
  574: *
  575: *              Call DORMQR to compute Q*(QB*UB).
  576: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
  577: *
  578:                CALL DORMQR( 'L', 'N', M, NS, N, A, LDA,
  579:      $                      WORK( ITAU ), U, LDU, WORK( ITEMP ),
  580:      $                      LWORK-ITEMP+1, INFO )
  581:             END IF
  582: *
  583: *           If needed, compute right singular vectors.
  584: *
  585:             IF( WANTVT) THEN
  586:                J = ITGKZ + N
  587:                DO I = 1, NS
  588:                   CALL DCOPY( N, WORK( J ), 1, VT( I,1 ), LDVT )
  589:                   J = J + N*2
  590:                END DO
  591: *
  592: *              Call DORMBR to compute VB**T * PB**T
  593: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
  594: *
  595:                CALL DORMBR( 'P', 'R', 'T', NS, N, N, WORK( IQRF ), N,
  596:      $                      WORK( ITAUP ), VT, LDVT, WORK( ITEMP ),
  597:      $                      LWORK-ITEMP+1, INFO )
  598:             END IF
  599:          ELSE
  600: *
  601: *           Path 2 (M at least N, but not much larger)
  602: *           Reduce A to bidiagonal form without QR decomposition
  603: *           A = QB * B * PB**T = QB * ( UB * S * VB**T ) * PB**T
  604: *           U = QB * UB; V**T = VB**T * PB**T
  605: *
  606: *           Bidiagonalize A
  607: *           (Workspace: need 4*N+M, prefer 4*N+(M+N)*NB)
  608: *
  609:             ID = 1
  610:             IE = ID + N
  611:             ITAUQ = IE + N
  612:             ITAUP = ITAUQ + N
  613:             ITEMP = ITAUP + N
  614:             CALL DGEBRD( M, N, A, LDA, WORK( ID ), WORK( IE ),
  615:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
  616:      $                   LWORK-ITEMP+1, INFO )
  617: *
  618: *           Solve eigenvalue problem TGK*Z=Z*S.
  619: *           (Workspace: need 14*N + 2*N*(N+1))
  620: *
  621:             ITGKZ = ITEMP
  622:             ITEMP = ITGKZ + N*(N*2+1)
  623:             CALL DBDSVDX( 'U', JOBZ, RNGTGK, N, WORK( ID ), WORK( IE ),
  624:      $                    VL, VU, ILTGK, IUTGK, NS, S, WORK( ITGKZ ),
  625:      $                    N*2, WORK( ITEMP ), IWORK, INFO)
  626: *
  627: *           If needed, compute left singular vectors.
  628: *
  629:             IF( WANTU ) THEN
  630:                J = ITGKZ
  631:                DO I = 1, NS
  632:                   CALL DCOPY( N, WORK( J ), 1, U( 1,I ), 1 )
  633:                   J = J + N*2
  634:                END DO
  635:                CALL DLASET( 'A', M-N, NS, ZERO, ZERO, U( N+1,1 ), LDU )
  636: *
  637: *              Call DORMBR to compute QB*UB.
  638: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
  639: *
  640:                CALL DORMBR( 'Q', 'L', 'N', M, NS, N, A, LDA,
  641:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
  642:      $                      LWORK-ITEMP+1, IERR )
  643:             END IF
  644: *
  645: *           If needed, compute right singular vectors.
  646: *
  647:             IF( WANTVT) THEN
  648:                J = ITGKZ + N
  649:                DO I = 1, NS
  650:                   CALL DCOPY( N, WORK( J ), 1, VT( I,1 ), LDVT )
  651:                   J = J + N*2
  652:                END DO
  653: *
  654: *              Call DORMBR to compute VB**T * PB**T
  655: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
  656: *
  657:                CALL DORMBR( 'P', 'R', 'T', NS, N, N, A, LDA,
  658:      $                      WORK( ITAUP ), VT, LDVT, WORK( ITEMP ),
  659:      $                      LWORK-ITEMP+1, IERR )
  660:             END IF
  661:          END IF
  662:       ELSE
  663: *
  664: *        A has more columns than rows. If A has sufficiently more
  665: *        columns than rows, first reduce A using the LQ decomposition.
  666: *
  667:          IF( N.GE.MNTHR ) THEN
  668: *
  669: *           Path 1t (N much larger than M):
  670: *           A = L * Q = ( QB * B * PB**T ) * Q
  671: *                     = ( QB * ( UB * S * VB**T ) * PB**T ) * Q
  672: *           U = QB * UB ; V**T = VB**T * PB**T * Q
  673: *
  674: *           Compute A=L*Q
  675: *           (Workspace: need 2*M, prefer M+M*NB)
  676: *
  677:             ITAU = 1
  678:             ITEMP = ITAU + M
  679:             CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( ITEMP ),
  680:      $                   LWORK-ITEMP+1, INFO )
  681: 
  682: *           Copy L into WORK and bidiagonalize it:
  683: *           (Workspace in WORK( ITEMP ): need M*M+5*N, prefer M*M+4*M+2*M*NB)
  684: *
  685:             ILQF = ITEMP
  686:             ID = ILQF + M*M
  687:             IE = ID + M
  688:             ITAUQ = IE + M
  689:             ITAUP = ITAUQ + M
  690:             ITEMP = ITAUP + M
  691:             CALL DLACPY( 'L', M, M, A, LDA, WORK( ILQF ), M )
  692:             CALL DLASET( 'U', M-1, M-1, ZERO, ZERO, WORK( ILQF+M ), M )
  693:             CALL DGEBRD( M, M, WORK( ILQF ), M, WORK( ID ), WORK( IE ),
  694:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
  695:      $                   LWORK-ITEMP+1, INFO )
  696: *
  697: *           Solve eigenvalue problem TGK*Z=Z*S.
  698: *           (Workspace: need 2*M*M+14*M)
  699: *
  700:             ITGKZ = ITEMP
  701:             ITEMP = ITGKZ + M*(M*2+1)
  702:             CALL DBDSVDX( 'U', JOBZ, RNGTGK, M, WORK( ID ), WORK( IE ),
  703:      $                    VL, VU, ILTGK, IUTGK, NS, S, WORK( ITGKZ ),
  704:      $                    M*2, WORK( ITEMP ), IWORK, INFO)
  705: *
  706: *           If needed, compute left singular vectors.
  707: *
  708:             IF( WANTU ) THEN
  709:                J = ITGKZ
  710:                DO I = 1, NS
  711:                   CALL DCOPY( M, WORK( J ), 1, U( 1,I ), 1 )
  712:                   J = J + M*2
  713:                END DO
  714: *
  715: *              Call DORMBR to compute QB*UB.
  716: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
  717: *
  718:                CALL DORMBR( 'Q', 'L', 'N', M, NS, M, WORK( ILQF ), M,
  719:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
  720:      $                      LWORK-ITEMP+1, INFO )
  721:             END IF
  722: *
  723: *           If needed, compute right singular vectors.
  724: *
  725:             IF( WANTVT) THEN
  726:                J = ITGKZ + M
  727:                DO I = 1, NS
  728:                   CALL DCOPY( M, WORK( J ), 1, VT( I,1 ), LDVT )
  729:                   J = J + M*2
  730:                END DO
  731:                CALL DLASET( 'A', NS, N-M, ZERO, ZERO, VT( 1,M+1 ), LDVT)
  732: *
  733: *              Call DORMBR to compute (VB**T)*(PB**T)
  734: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
  735: *
  736:                CALL DORMBR( 'P', 'R', 'T', NS, M, M, WORK( ILQF ), M,
  737:      $                      WORK( ITAUP ), VT, LDVT, WORK( ITEMP ),
  738:      $                      LWORK-ITEMP+1, INFO )
  739: *
  740: *              Call DORMLQ to compute ((VB**T)*(PB**T))*Q.
  741: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
  742: *
  743:                CALL DORMLQ( 'R', 'N', NS, N, M, A, LDA,
  744:      $                      WORK( ITAU ), VT, LDVT, WORK( ITEMP ),
  745:      $                      LWORK-ITEMP+1, INFO )
  746:             END IF
  747:          ELSE
  748: *
  749: *           Path 2t (N greater than M, but not much larger)
  750: *           Reduce to bidiagonal form without LQ decomposition
  751: *           A = QB * B * PB**T = QB * ( UB * S * VB**T ) * PB**T
  752: *           U = QB * UB; V**T = VB**T * PB**T
  753: *
  754: *           Bidiagonalize A
  755: *           (Workspace: need 4*M+N, prefer 4*M+(M+N)*NB)
  756: *
  757:             ID = 1
  758:             IE = ID + M
  759:             ITAUQ = IE + M
  760:             ITAUP = ITAUQ + M
  761:             ITEMP = ITAUP + M
  762:             CALL DGEBRD( M, N, A, LDA, WORK( ID ), WORK( IE ),
  763:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
  764:      $                   LWORK-ITEMP+1, INFO )
  765: *
  766: *           Solve eigenvalue problem TGK*Z=Z*S.
  767: *           (Workspace: need 2*M*M+14*M)
  768: *
  769:             ITGKZ = ITEMP
  770:             ITEMP = ITGKZ + M*(M*2+1)
  771:             CALL DBDSVDX( 'L', JOBZ, RNGTGK, M, WORK( ID ), WORK( IE ),
  772:      $                    VL, VU, ILTGK, IUTGK, NS, S, WORK( ITGKZ ),
  773:      $                    M*2, WORK( ITEMP ), IWORK, INFO)
  774: *
  775: *           If needed, compute left singular vectors.
  776: *
  777:             IF( WANTU ) THEN
  778:                J = ITGKZ
  779:                DO I = 1, NS
  780:                   CALL DCOPY( M, WORK( J ), 1, U( 1,I ), 1 )
  781:                   J = J + M*2
  782:                END DO
  783: *
  784: *              Call DORMBR to compute QB*UB.
  785: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
  786: *
  787:                CALL DORMBR( 'Q', 'L', 'N', M, NS, N, A, LDA,
  788:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
  789:      $                      LWORK-ITEMP+1, INFO )
  790:             END IF
  791: *
  792: *           If needed, compute right singular vectors.
  793: *
  794:             IF( WANTVT) THEN
  795:                J = ITGKZ + M
  796:                DO I = 1, NS
  797:                   CALL DCOPY( M, WORK( J ), 1, VT( I,1 ), LDVT )
  798:                   J = J + M*2
  799:                END DO
  800:                CALL DLASET( 'A', NS, N-M, ZERO, ZERO, VT( 1,M+1 ), LDVT)
  801: *
  802: *              Call DORMBR to compute VB**T * PB**T
  803: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
  804: *
  805:                CALL DORMBR( 'P', 'R', 'T', NS, N, M, A, LDA,
  806:      $                      WORK( ITAUP ), VT, LDVT, WORK( ITEMP ),
  807:      $                      LWORK-ITEMP+1, INFO )
  808:             END IF
  809:          END IF
  810:       END IF
  811: *
  812: *     Undo scaling if necessary
  813: *
  814:       IF( ISCL.EQ.1 ) THEN
  815:          IF( ANRM.GT.BIGNUM )
  816:      $      CALL DLASCL( 'G', 0, 0, BIGNUM, ANRM, MINMN, 1,
  817:      $                   S, MINMN, INFO )
  818:          IF( ANRM.LT.SMLNUM )
  819:      $      CALL DLASCL( 'G', 0, 0, SMLNUM, ANRM, MINMN, 1,
  820:      $                   S, MINMN, INFO )
  821:       END IF
  822: *
  823: *     Return optimal workspace in WORK(1)
  824: *
  825:       WORK( 1 ) = DBLE( MAXWRK )
  826: *
  827:       RETURN
  828: *
  829: *     End of DGESVDX
  830: *
  831:       END

CVSweb interface <joel.bertrand@systella.fr>