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