Annotation of rpl/lapack/lapack/dgesvdx.f, revision 1.8

1.1       bertrand    1: *> \brief <b> DGESVDX computes the singular value decomposition (SVD) for GE matrices</b>
                      2: *
                      3: *  =========== DOCUMENTATION ===========
                      4: *
1.4       bertrand    5: * Online html documentation available at
                      6: *            http://www.netlib.org/lapack/explore-html/
1.1       bertrand    7: *
                      8: *> \htmlonly
1.4       bertrand    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">
1.1       bertrand   15: *> [TXT]</a>
1.4       bertrand   16: *> \endhtmlonly
1.1       bertrand   17: *
                     18: *  Definition:
                     19: *  ===========
                     20: *
1.4       bertrand   21: *     SUBROUTINE DGESVDX( JOBU, JOBVT, RANGE, M, N, A, LDA, VL, VU,
                     22: *    $                    IL, IU, NS, S, U, LDU, VT, LDVT, WORK,
1.1       bertrand   23: *    $                    LWORK, IWORK, INFO )
1.4       bertrand   24: *
1.1       bertrand   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: *     ..
1.4       bertrand   36: *
1.1       bertrand   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
1.4       bertrand   46: *>
1.1       bertrand   47: *>      A = U * SIGMA * transpose(V)
1.4       bertrand   48: *>
1.1       bertrand   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.
1.4       bertrand   55: *>
                     56: *>  DGESVDX uses an eigenvalue problem for obtaining the SVD, which
                     57: *>  allows for the computation of a subset of singular values and
1.1       bertrand   58: *>  vectors. See DBDSVDX for details.
1.4       bertrand   59: *>
1.1       bertrand   60: *>  Note that the routine returns V**T, not V.
                     61: *> \endverbatim
1.4       bertrand   62: *
1.1       bertrand   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
1.4       bertrand   71: *>                  vectors) or as specified by RANGE are returned in
1.1       bertrand   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
1.4       bertrand   83: *>                   vectors) or as specified by RANGE are returned in
1.1       bertrand   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.
1.4       bertrand   95: *>          = 'I': the IL-th through IU-th singular values will be found.
1.1       bertrand   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
1.2       bertrand  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'.
1.1       bertrand  129: *> \endverbatim
                    130: *>
                    131: *> \param[in] VU
                    132: *> \verbatim
                    133: *>          VU is DOUBLE PRECISION
1.2       bertrand  134: *>          If RANGE='V', the upper bound of the interval to
1.1       bertrand  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
1.2       bertrand  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'.
1.1       bertrand  146: *> \endverbatim
                    147: *>
                    148: *> \param[in] IU
                    149: *> \verbatim
                    150: *>          IU is INTEGER
1.2       bertrand  151: *>          If RANGE='I', the index of the
                    152: *>          largest singular value to be returned.
1.1       bertrand  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
1.4       bertrand  160: *>          The total number of singular values found,
1.1       bertrand  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)
1.4       bertrand  174: *>          If JOBU = 'V', U contains columns of U (the left singular
                    175: *>          vectors, stored columnwise) as specified by RANGE; if
1.1       bertrand  176: *>          JOBU = 'N', U is not referenced.
1.4       bertrand  177: *>          Note: The user must ensure that UCOL >= NS; if RANGE = 'V',
1.2       bertrand  178: *>          the exact value of NS is not known in advance and an upper
1.1       bertrand  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)
1.4       bertrand  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',
1.1       bertrand  194: *>          VT is not referenced.
1.4       bertrand  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
1.1       bertrand  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.
1.4       bertrand  217: *>          LWORK >= MAX(1,MIN(M,N)*(MIN(M,N)+4)) for the paths (see
1.1       bertrand  218: *>          comments inside the code):
1.4       bertrand  219: *>             - PATH 1  (M much larger than N)
1.1       bertrand  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))
1.4       bertrand  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
1.1       bertrand  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: *
1.4       bertrand  252: *> \author Univ. of Tennessee
                    253: *> \author Univ. of California Berkeley
                    254: *> \author Univ. of Colorado Denver
                    255: *> \author NAG Ltd.
1.1       bertrand  256: *
                    257: *> \ingroup doubleGEsing
                    258: *
                    259: *  =====================================================================
1.4       bertrand  260:       SUBROUTINE DGESVDX( JOBU, JOBVT, RANGE, M, N, A, LDA, VL, VU,
                    261:      $                    IL, IU, NS, S, U, LDU, VT, LDVT, WORK,
1.1       bertrand  262:      $                    LWORK, IWORK, INFO )
                    263: *
1.8     ! bertrand  264: *  -- LAPACK driver routine --
1.1       bertrand  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,
1.4       bertrand  289:      $                   ITAU, ITAUP, ITAUQ, ITEMP, ITGKZ, IUTGK,
1.1       bertrand  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,
1.6       bertrand  299:      $                   DCOPY, XERBLA
1.1       bertrand  300: *     ..
                    301: *     .. External Functions ..
                    302:       LOGICAL            LSAME
                    303:       INTEGER            ILAENV
1.4       bertrand  304:       DOUBLE PRECISION   DLAMCH, DLANGE
                    305:       EXTERNAL           LSAME, ILAENV, DLAMCH, DLANGE
1.1       bertrand  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
1.2       bertrand  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
1.1       bertrand  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: *
1.4       bertrand  392:                   MAXWRK = N +
1.1       bertrand  393:      $                     N*ILAENV( 1, 'DGEQRF', ' ', M, N, -1, -1 )
1.2       bertrand  394:                   MAXWRK = MAX( MAXWRK, N*(N+5) + 2*N*
1.1       bertrand  395:      $                     ILAENV( 1, 'DGEBRD', ' ', N, N, -1, -1 ) )
1.2       bertrand  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)
1.1       bertrand  405:                ELSE
                    406: *
                    407: *                 Path 2 (M at least N, but not much larger)
                    408: *
1.2       bertrand  409:                   MAXWRK = 4*N + ( M+N )*
1.1       bertrand  410:      $                     ILAENV( 1, 'DGEBRD', ' ', M, N, -1, -1 )
1.2       bertrand  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)
1.1       bertrand  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: *
1.4       bertrand  427:                   MAXWRK = M +
1.1       bertrand  428:      $                     M*ILAENV( 1, 'DGELQF', ' ', M, N, -1, -1 )
1.2       bertrand  429:                   MAXWRK = MAX( MAXWRK, M*(M+5) + 2*M*
1.1       bertrand  430:      $                     ILAENV( 1, 'DGEBRD', ' ', M, M, -1, -1 ) )
1.2       bertrand  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)
1.1       bertrand  440:                ELSE
                    441: *
1.2       bertrand  442: *                 Path 2t (N at least M, but not much larger)
1.1       bertrand  443: *
1.2       bertrand  444:                   MAXWRK = 4*M + ( M+N )*
1.1       bertrand  445:      $                     ILAENV( 1, 'DGEBRD', ' ', M, N, -1, -1 )
1.2       bertrand  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)
1.1       bertrand  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
1.4       bertrand  489:       ELSE
1.1       bertrand  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 )
1.4       bertrand  533: *
1.1       bertrand  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
1.4       bertrand  542:             ITEMP = ITAUP + N
1.1       bertrand  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 )
1.4       bertrand  545:             CALL DGEBRD( N, N, WORK( IQRF ), N, WORK( ID ), WORK( IE ),
1.1       bertrand  546:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
                    547:      $                   LWORK-ITEMP+1, INFO )
                    548: *
                    549: *           Solve eigenvalue problem TGK*Z=Z*S.
1.4       bertrand  550: *           (Workspace: need 14*N + 2*N*(N+1))
                    551: *
1.1       bertrand  552:             ITGKZ = ITEMP
                    553:             ITEMP = ITGKZ + N*(N*2+1)
1.4       bertrand  554:             CALL DBDSVDX( 'U', JOBZ, RNGTGK, N, WORK( ID ), WORK( IE ),
1.1       bertrand  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
1.2       bertrand  566:                CALL DLASET( 'A', M-N, NS, ZERO, ZERO, U( N+1,1 ), LDU )
1.1       bertrand  567: *
                    568: *              Call DORMBR to compute QB*UB.
                    569: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
                    570: *
1.4       bertrand  571:                CALL DORMBR( 'Q', 'L', 'N', N, NS, N, WORK( IQRF ), N,
                    572:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
1.1       bertrand  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: *
1.4       bertrand  578:                CALL DORMQR( 'L', 'N', M, NS, N, A, LDA,
1.1       bertrand  579:      $                      WORK( ITAU ), U, LDU, WORK( ITEMP ),
                    580:      $                      LWORK-ITEMP+1, INFO )
1.4       bertrand  581:             END IF
                    582: *
1.1       bertrand  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: *
1.4       bertrand  595:                CALL DORMBR( 'P', 'R', 'T', NS, N, N, WORK( IQRF ), N,
1.1       bertrand  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
1.4       bertrand  613:             ITEMP = ITAUP + N
                    614:             CALL DGEBRD( M, N, A, LDA, WORK( ID ), WORK( IE ),
1.1       bertrand  615:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
                    616:      $                   LWORK-ITEMP+1, INFO )
                    617: *
                    618: *           Solve eigenvalue problem TGK*Z=Z*S.
1.4       bertrand  619: *           (Workspace: need 14*N + 2*N*(N+1))
                    620: *
1.1       bertrand  621:             ITGKZ = ITEMP
                    622:             ITEMP = ITGKZ + N*(N*2+1)
1.4       bertrand  623:             CALL DBDSVDX( 'U', JOBZ, RNGTGK, N, WORK( ID ), WORK( IE ),
1.1       bertrand  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
1.2       bertrand  635:                CALL DLASET( 'A', M-N, NS, ZERO, ZERO, U( N+1,1 ), LDU )
1.1       bertrand  636: *
                    637: *              Call DORMBR to compute QB*UB.
                    638: *              (Workspace in WORK( ITEMP ): need N, prefer N*NB)
1.4       bertrand  639: *
                    640:                CALL DORMBR( 'Q', 'L', 'N', M, NS, N, A, LDA,
                    641:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
1.1       bertrand  642:      $                      LWORK-ITEMP+1, IERR )
1.4       bertrand  643:             END IF
                    644: *
1.1       bertrand  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: *
1.4       bertrand  657:                CALL DORMBR( 'P', 'R', 'T', NS, N, N, A, LDA,
1.1       bertrand  658:      $                      WORK( ITAUP ), VT, LDVT, WORK( ITEMP ),
                    659:      $                      LWORK-ITEMP+1, IERR )
                    660:             END IF
1.4       bertrand  661:          END IF
1.1       bertrand  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):
1.4       bertrand  670: *           A = L * Q = ( QB * B * PB**T ) * Q
1.1       bertrand  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 )
1.4       bertrand  693:             CALL DGEBRD( M, M, WORK( ILQF ), M, WORK( ID ), WORK( IE ),
1.1       bertrand  694:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
                    695:      $                   LWORK-ITEMP+1, INFO )
                    696: *
                    697: *           Solve eigenvalue problem TGK*Z=Z*S.
1.4       bertrand  698: *           (Workspace: need 2*M*M+14*M)
1.1       bertrand  699: *
                    700:             ITGKZ = ITEMP
                    701:             ITEMP = ITGKZ + M*(M*2+1)
1.4       bertrand  702:             CALL DBDSVDX( 'U', JOBZ, RNGTGK, M, WORK( ID ), WORK( IE ),
1.1       bertrand  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: *
1.4       bertrand  718:                CALL DORMBR( 'Q', 'L', 'N', M, NS, M, WORK( ILQF ), M,
                    719:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
1.1       bertrand  720:      $                      LWORK-ITEMP+1, INFO )
1.4       bertrand  721:             END IF
                    722: *
1.1       bertrand  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
1.2       bertrand  731:                CALL DLASET( 'A', NS, N-M, ZERO, ZERO, VT( 1,M+1 ), LDVT)
1.1       bertrand  732: *
                    733: *              Call DORMBR to compute (VB**T)*(PB**T)
                    734: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
                    735: *
1.4       bertrand  736:                CALL DORMBR( 'P', 'R', 'T', NS, M, M, WORK( ILQF ), M,
1.1       bertrand  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: *
1.4       bertrand  743:                CALL DORMLQ( 'R', 'N', NS, N, M, A, LDA,
1.1       bertrand  744:      $                      WORK( ITAU ), VT, LDVT, WORK( ITEMP ),
                    745:      $                      LWORK-ITEMP+1, INFO )
1.4       bertrand  746:             END IF
1.1       bertrand  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
1.4       bertrand  752: *           U = QB * UB; V**T = VB**T * PB**T
1.1       bertrand  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
1.4       bertrand  762:             CALL DGEBRD( M, N, A, LDA, WORK( ID ), WORK( IE ),
1.1       bertrand  763:      $                   WORK( ITAUQ ), WORK( ITAUP ), WORK( ITEMP ),
                    764:      $                   LWORK-ITEMP+1, INFO )
                    765: *
                    766: *           Solve eigenvalue problem TGK*Z=Z*S.
1.4       bertrand  767: *           (Workspace: need 2*M*M+14*M)
1.1       bertrand  768: *
                    769:             ITGKZ = ITEMP
                    770:             ITEMP = ITGKZ + M*(M*2+1)
1.4       bertrand  771:             CALL DBDSVDX( 'L', JOBZ, RNGTGK, M, WORK( ID ), WORK( IE ),
1.1       bertrand  772:      $                    VL, VU, ILTGK, IUTGK, NS, S, WORK( ITGKZ ),
                    773:      $                    M*2, WORK( ITEMP ), IWORK, INFO)
1.4       bertrand  774: *
1.1       bertrand  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: *
1.4       bertrand  787:                CALL DORMBR( 'Q', 'L', 'N', M, NS, N, A, LDA,
                    788:      $                      WORK( ITAUQ ), U, LDU, WORK( ITEMP ),
1.1       bertrand  789:      $                      LWORK-ITEMP+1, INFO )
1.4       bertrand  790:             END IF
                    791: *
1.1       bertrand  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
1.2       bertrand  800:                CALL DLASET( 'A', NS, N-M, ZERO, ZERO, VT( 1,M+1 ), LDVT)
1.1       bertrand  801: *
                    802: *              Call DORMBR to compute VB**T * PB**T
                    803: *              (Workspace in WORK( ITEMP ): need M, prefer M*NB)
                    804: *
1.4       bertrand  805:                CALL DORMBR( 'P', 'R', 'T', NS, N, M, A, LDA,
1.1       bertrand  806:      $                      WORK( ITAUP ), VT, LDVT, WORK( ITEMP ),
                    807:      $                      LWORK-ITEMP+1, INFO )
1.4       bertrand  808:             END IF
1.1       bertrand  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>