Annotation of rpl/lapack/lapack/dbdsvdx.f, revision 1.1
1.1 ! bertrand 1: *> \brief \b DBDSVDX
! 2: *
! 3: * =========== DOCUMENTATION ===========
! 4: *
! 5: * Online html documentation available at
! 6: * http://www.netlib.org/lapack/explore-html/
! 7: *
! 8: *> \htmlonly
! 9: *> Download DBDSVDX + dependencies
! 10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dbdsvdx.f">
! 11: *> [TGZ]</a>
! 12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dbdsvdx.f">
! 13: *> [ZIP]</a>
! 14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dbdsvdx.f">
! 15: *> [TXT]</a>
! 16: *> \endhtmlonly
! 17: *
! 18: * Definition:
! 19: * ===========
! 20: *
! 21: * SUBROUTINE DBDSVDX( UPLO, JOBZ, RANGE, N, D, E, VL, VU, IL, IU,
! 22: * $ NS, S, Z, LDZ, WORK, IWORK, INFO )
! 23: *
! 24: * .. Scalar Arguments ..
! 25: * CHARACTER JOBZ, RANGE, UPLO
! 26: * INTEGER IL, INFO, IU, LDZ, N, NS
! 27: * DOUBLE PRECISION VL, VU
! 28: * ..
! 29: * .. Array Arguments ..
! 30: * INTEGER IWORK( * )
! 31: * DOUBLE PRECISION D( * ), E( * ), S( * ), WORK( * ),
! 32: * Z( LDZ, * )
! 33: * ..
! 34: *
! 35: *> \par Purpose:
! 36: * =============
! 37: *>
! 38: *> \verbatim
! 39: *>
! 40: *> DBDSVDX computes the singular value decomposition (SVD) of a real
! 41: *> N-by-N (upper or lower) bidiagonal matrix B, B = U * S * VT,
! 42: *> where S is a diagonal matrix with non-negative diagonal elements
! 43: *> (the singular values of B), and U and VT are orthogonal matrices
! 44: *> of left and right singular vectors, respectively.
! 45: *>
! 46: *> Given an upper bidiagonal B with diagonal D = [ d_1 d_2 ... d_N ]
! 47: *> and superdiagonal E = [ e_1 e_2 ... e_N-1 ], DBDSVDX computes the
! 48: *> singular value decompositon of B through the eigenvalues and
! 49: *> eigenvectors of the N*2-by-N*2 tridiagonal matrix
! 50: *>
! 51: *> | 0 d_1 |
! 52: *> | d_1 0 e_1 |
! 53: *> TGK = | e_1 0 d_2 |
! 54: *> | d_2 . . |
! 55: *> | . . . |
! 56: *>
! 57: *> If (s,u,v) is a singular triplet of B with ||u|| = ||v|| = 1, then
! 58: *> (+/-s,q), ||q|| = 1, are eigenpairs of TGK, with q = P * ( u' +/-v' ) /
! 59: *> sqrt(2) = ( v_1 u_1 v_2 u_2 ... v_n u_n ) / sqrt(2), and
! 60: *> P = [ e_{n+1} e_{1} e_{n+2} e_{2} ... ].
! 61: *>
! 62: *> Given a TGK matrix, one can either a) compute -s,-v and change signs
! 63: *> so that the singular values (and corresponding vectors) are already in
! 64: *> descending order (as in DGESVD/DGESDD) or b) compute s,v and reorder
! 65: *> the values (and corresponding vectors). DBDSVDX implements a) by
! 66: *> calling DSTEVX (bisection plus inverse iteration, to be replaced
! 67: *> with a version of the Multiple Relative Robust Representation
! 68: *> algorithm. (See P. Willems and B. Lang, A framework for the MR^3
! 69: *> algorithm: theory and implementation, SIAM J. Sci. Comput.,
! 70: *> 35:740-766, 2013.)
! 71: *> \endverbatim
! 72: *
! 73: * Arguments:
! 74: * ==========
! 75: *
! 76: *> \param[in] UPLO
! 77: *> \verbatim
! 78: *> UPLO is CHARACTER*1
! 79: *> = 'U': B is upper bidiagonal;
! 80: *> = 'L': B is lower bidiagonal.
! 81: *> \endverbatim
! 82: *>
! 83: *> \param[in] JOBXZ
! 84: *> \verbatim
! 85: *> JOBZ is CHARACTER*1
! 86: *> = 'N': Compute singular values only;
! 87: *> = 'V': Compute singular values and singular vectors.
! 88: *> \endverbatim
! 89: *>
! 90: *> \param[in] RANGE
! 91: *> \verbatim
! 92: *> RANGE is CHARACTER*1
! 93: *> = 'A': all singular values will be found.
! 94: *> = 'V': all singular values in the half-open interval [VL,VU)
! 95: *> will be found.
! 96: *> = 'I': the IL-th through IU-th singular values will be found.
! 97: *> \endverbatim
! 98: *>
! 99: *> \param[in] N
! 100: *> \verbatim
! 101: *> N is INTEGER
! 102: *> The order of the bidiagonal matrix. N >= 0.
! 103: *> \endverbatim
! 104: *>
! 105: *> \param[in] D
! 106: *> \verbatim
! 107: *> D is DOUBLE PRECISION array, dimension (N)
! 108: *> The n diagonal elements of the bidiagonal matrix B.
! 109: *> \endverbatim
! 110: *>
! 111: *> \param[in] E
! 112: *> \verbatim
! 113: *> E is DOUBLE PRECISION array, dimension (max(1,N-1))
! 114: *> The (n-1) superdiagonal elements of the bidiagonal matrix
! 115: *> B in elements 1 to N-1.
! 116: *> \endverbatim
! 117: *>
! 118: *> \param[in] VL
! 119: *> \verbatim
! 120: *> VL is DOUBLE PRECISION
! 121: *> VL >=0.
! 122: *> \endverbatim
! 123: *>
! 124: *> \param[in] VU
! 125: *> \verbatim
! 126: *> VU is DOUBLE PRECISION
! 127: *> If RANGE='V', the lower and upper bounds of the interval to
! 128: *> be searched for singular values. VU > VL.
! 129: *> Not referenced if RANGE = 'A' or 'I'.
! 130: *> \endverbatim
! 131: *>
! 132: *> \param[in] IL
! 133: *> \verbatim
! 134: *> IL is INTEGER
! 135: *> \endverbatim
! 136: *>
! 137: *> \param[in] IU
! 138: *> \verbatim
! 139: *> IU is INTEGER
! 140: *> If RANGE='I', the indices (in ascending order) of the
! 141: *> smallest and largest singular values to be returned.
! 142: *> 1 <= IL <= IU <= min(M,N), if min(M,N) > 0.
! 143: *> Not referenced if RANGE = 'A' or 'V'.
! 144: *> \endverbatim
! 145: *>
! 146: *> \param[out] NS
! 147: *> \verbatim
! 148: *> NS is INTEGER
! 149: *> The total number of singular values found. 0 <= NS <= N.
! 150: *> If RANGE = 'A', NS = N, and if RANGE = 'I', NS = IU-IL+1.
! 151: *> \endverbatim
! 152: *>
! 153: *> \param[out] S
! 154: *> \verbatim
! 155: *> S is DOUBLE PRECISION array, dimension (N)
! 156: *> The first NS elements contain the selected singular values in
! 157: *> ascending order.
! 158: *> \endverbatim
! 159: *>
! 160: *> \param[out] Z
! 161: *> \verbatim
! 162: *> Z is DOUBLE PRECISION array, dimension (2*N,K) )
! 163: *> If JOBZ = 'V', then if INFO = 0 the first NS columns of Z
! 164: *> contain the singular vectors of the matrix B corresponding to
! 165: *> the selected singular values, with U in rows 1 to N and V
! 166: *> in rows N+1 to N*2, i.e.
! 167: *> Z = [ U ]
! 168: *> [ V ]
! 169: *> If JOBZ = 'N', then Z is not referenced.
! 170: *> Note: The user must ensure that at least K = NS+1 columns are
! 171: *> supplied in the array Z; if RANGE = 'V', the exact value of
! 172: *> NS is not known in advance and an upper bound must be used.
! 173: *> \endverbatim
! 174: *>
! 175: *> \param[in] LDZ
! 176: *> \verbatim
! 177: *> LDZ is INTEGER
! 178: *> The leading dimension of the array Z. LDZ >= 1, and if
! 179: *> JOBZ = 'V', LDZ >= max(2,N*2).
! 180: *> \endverbatim
! 181: *>
! 182: *> \param[out] WORK
! 183: *> \verbatim
! 184: *> WORK is DOUBLE PRECISION array, dimension (14*N)
! 185: *> \endverbatim
! 186: *>
! 187: *> \param[out] IWORK
! 188: *> \verbatim
! 189: *> IWORK is INTEGER array, dimension (12*N)
! 190: *> If JOBZ = 'V', then if INFO = 0, the first NS elements of
! 191: *> IWORK are zero. If INFO > 0, then IWORK contains the indices
! 192: *> of the eigenvectors that failed to converge in DSTEVX.
! 193: *>
! 194: *> INFO is INTEGER
! 195: *> = 0: successful exit
! 196: *> < 0: if INFO = -i, the i-th argument had an illegal value
! 197: *> > 0: if INFO = i, then i eigenvectors failed to converge
! 198: *> in DSTEVX. The indices of the eigenvectors
! 199: *> (as returned by DSTEVX) are stored in the
! 200: *> array IWORK.
! 201: *> if INFO = N*2 + 1, an internal error occurred.
! 202: *> \endverbatim
! 203: *
! 204: * Authors:
! 205: * ========
! 206: *
! 207: *> \author Univ. of Tennessee
! 208: *> \author Univ. of California Berkeley
! 209: *> \author Univ. of Colorado Denver
! 210: *> \author NAG Ltd.
! 211: *
! 212: *> \date November 2011
! 213: *
! 214: *> \ingroup doubleOTHEReigen
! 215: *
! 216: * =====================================================================
! 217: SUBROUTINE DBDSVDX( UPLO, JOBZ, RANGE, N, D, E, VL, VU, IL, IU,
! 218: $ NS, S, Z, LDZ, WORK, IWORK, INFO)
! 219: *
! 220: * -- LAPACK driver routine (version 3.6.0) --
! 221: * -- LAPACK is a software package provided by Univ. of Tennessee, --
! 222: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
! 223: * November 2016
! 224: *
! 225: * .. Scalar Arguments ..
! 226: CHARACTER JOBZ, RANGE, UPLO
! 227: INTEGER IL, INFO, IU, LDZ, N, NS
! 228: DOUBLE PRECISION VL, VU
! 229: * ..
! 230: * .. Array Arguments ..
! 231: INTEGER IWORK( * )
! 232: DOUBLE PRECISION D( * ), E( * ), S( * ), WORK( * ),
! 233: $ Z( LDZ, * )
! 234: * ..
! 235: *
! 236: * =====================================================================
! 237: *
! 238: * .. Parameters ..
! 239: DOUBLE PRECISION ZERO, ONE, TEN, HNDRD, MEIGTH
! 240: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0, TEN = 10.0D0,
! 241: $ HNDRD = 100.0D0, MEIGTH = -0.1250D0 )
! 242: DOUBLE PRECISION FUDGE
! 243: PARAMETER ( FUDGE = 2.0D0 )
! 244: * ..
! 245: * .. Local Scalars ..
! 246: CHARACTER RNGVX
! 247: LOGICAL ALLSV, INDSV, LOWER, SPLIT, SVEQ0, VALSV, WANTZ
! 248: INTEGER I, ICOLZ, IDBEG, IDEND, IDTGK, IDPTR, IEPTR,
! 249: $ IETGK, IIFAIL, IIWORK, ILTGK, IROWU, IROWV,
! 250: $ IROWZ, ISBEG, ISPLT, ITEMP, IUTGK, J, K,
! 251: $ NTGK, NRU, NRV, NSL
! 252: DOUBLE PRECISION ABSTOL, EPS, EMIN, MU, NRMU, NRMV, ORTOL, SMAX,
! 253: $ SMIN, SQRT2, THRESH, TOL, ULP,
! 254: $ VLTGK, VUTGK, ZJTJI
! 255: * ..
! 256: * .. External Functions ..
! 257: LOGICAL LSAME
! 258: INTEGER IDAMAX
! 259: DOUBLE PRECISION DDOT, DLAMCH, DNRM2
! 260: EXTERNAL IDAMAX, LSAME, DAXPY, DDOT, DLAMCH, DNRM2
! 261: * ..
! 262: * .. External Subroutines ..
! 263: EXTERNAL DCOPY, DLASET, DSCAL, DSWAP
! 264: * ..
! 265: * .. Intrinsic Functions ..
! 266: INTRINSIC ABS, DBLE, SIGN, SQRT
! 267: * ..
! 268: * .. Executable Statements ..
! 269: *
! 270: * Test the input parameters.
! 271: *
! 272: ALLSV = LSAME( RANGE, 'A' )
! 273: VALSV = LSAME( RANGE, 'V' )
! 274: INDSV = LSAME( RANGE, 'I' )
! 275: WANTZ = LSAME( JOBZ, 'V' )
! 276: LOWER = LSAME( UPLO, 'L' )
! 277: *
! 278: INFO = 0
! 279: IF( .NOT.LSAME( UPLO, 'U' ) .AND. .NOT.LOWER ) THEN
! 280: INFO = -1
! 281: ELSE IF( .NOT.( WANTZ .OR. LSAME( JOBZ, 'N' ) ) ) THEN
! 282: INFO = -2
! 283: ELSE IF( .NOT.( ALLSV .OR. VALSV .OR. INDSV ) ) THEN
! 284: INFO = -3
! 285: ELSE IF( N.LT.0 ) THEN
! 286: INFO = -4
! 287: ELSE IF( N.GT.0 ) THEN
! 288: IF( VALSV ) THEN
! 289: IF( VL.LT.ZERO ) THEN
! 290: INFO = -7
! 291: ELSE IF( VU.LE.VL ) THEN
! 292: INFO = -8
! 293: END IF
! 294: ELSE IF( INDSV ) THEN
! 295: IF( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) THEN
! 296: INFO = -9
! 297: ELSE IF( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) THEN
! 298: INFO = -10
! 299: END IF
! 300: END IF
! 301: END IF
! 302: IF( INFO.EQ.0 ) THEN
! 303: IF( LDZ.LT.1 .OR. ( WANTZ .AND. LDZ.LT.N*2 ) ) INFO = -14
! 304: END IF
! 305: *
! 306: IF( INFO.NE.0 ) THEN
! 307: CALL XERBLA( 'DBDSVDX', -INFO )
! 308: RETURN
! 309: END IF
! 310: *
! 311: * Quick return if possible (N.LE.1)
! 312: *
! 313: NS = 0
! 314: IF( N.EQ.0 ) RETURN
! 315: *
! 316: IF( N.EQ.1 ) THEN
! 317: IF( ALLSV .OR. INDSV ) THEN
! 318: NS = 1
! 319: S( 1 ) = ABS( D( 1 ) )
! 320: ELSE
! 321: IF( VL.LT.ABS( D( 1 ) ) .AND. VU.GE.ABS( D( 1 ) ) ) THEN
! 322: NS = 1
! 323: S( 1 ) = ABS( D( 1 ) )
! 324: END IF
! 325: END IF
! 326: IF( WANTZ ) THEN
! 327: Z( 1, 1 ) = SIGN( ONE, D( 1 ) )
! 328: Z( 2, 1 ) = ONE
! 329: END IF
! 330: RETURN
! 331: END IF
! 332: *
! 333: ABSTOL = 2*DLAMCH( 'Safe Minimum' )
! 334: ULP = DLAMCH( 'Precision' )
! 335: EPS = DLAMCH( 'Epsilon' )
! 336: SQRT2 = SQRT( 2.0D0 )
! 337: ORTOL = SQRT( ULP )
! 338: *
! 339: * Criterion for splitting is taken from DBDSQR when singular
! 340: * values are computed to relative accuracy TOL. (See J. Demmel and
! 341: * W. Kahan, Accurate singular values of bidiagonal matrices, SIAM
! 342: * J. Sci. and Stat. Comput., 11:873–912, 1990.)
! 343: *
! 344: TOL = MAX( TEN, MIN( HNDRD, EPS**MEIGTH ) )*EPS
! 345: *
! 346: * Compute approximate maximum, minimum singular values.
! 347: *
! 348: I = IDAMAX( N, D, 1 )
! 349: SMAX = ABS( D( I ) )
! 350: I = IDAMAX( N-1, E, 1 )
! 351: SMAX = MAX( SMAX, ABS( E( I ) ) )
! 352: *
! 353: * Compute threshold for neglecting D's and E's.
! 354: *
! 355: SMIN = ABS( D( 1 ) )
! 356: IF( SMIN.NE.ZERO ) THEN
! 357: MU = SMIN
! 358: DO I = 2, N
! 359: MU = ABS( D( I ) )*( MU / ( MU+ABS( E( I-1 ) ) ) )
! 360: SMIN = MIN( SMIN, MU )
! 361: IF( SMIN.EQ.ZERO ) EXIT
! 362: END DO
! 363: END IF
! 364: SMIN = SMIN / SQRT( DBLE( N ) )
! 365: THRESH = TOL*SMIN
! 366: *
! 367: * Check for zeros in D and E (splits), i.e. submatrices.
! 368: *
! 369: DO I = 1, N-1
! 370: IF( ABS( D( I ) ).LE.THRESH ) D( I ) = ZERO
! 371: IF( ABS( E( I ) ).LE.THRESH ) E( I ) = ZERO
! 372: END DO
! 373: IF( ABS( D( N ) ).LE.THRESH ) D( N ) = ZERO
! 374: E( N ) = ZERO
! 375: *
! 376: * Pointers for arrays used by DSTEVX.
! 377: *
! 378: IDTGK = 1
! 379: IETGK = IDTGK + N*2
! 380: ITEMP = IETGK + N*2
! 381: IIFAIL = 1
! 382: IIWORK = IIFAIL + N*2
! 383: *
! 384: * Set RNGVX, which corresponds to RANGE for DSTEVX in TGK mode.
! 385: * VL,VU or IL,IU are redefined to conform to implementation a)
! 386: * described in the leading comments.
! 387: *
! 388: ILTGK = 0
! 389: IUTGK = 0
! 390: VLTGK = ZERO
! 391: VUTGK = ZERO
! 392: *
! 393: IF( ALLSV ) THEN
! 394: *
! 395: * All singular values will be found. We aim at -s (see
! 396: * leading comments) with RNGVX = 'I'. IL and IU are set
! 397: * later (as ILTGK and IUTGK) according to the dimension
! 398: * of the active submatrix.
! 399: *
! 400: RNGVX = 'I'
! 401: CALL DLASET( 'F', N*2, N+1, ZERO, ZERO, Z, LDZ )
! 402: ELSE IF( VALSV ) THEN
! 403: *
! 404: * Find singular values in a half-open interval. We aim
! 405: * at -s (see leading comments) and we swap VL and VU
! 406: * (as VUTGK and VLTGK), changing their signs.
! 407: *
! 408: RNGVX = 'V'
! 409: VLTGK = -VU
! 410: VUTGK = -VL
! 411: WORK( IDTGK:IDTGK+2*N-1 ) = ZERO
! 412: CALL DCOPY( N, D, 1, WORK( IETGK ), 2 )
! 413: CALL DCOPY( N-1, E, 1, WORK( IETGK+1 ), 2 )
! 414: CALL DSTEVX( 'N', 'V', N*2, WORK( IDTGK ), WORK( IETGK ),
! 415: $ VLTGK, VUTGK, ILTGK, ILTGK, ABSTOL, NS, S,
! 416: $ Z, LDZ, WORK( ITEMP ), IWORK( IIWORK ),
! 417: $ IWORK( IIFAIL ), INFO )
! 418: IF( NS.EQ.0 ) THEN
! 419: RETURN
! 420: ELSE
! 421: CALL DLASET( 'F', N*2, NS, ZERO, ZERO, Z, LDZ )
! 422: END IF
! 423: ELSE IF( INDSV ) THEN
! 424: *
! 425: * Find the IL-th through the IU-th singular values. We aim
! 426: * at -s (see leading comments) and indices are mapped into
! 427: * values, therefore mimicking DSTEBZ, where
! 428: *
! 429: * GL = GL - FUDGE*TNORM*ULP*N - FUDGE*TWO*PIVMIN
! 430: * GU = GU + FUDGE*TNORM*ULP*N + FUDGE*PIVMIN
! 431: *
! 432: ILTGK = IL
! 433: IUTGK = IU
! 434: RNGVX = 'V'
! 435: WORK( IDTGK:IDTGK+2*N-1 ) = ZERO
! 436: CALL DCOPY( N, D, 1, WORK( IETGK ), 2 )
! 437: CALL DCOPY( N-1, E, 1, WORK( IETGK+1 ), 2 )
! 438: CALL DSTEVX( 'N', 'I', N*2, WORK( IDTGK ), WORK( IETGK ),
! 439: $ VLTGK, VLTGK, ILTGK, ILTGK, ABSTOL, NS, S,
! 440: $ Z, LDZ, WORK( ITEMP ), IWORK( IIWORK ),
! 441: $ IWORK( IIFAIL ), INFO )
! 442: VLTGK = S( 1 ) - FUDGE*SMAX*ULP*N
! 443: WORK( IDTGK:IDTGK+2*N-1 ) = ZERO
! 444: CALL DCOPY( N, D, 1, WORK( IETGK ), 2 )
! 445: CALL DCOPY( N-1, E, 1, WORK( IETGK+1 ), 2 )
! 446: CALL DSTEVX( 'N', 'I', N*2, WORK( IDTGK ), WORK( IETGK ),
! 447: $ VUTGK, VUTGK, IUTGK, IUTGK, ABSTOL, NS, S,
! 448: $ Z, LDZ, WORK( ITEMP ), IWORK( IIWORK ),
! 449: $ IWORK( IIFAIL ), INFO )
! 450: VUTGK = S( 1 ) + FUDGE*SMAX*ULP*N
! 451: VUTGK = MIN( VUTGK, ZERO )
! 452: *
! 453: * If VLTGK=VUTGK, DSTEVX returns an error message,
! 454: * so if needed we change VUTGK slightly.
! 455: *
! 456: IF( VLTGK.EQ.VUTGK ) VLTGK = VLTGK - TOL
! 457: *
! 458: CALL DLASET( 'F', N*2, IU-IL+1, ZERO, ZERO, Z, LDZ )
! 459: END IF
! 460: *
! 461: * Initialize variables and pointers for S, Z, and WORK.
! 462: *
! 463: * NRU, NRV: number of rows in U and V for the active submatrix
! 464: * IDBEG, ISBEG: offsets for the entries of D and S
! 465: * IROWZ, ICOLZ: offsets for the rows and columns of Z
! 466: * IROWU, IROWV: offsets for the rows of U and V
! 467: *
! 468: NS = 0
! 469: NRU = 0
! 470: NRV = 0
! 471: IDBEG = 1
! 472: ISBEG = 1
! 473: IROWZ = 1
! 474: ICOLZ = 1
! 475: IROWU = 2
! 476: IROWV = 1
! 477: SPLIT = .FALSE.
! 478: SVEQ0 = .FALSE.
! 479: *
! 480: * Form the tridiagonal TGK matrix.
! 481: *
! 482: S( 1:N ) = ZERO
! 483: WORK( IETGK+2*N-1 ) = ZERO
! 484: WORK( IDTGK:IDTGK+2*N-1 ) = ZERO
! 485: CALL DCOPY( N, D, 1, WORK( IETGK ), 2 )
! 486: CALL DCOPY( N-1, E, 1, WORK( IETGK+1 ), 2 )
! 487: *
! 488: *
! 489: * Check for splits in two levels, outer level
! 490: * in E and inner level in D.
! 491: *
! 492: DO IEPTR = 2, N*2, 2
! 493: IF( WORK( IETGK+IEPTR-1 ).EQ.ZERO ) THEN
! 494: *
! 495: * Split in E (this piece of B is square) or bottom
! 496: * of the (input bidiagonal) matrix.
! 497: *
! 498: ISPLT = IDBEG
! 499: IDEND = IEPTR - 1
! 500: DO IDPTR = IDBEG, IDEND, 2
! 501: IF( WORK( IETGK+IDPTR-1 ).EQ.ZERO ) THEN
! 502: *
! 503: * Split in D (rectangular submatrix). Set the number
! 504: * of rows in U and V (NRU and NRV) accordingly.
! 505: *
! 506: IF( IDPTR.EQ.IDBEG ) THEN
! 507: *
! 508: * D=0 at the top.
! 509: *
! 510: SVEQ0 = .TRUE.
! 511: IF( IDBEG.EQ.IDEND) THEN
! 512: NRU = 1
! 513: NRV = 1
! 514: END IF
! 515: ELSE IF( IDPTR.EQ.IDEND ) THEN
! 516: *
! 517: * D=0 at the bottom.
! 518: *
! 519: SVEQ0 = .TRUE.
! 520: NRU = (IDEND-ISPLT)/2 + 1
! 521: NRV = NRU
! 522: IF( ISPLT.NE.IDBEG ) THEN
! 523: NRU = NRU + 1
! 524: END IF
! 525: ELSE
! 526: IF( ISPLT.EQ.IDBEG ) THEN
! 527: *
! 528: * Split: top rectangular submatrix.
! 529: *
! 530: NRU = (IDPTR-IDBEG)/2
! 531: NRV = NRU + 1
! 532: ELSE
! 533: *
! 534: * Split: middle square submatrix.
! 535: *
! 536: NRU = (IDPTR-ISPLT)/2 + 1
! 537: NRV = NRU
! 538: END IF
! 539: END IF
! 540: ELSE IF( IDPTR.EQ.IDEND ) THEN
! 541: *
! 542: * Last entry of D in the active submatrix.
! 543: *
! 544: IF( ISPLT.EQ.IDBEG ) THEN
! 545: *
! 546: * No split (trivial case).
! 547: *
! 548: NRU = (IDEND-IDBEG)/2 + 1
! 549: NRV = NRU
! 550: ELSE
! 551: *
! 552: * Split: bottom rectangular submatrix.
! 553: *
! 554: NRV = (IDEND-ISPLT)/2 + 1
! 555: NRU = NRV + 1
! 556: END IF
! 557: END IF
! 558: *
! 559: NTGK = NRU + NRV
! 560: *
! 561: IF( NTGK.GT.0 ) THEN
! 562: *
! 563: * Compute eigenvalues/vectors of the active
! 564: * submatrix according to RANGE:
! 565: * if RANGE='A' (ALLSV) then RNGVX = 'I'
! 566: * if RANGE='V' (VALSV) then RNGVX = 'V'
! 567: * if RANGE='I' (INDSV) then RNGVX = 'V'
! 568: *
! 569: ILTGK = 1
! 570: IUTGK = NTGK / 2
! 571: IF( ALLSV .OR. VUTGK.EQ.ZERO ) THEN
! 572: IF( SVEQ0 .OR.
! 573: $ SMIN.LT.EPS .OR.
! 574: $ MOD(NTGK,2).GT.0 ) THEN
! 575: * Special case: eigenvalue equal to zero or very
! 576: * small, additional eigenvector is needed.
! 577: IUTGK = IUTGK + 1
! 578: END IF
! 579: END IF
! 580: *
! 581: * Workspace needed by DSTEVX:
! 582: * WORK( ITEMP: ): 2*5*NTGK
! 583: * IWORK( 1: ): 2*6*NTGK
! 584: *
! 585: CALL DSTEVX( JOBZ, RNGVX, NTGK, WORK( IDTGK+ISPLT-1 ),
! 586: $ WORK( IETGK+ISPLT-1 ), VLTGK, VUTGK,
! 587: $ ILTGK, IUTGK, ABSTOL, NSL, S( ISBEG ),
! 588: $ Z( IROWZ,ICOLZ ), LDZ, WORK( ITEMP ),
! 589: $ IWORK( IIWORK ), IWORK( IIFAIL ),
! 590: $ INFO )
! 591: IF( INFO.NE.0 ) THEN
! 592: * Exit with the error code from DSTEVX.
! 593: RETURN
! 594: END IF
! 595: EMIN = ABS( MAXVAL( S( ISBEG:ISBEG+NSL-1 ) ) )
! 596: *
! 597: IF( NSL.GT.0 .AND. WANTZ ) THEN
! 598: *
! 599: * Normalize u=Z([2,4,...],:) and v=Z([1,3,...],:),
! 600: * changing the sign of v as discussed in the leading
! 601: * comments. The norms of u and v may be (slightly)
! 602: * different from 1/sqrt(2) if the corresponding
! 603: * eigenvalues are very small or too close. We check
! 604: * those norms and, if needed, reorthogonalize the
! 605: * vectors.
! 606: *
! 607: IF( NSL.GT.1 .AND.
! 608: $ VUTGK.EQ.ZERO .AND.
! 609: $ MOD(NTGK,2).EQ.0 .AND.
! 610: $ EMIN.EQ.0 .AND. .NOT.SPLIT ) THEN
! 611: *
! 612: * D=0 at the top or bottom of the active submatrix:
! 613: * one eigenvalue is equal to zero; concatenate the
! 614: * eigenvectors corresponding to the two smallest
! 615: * eigenvalues.
! 616: *
! 617: Z( IROWZ:IROWZ+NTGK-1,ICOLZ+NSL-2 ) =
! 618: $ Z( IROWZ:IROWZ+NTGK-1,ICOLZ+NSL-2 ) +
! 619: $ Z( IROWZ:IROWZ+NTGK-1,ICOLZ+NSL-1 )
! 620: Z( IROWZ:IROWZ+NTGK-1,ICOLZ+NSL-1 ) =
! 621: $ ZERO
! 622: * IF( IUTGK*2.GT.NTGK ) THEN
! 623: * Eigenvalue equal to zero or very small.
! 624: * NSL = NSL - 1
! 625: * END IF
! 626: END IF
! 627: *
! 628: DO I = 0, MIN( NSL-1, NRU-1 )
! 629: NRMU = DNRM2( NRU, Z( IROWU, ICOLZ+I ), 2 )
! 630: IF( NRMU.EQ.ZERO ) THEN
! 631: INFO = N*2 + 1
! 632: RETURN
! 633: END IF
! 634: CALL DSCAL( NRU, ONE/NRMU,
! 635: $ Z( IROWU,ICOLZ+I ), 2 )
! 636: IF( NRMU.NE.ONE .AND.
! 637: $ ABS( NRMU-ORTOL )*SQRT2.GT.ONE )
! 638: $ THEN
! 639: DO J = 0, I-1
! 640: ZJTJI = -DDOT( NRU, Z( IROWU, ICOLZ+J ),
! 641: $ 2, Z( IROWU, ICOLZ+I ), 2 )
! 642: CALL DAXPY( NRU, ZJTJI,
! 643: $ Z( IROWU, ICOLZ+J ), 2,
! 644: $ Z( IROWU, ICOLZ+I ), 2 )
! 645: END DO
! 646: NRMU = DNRM2( NRU, Z( IROWU, ICOLZ+I ), 2 )
! 647: CALL DSCAL( NRU, ONE/NRMU,
! 648: $ Z( IROWU,ICOLZ+I ), 2 )
! 649: END IF
! 650: END DO
! 651: DO I = 0, MIN( NSL-1, NRV-1 )
! 652: NRMV = DNRM2( NRV, Z( IROWV, ICOLZ+I ), 2 )
! 653: IF( NRMV.EQ.ZERO ) THEN
! 654: INFO = N*2 + 1
! 655: RETURN
! 656: END IF
! 657: CALL DSCAL( NRV, -ONE/NRMV,
! 658: $ Z( IROWV,ICOLZ+I ), 2 )
! 659: IF( NRMV.NE.ONE .AND.
! 660: $ ABS( NRMV-ORTOL )*SQRT2.GT.ONE )
! 661: $ THEN
! 662: DO J = 0, I-1
! 663: ZJTJI = -DDOT( NRV, Z( IROWV, ICOLZ+J ),
! 664: $ 2, Z( IROWV, ICOLZ+I ), 2 )
! 665: CALL DAXPY( NRU, ZJTJI,
! 666: $ Z( IROWV, ICOLZ+J ), 2,
! 667: $ Z( IROWV, ICOLZ+I ), 2 )
! 668: END DO
! 669: NRMV = DNRM2( NRV, Z( IROWV, ICOLZ+I ), 2 )
! 670: CALL DSCAL( NRV, ONE/NRMV,
! 671: $ Z( IROWV,ICOLZ+I ), 2 )
! 672: END IF
! 673: END DO
! 674: IF( VUTGK.EQ.ZERO .AND.
! 675: $ IDPTR.LT.IDEND .AND.
! 676: $ MOD(NTGK,2).GT.0 ) THEN
! 677: *
! 678: * D=0 in the middle of the active submatrix (one
! 679: * eigenvalue is equal to zero): save the corresponding
! 680: * eigenvector for later use (when bottom of the
! 681: * active submatrix is reached).
! 682: *
! 683: SPLIT = .TRUE.
! 684: Z( IROWZ:IROWZ+NTGK-1,N+1 ) =
! 685: $ Z( IROWZ:IROWZ+NTGK-1,NS+NSL )
! 686: Z( IROWZ:IROWZ+NTGK-1,NS+NSL ) =
! 687: $ ZERO
! 688: END IF
! 689: END IF !** WANTZ **!
! 690: *
! 691: NSL = MIN( NSL, NRU )
! 692: SVEQ0 = .FALSE.
! 693: *
! 694: * Absolute values of the eigenvalues of TGK.
! 695: *
! 696: DO I = 0, NSL-1
! 697: S( ISBEG+I ) = ABS( S( ISBEG+I ) )
! 698: END DO
! 699: *
! 700: * Update pointers for TGK, S and Z.
! 701: *
! 702: ISBEG = ISBEG + NSL
! 703: IROWZ = IROWZ + NTGK
! 704: ICOLZ = ICOLZ + NSL
! 705: IROWU = IROWZ
! 706: IROWV = IROWZ + 1
! 707: ISPLT = IDPTR + 1
! 708: NS = NS + NSL
! 709: NRU = 0
! 710: NRV = 0
! 711: END IF !** NTGK.GT.0 **!
! 712: IF( IROWZ.LT.N*2 ) Z( 1:IROWZ-1, ICOLZ ) = ZERO
! 713: END DO !** IDPTR loop **!
! 714: IF( SPLIT ) THEN
! 715: *
! 716: * Bring back eigenvector corresponding
! 717: * to eigenvalue equal to zero.
! 718: *
! 719: Z( IDBEG:IDEND-NTGK+1,ISBEG-1 ) =
! 720: $ Z( IDBEG:IDEND-NTGK+1,ISBEG-1 ) +
! 721: $ Z( IDBEG:IDEND-NTGK+1,N+1 )
! 722: Z( IDBEG:IDEND-NTGK+1,N+1 ) = 0
! 723: END IF
! 724: IROWV = IROWV - 1
! 725: IROWU = IROWU + 1
! 726: IDBEG = IEPTR + 1
! 727: SVEQ0 = .FALSE.
! 728: SPLIT = .FALSE.
! 729: END IF !** Check for split in E **!
! 730: END DO !** IEPTR loop **!
! 731: *
! 732: * Sort the singular values into decreasing order (insertion sort on
! 733: * singular values, but only one transposition per singular vector)
! 734: *
! 735: DO I = 1, NS-1
! 736: K = 1
! 737: SMIN = S( 1 )
! 738: DO J = 2, NS + 1 - I
! 739: IF( S( J ).LE.SMIN ) THEN
! 740: K = J
! 741: SMIN = S( J )
! 742: END IF
! 743: END DO
! 744: IF( K.NE.NS+1-I ) THEN
! 745: S( K ) = S( NS+1-I )
! 746: S( NS+1-I ) = SMIN
! 747: CALL DSWAP( N*2, Z( 1,K ), 1, Z( 1,NS+1-I ), 1 )
! 748: END IF
! 749: END DO
! 750: *
! 751: * If RANGE=I, check for singular values/vectors to be discarded.
! 752: *
! 753: IF( INDSV ) THEN
! 754: K = IU - IL + 1
! 755: IF( K.LT.NS ) THEN
! 756: S( K+1:NS ) = ZERO
! 757: Z( 1:N*2,K+1:NS ) = ZERO
! 758: NS = K
! 759: END IF
! 760: END IF
! 761: *
! 762: * Reorder Z: U = Z( 1:N,1:NS ), V = Z( N+1:N*2,1:NS ).
! 763: * If B is a lower diagonal, swap U and V.
! 764: *
! 765: DO I = 1, NS
! 766: CALL DCOPY( N*2, Z( 1,I ), 1, WORK, 1 )
! 767: IF( LOWER ) THEN
! 768: CALL DCOPY( N, WORK( 2 ), 2, Z( N+1,I ), 1 )
! 769: CALL DCOPY( N, WORK( 1 ), 2, Z( 1 ,I ), 1 )
! 770: ELSE
! 771: CALL DCOPY( N, WORK( 2 ), 2, Z( 1 ,I ), 1 )
! 772: CALL DCOPY( N, WORK( 1 ), 2, Z( N+1,I ), 1 )
! 773: END IF
! 774: END DO
! 775: *
! 776: RETURN
! 777: *
! 778: * End of DBDSVDX
! 779: *
! 780: END
CVSweb interface <joel.bertrand@systella.fr>