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>