1: SUBROUTINE ZSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO )
2: *
3: * -- LAPACK routine (version 3.2) --
4: * -- LAPACK is a software package provided by Univ. of Tennessee, --
5: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
6: * November 2006
7: *
8: * .. Scalar Arguments ..
9: CHARACTER COMPZ
10: INTEGER INFO, LDZ, N
11: * ..
12: * .. Array Arguments ..
13: DOUBLE PRECISION D( * ), E( * ), WORK( * )
14: COMPLEX*16 Z( LDZ, * )
15: * ..
16: *
17: * Purpose
18: * =======
19: *
20: * ZSTEQR computes all eigenvalues and, optionally, eigenvectors of a
21: * symmetric tridiagonal matrix using the implicit QL or QR method.
22: * The eigenvectors of a full or band complex Hermitian matrix can also
23: * be found if ZHETRD or ZHPTRD or ZHBTRD has been used to reduce this
24: * matrix to tridiagonal form.
25: *
26: * Arguments
27: * =========
28: *
29: * COMPZ (input) CHARACTER*1
30: * = 'N': Compute eigenvalues only.
31: * = 'V': Compute eigenvalues and eigenvectors of the original
32: * Hermitian matrix. On entry, Z must contain the
33: * unitary matrix used to reduce the original matrix
34: * to tridiagonal form.
35: * = 'I': Compute eigenvalues and eigenvectors of the
36: * tridiagonal matrix. Z is initialized to the identity
37: * matrix.
38: *
39: * N (input) INTEGER
40: * The order of the matrix. N >= 0.
41: *
42: * D (input/output) DOUBLE PRECISION array, dimension (N)
43: * On entry, the diagonal elements of the tridiagonal matrix.
44: * On exit, if INFO = 0, the eigenvalues in ascending order.
45: *
46: * E (input/output) DOUBLE PRECISION array, dimension (N-1)
47: * On entry, the (n-1) subdiagonal elements of the tridiagonal
48: * matrix.
49: * On exit, E has been destroyed.
50: *
51: * Z (input/output) COMPLEX*16 array, dimension (LDZ, N)
52: * On entry, if COMPZ = 'V', then Z contains the unitary
53: * matrix used in the reduction to tridiagonal form.
54: * On exit, if INFO = 0, then if COMPZ = 'V', Z contains the
55: * orthonormal eigenvectors of the original Hermitian matrix,
56: * and if COMPZ = 'I', Z contains the orthonormal eigenvectors
57: * of the symmetric tridiagonal matrix.
58: * If COMPZ = 'N', then Z is not referenced.
59: *
60: * LDZ (input) INTEGER
61: * The leading dimension of the array Z. LDZ >= 1, and if
62: * eigenvectors are desired, then LDZ >= max(1,N).
63: *
64: * WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2))
65: * If COMPZ = 'N', then WORK is not referenced.
66: *
67: * INFO (output) INTEGER
68: * = 0: successful exit
69: * < 0: if INFO = -i, the i-th argument had an illegal value
70: * > 0: the algorithm has failed to find all the eigenvalues in
71: * a total of 30*N iterations; if INFO = i, then i
72: * elements of E have not converged to zero; on exit, D
73: * and E contain the elements of a symmetric tridiagonal
74: * matrix which is unitarily similar to the original
75: * matrix.
76: *
77: * =====================================================================
78: *
79: * .. Parameters ..
80: DOUBLE PRECISION ZERO, ONE, TWO, THREE
81: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0, TWO = 2.0D0,
82: $ THREE = 3.0D0 )
83: COMPLEX*16 CZERO, CONE
84: PARAMETER ( CZERO = ( 0.0D0, 0.0D0 ),
85: $ CONE = ( 1.0D0, 0.0D0 ) )
86: INTEGER MAXIT
87: PARAMETER ( MAXIT = 30 )
88: * ..
89: * .. Local Scalars ..
90: INTEGER I, ICOMPZ, II, ISCALE, J, JTOT, K, L, L1, LEND,
91: $ LENDM1, LENDP1, LENDSV, LM1, LSV, M, MM, MM1,
92: $ NM1, NMAXIT
93: DOUBLE PRECISION ANORM, B, C, EPS, EPS2, F, G, P, R, RT1, RT2,
94: $ S, SAFMAX, SAFMIN, SSFMAX, SSFMIN, TST
95: * ..
96: * .. External Functions ..
97: LOGICAL LSAME
98: DOUBLE PRECISION DLAMCH, DLANST, DLAPY2
99: EXTERNAL LSAME, DLAMCH, DLANST, DLAPY2
100: * ..
101: * .. External Subroutines ..
102: EXTERNAL DLAE2, DLAEV2, DLARTG, DLASCL, DLASRT, XERBLA,
103: $ ZLASET, ZLASR, ZSWAP
104: * ..
105: * .. Intrinsic Functions ..
106: INTRINSIC ABS, MAX, SIGN, SQRT
107: * ..
108: * .. Executable Statements ..
109: *
110: * Test the input parameters.
111: *
112: INFO = 0
113: *
114: IF( LSAME( COMPZ, 'N' ) ) THEN
115: ICOMPZ = 0
116: ELSE IF( LSAME( COMPZ, 'V' ) ) THEN
117: ICOMPZ = 1
118: ELSE IF( LSAME( COMPZ, 'I' ) ) THEN
119: ICOMPZ = 2
120: ELSE
121: ICOMPZ = -1
122: END IF
123: IF( ICOMPZ.LT.0 ) THEN
124: INFO = -1
125: ELSE IF( N.LT.0 ) THEN
126: INFO = -2
127: ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1,
128: $ N ) ) ) THEN
129: INFO = -6
130: END IF
131: IF( INFO.NE.0 ) THEN
132: CALL XERBLA( 'ZSTEQR', -INFO )
133: RETURN
134: END IF
135: *
136: * Quick return if possible
137: *
138: IF( N.EQ.0 )
139: $ RETURN
140: *
141: IF( N.EQ.1 ) THEN
142: IF( ICOMPZ.EQ.2 )
143: $ Z( 1, 1 ) = CONE
144: RETURN
145: END IF
146: *
147: * Determine the unit roundoff and over/underflow thresholds.
148: *
149: EPS = DLAMCH( 'E' )
150: EPS2 = EPS**2
151: SAFMIN = DLAMCH( 'S' )
152: SAFMAX = ONE / SAFMIN
153: SSFMAX = SQRT( SAFMAX ) / THREE
154: SSFMIN = SQRT( SAFMIN ) / EPS2
155: *
156: * Compute the eigenvalues and eigenvectors of the tridiagonal
157: * matrix.
158: *
159: IF( ICOMPZ.EQ.2 )
160: $ CALL ZLASET( 'Full', N, N, CZERO, CONE, Z, LDZ )
161: *
162: NMAXIT = N*MAXIT
163: JTOT = 0
164: *
165: * Determine where the matrix splits and choose QL or QR iteration
166: * for each block, according to whether top or bottom diagonal
167: * element is smaller.
168: *
169: L1 = 1
170: NM1 = N - 1
171: *
172: 10 CONTINUE
173: IF( L1.GT.N )
174: $ GO TO 160
175: IF( L1.GT.1 )
176: $ E( L1-1 ) = ZERO
177: IF( L1.LE.NM1 ) THEN
178: DO 20 M = L1, NM1
179: TST = ABS( E( M ) )
180: IF( TST.EQ.ZERO )
181: $ GO TO 30
182: IF( TST.LE.( SQRT( ABS( D( M ) ) )*SQRT( ABS( D( M+
183: $ 1 ) ) ) )*EPS ) THEN
184: E( M ) = ZERO
185: GO TO 30
186: END IF
187: 20 CONTINUE
188: END IF
189: M = N
190: *
191: 30 CONTINUE
192: L = L1
193: LSV = L
194: LEND = M
195: LENDSV = LEND
196: L1 = M + 1
197: IF( LEND.EQ.L )
198: $ GO TO 10
199: *
200: * Scale submatrix in rows and columns L to LEND
201: *
202: ANORM = DLANST( 'I', LEND-L+1, D( L ), E( L ) )
203: ISCALE = 0
204: IF( ANORM.EQ.ZERO )
205: $ GO TO 10
206: IF( ANORM.GT.SSFMAX ) THEN
207: ISCALE = 1
208: CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L+1, 1, D( L ), N,
209: $ INFO )
210: CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L, 1, E( L ), N,
211: $ INFO )
212: ELSE IF( ANORM.LT.SSFMIN ) THEN
213: ISCALE = 2
214: CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L+1, 1, D( L ), N,
215: $ INFO )
216: CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L, 1, E( L ), N,
217: $ INFO )
218: END IF
219: *
220: * Choose between QL and QR iteration
221: *
222: IF( ABS( D( LEND ) ).LT.ABS( D( L ) ) ) THEN
223: LEND = LSV
224: L = LENDSV
225: END IF
226: *
227: IF( LEND.GT.L ) THEN
228: *
229: * QL Iteration
230: *
231: * Look for small subdiagonal element.
232: *
233: 40 CONTINUE
234: IF( L.NE.LEND ) THEN
235: LENDM1 = LEND - 1
236: DO 50 M = L, LENDM1
237: TST = ABS( E( M ) )**2
238: IF( TST.LE.( EPS2*ABS( D( M ) ) )*ABS( D( M+1 ) )+
239: $ SAFMIN )GO TO 60
240: 50 CONTINUE
241: END IF
242: *
243: M = LEND
244: *
245: 60 CONTINUE
246: IF( M.LT.LEND )
247: $ E( M ) = ZERO
248: P = D( L )
249: IF( M.EQ.L )
250: $ GO TO 80
251: *
252: * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
253: * to compute its eigensystem.
254: *
255: IF( M.EQ.L+1 ) THEN
256: IF( ICOMPZ.GT.0 ) THEN
257: CALL DLAEV2( D( L ), E( L ), D( L+1 ), RT1, RT2, C, S )
258: WORK( L ) = C
259: WORK( N-1+L ) = S
260: CALL ZLASR( 'R', 'V', 'B', N, 2, WORK( L ),
261: $ WORK( N-1+L ), Z( 1, L ), LDZ )
262: ELSE
263: CALL DLAE2( D( L ), E( L ), D( L+1 ), RT1, RT2 )
264: END IF
265: D( L ) = RT1
266: D( L+1 ) = RT2
267: E( L ) = ZERO
268: L = L + 2
269: IF( L.LE.LEND )
270: $ GO TO 40
271: GO TO 140
272: END IF
273: *
274: IF( JTOT.EQ.NMAXIT )
275: $ GO TO 140
276: JTOT = JTOT + 1
277: *
278: * Form shift.
279: *
280: G = ( D( L+1 )-P ) / ( TWO*E( L ) )
281: R = DLAPY2( G, ONE )
282: G = D( M ) - P + ( E( L ) / ( G+SIGN( R, G ) ) )
283: *
284: S = ONE
285: C = ONE
286: P = ZERO
287: *
288: * Inner loop
289: *
290: MM1 = M - 1
291: DO 70 I = MM1, L, -1
292: F = S*E( I )
293: B = C*E( I )
294: CALL DLARTG( G, F, C, S, R )
295: IF( I.NE.M-1 )
296: $ E( I+1 ) = R
297: G = D( I+1 ) - P
298: R = ( D( I )-G )*S + TWO*C*B
299: P = S*R
300: D( I+1 ) = G + P
301: G = C*R - B
302: *
303: * If eigenvectors are desired, then save rotations.
304: *
305: IF( ICOMPZ.GT.0 ) THEN
306: WORK( I ) = C
307: WORK( N-1+I ) = -S
308: END IF
309: *
310: 70 CONTINUE
311: *
312: * If eigenvectors are desired, then apply saved rotations.
313: *
314: IF( ICOMPZ.GT.0 ) THEN
315: MM = M - L + 1
316: CALL ZLASR( 'R', 'V', 'B', N, MM, WORK( L ), WORK( N-1+L ),
317: $ Z( 1, L ), LDZ )
318: END IF
319: *
320: D( L ) = D( L ) - P
321: E( L ) = G
322: GO TO 40
323: *
324: * Eigenvalue found.
325: *
326: 80 CONTINUE
327: D( L ) = P
328: *
329: L = L + 1
330: IF( L.LE.LEND )
331: $ GO TO 40
332: GO TO 140
333: *
334: ELSE
335: *
336: * QR Iteration
337: *
338: * Look for small superdiagonal element.
339: *
340: 90 CONTINUE
341: IF( L.NE.LEND ) THEN
342: LENDP1 = LEND + 1
343: DO 100 M = L, LENDP1, -1
344: TST = ABS( E( M-1 ) )**2
345: IF( TST.LE.( EPS2*ABS( D( M ) ) )*ABS( D( M-1 ) )+
346: $ SAFMIN )GO TO 110
347: 100 CONTINUE
348: END IF
349: *
350: M = LEND
351: *
352: 110 CONTINUE
353: IF( M.GT.LEND )
354: $ E( M-1 ) = ZERO
355: P = D( L )
356: IF( M.EQ.L )
357: $ GO TO 130
358: *
359: * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
360: * to compute its eigensystem.
361: *
362: IF( M.EQ.L-1 ) THEN
363: IF( ICOMPZ.GT.0 ) THEN
364: CALL DLAEV2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2, C, S )
365: WORK( M ) = C
366: WORK( N-1+M ) = S
367: CALL ZLASR( 'R', 'V', 'F', N, 2, WORK( M ),
368: $ WORK( N-1+M ), Z( 1, L-1 ), LDZ )
369: ELSE
370: CALL DLAE2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2 )
371: END IF
372: D( L-1 ) = RT1
373: D( L ) = RT2
374: E( L-1 ) = ZERO
375: L = L - 2
376: IF( L.GE.LEND )
377: $ GO TO 90
378: GO TO 140
379: END IF
380: *
381: IF( JTOT.EQ.NMAXIT )
382: $ GO TO 140
383: JTOT = JTOT + 1
384: *
385: * Form shift.
386: *
387: G = ( D( L-1 )-P ) / ( TWO*E( L-1 ) )
388: R = DLAPY2( G, ONE )
389: G = D( M ) - P + ( E( L-1 ) / ( G+SIGN( R, G ) ) )
390: *
391: S = ONE
392: C = ONE
393: P = ZERO
394: *
395: * Inner loop
396: *
397: LM1 = L - 1
398: DO 120 I = M, LM1
399: F = S*E( I )
400: B = C*E( I )
401: CALL DLARTG( G, F, C, S, R )
402: IF( I.NE.M )
403: $ E( I-1 ) = R
404: G = D( I ) - P
405: R = ( D( I+1 )-G )*S + TWO*C*B
406: P = S*R
407: D( I ) = G + P
408: G = C*R - B
409: *
410: * If eigenvectors are desired, then save rotations.
411: *
412: IF( ICOMPZ.GT.0 ) THEN
413: WORK( I ) = C
414: WORK( N-1+I ) = S
415: END IF
416: *
417: 120 CONTINUE
418: *
419: * If eigenvectors are desired, then apply saved rotations.
420: *
421: IF( ICOMPZ.GT.0 ) THEN
422: MM = L - M + 1
423: CALL ZLASR( 'R', 'V', 'F', N, MM, WORK( M ), WORK( N-1+M ),
424: $ Z( 1, M ), LDZ )
425: END IF
426: *
427: D( L ) = D( L ) - P
428: E( LM1 ) = G
429: GO TO 90
430: *
431: * Eigenvalue found.
432: *
433: 130 CONTINUE
434: D( L ) = P
435: *
436: L = L - 1
437: IF( L.GE.LEND )
438: $ GO TO 90
439: GO TO 140
440: *
441: END IF
442: *
443: * Undo scaling if necessary
444: *
445: 140 CONTINUE
446: IF( ISCALE.EQ.1 ) THEN
447: CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV+1, 1,
448: $ D( LSV ), N, INFO )
449: CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV, 1, E( LSV ),
450: $ N, INFO )
451: ELSE IF( ISCALE.EQ.2 ) THEN
452: CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV+1, 1,
453: $ D( LSV ), N, INFO )
454: CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV, 1, E( LSV ),
455: $ N, INFO )
456: END IF
457: *
458: * Check for no convergence to an eigenvalue after a total
459: * of N*MAXIT iterations.
460: *
461: IF( JTOT.EQ.NMAXIT ) THEN
462: DO 150 I = 1, N - 1
463: IF( E( I ).NE.ZERO )
464: $ INFO = INFO + 1
465: 150 CONTINUE
466: RETURN
467: END IF
468: GO TO 10
469: *
470: * Order eigenvalues and eigenvectors.
471: *
472: 160 CONTINUE
473: IF( ICOMPZ.EQ.0 ) THEN
474: *
475: * Use Quick Sort
476: *
477: CALL DLASRT( 'I', N, D, INFO )
478: *
479: ELSE
480: *
481: * Use Selection Sort to minimize swaps of eigenvectors
482: *
483: DO 180 II = 2, N
484: I = II - 1
485: K = I
486: P = D( I )
487: DO 170 J = II, N
488: IF( D( J ).LT.P ) THEN
489: K = J
490: P = D( J )
491: END IF
492: 170 CONTINUE
493: IF( K.NE.I ) THEN
494: D( K ) = D( I )
495: D( I ) = P
496: CALL ZSWAP( N, Z( 1, I ), 1, Z( 1, K ), 1 )
497: END IF
498: 180 CONTINUE
499: END IF
500: RETURN
501: *
502: * End of ZSTEQR
503: *
504: END
CVSweb interface <joel.bertrand@systella.fr>