1: SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR,
2: $ LDVR, WORK, LWORK, INFO )
3: *
4: * -- LAPACK driver routine (version 3.2) --
5: * -- LAPACK is a software package provided by Univ. of Tennessee, --
6: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
7: * November 2006
8: *
9: * .. Scalar Arguments ..
10: CHARACTER JOBVL, JOBVR
11: INTEGER INFO, LDA, LDVL, LDVR, LWORK, N
12: * ..
13: * .. Array Arguments ..
14: DOUBLE PRECISION A( LDA, * ), VL( LDVL, * ), VR( LDVR, * ),
15: $ WI( * ), WORK( * ), WR( * )
16: * ..
17: *
18: * Purpose
19: * =======
20: *
21: * DGEEV computes for an N-by-N real nonsymmetric matrix A, the
22: * eigenvalues and, optionally, the left and/or right eigenvectors.
23: *
24: * The right eigenvector v(j) of A satisfies
25: * A * v(j) = lambda(j) * v(j)
26: * where lambda(j) is its eigenvalue.
27: * The left eigenvector u(j) of A satisfies
28: * u(j)**H * A = lambda(j) * u(j)**H
29: * where u(j)**H denotes the conjugate transpose of u(j).
30: *
31: * The computed eigenvectors are normalized to have Euclidean norm
32: * equal to 1 and largest component real.
33: *
34: * Arguments
35: * =========
36: *
37: * JOBVL (input) CHARACTER*1
38: * = 'N': left eigenvectors of A are not computed;
39: * = 'V': left eigenvectors of A are computed.
40: *
41: * JOBVR (input) CHARACTER*1
42: * = 'N': right eigenvectors of A are not computed;
43: * = 'V': right eigenvectors of A are computed.
44: *
45: * N (input) INTEGER
46: * The order of the matrix A. N >= 0.
47: *
48: * A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
49: * On entry, the N-by-N matrix A.
50: * On exit, A has been overwritten.
51: *
52: * LDA (input) INTEGER
53: * The leading dimension of the array A. LDA >= max(1,N).
54: *
55: * WR (output) DOUBLE PRECISION array, dimension (N)
56: * WI (output) DOUBLE PRECISION array, dimension (N)
57: * WR and WI contain the real and imaginary parts,
58: * respectively, of the computed eigenvalues. Complex
59: * conjugate pairs of eigenvalues appear consecutively
60: * with the eigenvalue having the positive imaginary part
61: * first.
62: *
63: * VL (output) DOUBLE PRECISION array, dimension (LDVL,N)
64: * If JOBVL = 'V', the left eigenvectors u(j) are stored one
65: * after another in the columns of VL, in the same order
66: * as their eigenvalues.
67: * If JOBVL = 'N', VL is not referenced.
68: * If the j-th eigenvalue is real, then u(j) = VL(:,j),
69: * the j-th column of VL.
70: * If the j-th and (j+1)-st eigenvalues form a complex
71: * conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and
72: * u(j+1) = VL(:,j) - i*VL(:,j+1).
73: *
74: * LDVL (input) INTEGER
75: * The leading dimension of the array VL. LDVL >= 1; if
76: * JOBVL = 'V', LDVL >= N.
77: *
78: * VR (output) DOUBLE PRECISION array, dimension (LDVR,N)
79: * If JOBVR = 'V', the right eigenvectors v(j) are stored one
80: * after another in the columns of VR, in the same order
81: * as their eigenvalues.
82: * If JOBVR = 'N', VR is not referenced.
83: * If the j-th eigenvalue is real, then v(j) = VR(:,j),
84: * the j-th column of VR.
85: * If the j-th and (j+1)-st eigenvalues form a complex
86: * conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and
87: * v(j+1) = VR(:,j) - i*VR(:,j+1).
88: *
89: * LDVR (input) INTEGER
90: * The leading dimension of the array VR. LDVR >= 1; if
91: * JOBVR = 'V', LDVR >= N.
92: *
93: * WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
94: * On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
95: *
96: * LWORK (input) INTEGER
97: * The dimension of the array WORK. LWORK >= max(1,3*N), and
98: * if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N. For good
99: * performance, LWORK must generally be larger.
100: *
101: * If LWORK = -1, then a workspace query is assumed; the routine
102: * only calculates the optimal size of the WORK array, returns
103: * this value as the first entry of the WORK array, and no error
104: * message related to LWORK is issued by XERBLA.
105: *
106: * INFO (output) INTEGER
107: * = 0: successful exit
108: * < 0: if INFO = -i, the i-th argument had an illegal value.
109: * > 0: if INFO = i, the QR algorithm failed to compute all the
110: * eigenvalues, and no eigenvectors have been computed;
111: * elements i+1:N of WR and WI contain eigenvalues which
112: * have converged.
113: *
114: * =====================================================================
115: *
116: * .. Parameters ..
117: DOUBLE PRECISION ZERO, ONE
118: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
119: * ..
120: * .. Local Scalars ..
121: LOGICAL LQUERY, SCALEA, WANTVL, WANTVR
122: CHARACTER SIDE
123: INTEGER HSWORK, I, IBAL, IERR, IHI, ILO, ITAU, IWRK, K,
124: $ MAXWRK, MINWRK, NOUT
125: DOUBLE PRECISION ANRM, BIGNUM, CS, CSCALE, EPS, R, SCL, SMLNUM,
126: $ SN
127: * ..
128: * .. Local Arrays ..
129: LOGICAL SELECT( 1 )
130: DOUBLE PRECISION DUM( 1 )
131: * ..
132: * .. External Subroutines ..
133: EXTERNAL DGEBAK, DGEBAL, DGEHRD, DHSEQR, DLABAD, DLACPY,
134: $ DLARTG, DLASCL, DORGHR, DROT, DSCAL, DTREVC,
135: $ XERBLA
136: * ..
137: * .. External Functions ..
138: LOGICAL LSAME
139: INTEGER IDAMAX, ILAENV
140: DOUBLE PRECISION DLAMCH, DLANGE, DLAPY2, DNRM2
141: EXTERNAL LSAME, IDAMAX, ILAENV, DLAMCH, DLANGE, DLAPY2,
142: $ DNRM2
143: * ..
144: * .. Intrinsic Functions ..
145: INTRINSIC MAX, SQRT
146: * ..
147: * .. Executable Statements ..
148: *
149: * Test the input arguments
150: *
151: INFO = 0
152: LQUERY = ( LWORK.EQ.-1 )
153: WANTVL = LSAME( JOBVL, 'V' )
154: WANTVR = LSAME( JOBVR, 'V' )
155: IF( ( .NOT.WANTVL ) .AND. ( .NOT.LSAME( JOBVL, 'N' ) ) ) THEN
156: INFO = -1
157: ELSE IF( ( .NOT.WANTVR ) .AND. ( .NOT.LSAME( JOBVR, 'N' ) ) ) THEN
158: INFO = -2
159: ELSE IF( N.LT.0 ) THEN
160: INFO = -3
161: ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
162: INFO = -5
163: ELSE IF( LDVL.LT.1 .OR. ( WANTVL .AND. LDVL.LT.N ) ) THEN
164: INFO = -9
165: ELSE IF( LDVR.LT.1 .OR. ( WANTVR .AND. LDVR.LT.N ) ) THEN
166: INFO = -11
167: END IF
168: *
169: * Compute workspace
170: * (Note: Comments in the code beginning "Workspace:" describe the
171: * minimal amount of workspace needed at that point in the code,
172: * as well as the preferred amount for good performance.
173: * NB refers to the optimal block size for the immediately
174: * following subroutine, as returned by ILAENV.
175: * HSWORK refers to the workspace preferred by DHSEQR, as
176: * calculated below. HSWORK is computed assuming ILO=1 and IHI=N,
177: * the worst case.)
178: *
179: IF( INFO.EQ.0 ) THEN
180: IF( N.EQ.0 ) THEN
181: MINWRK = 1
182: MAXWRK = 1
183: ELSE
184: MAXWRK = 2*N + N*ILAENV( 1, 'DGEHRD', ' ', N, 1, N, 0 )
185: IF( WANTVL ) THEN
186: MINWRK = 4*N
187: MAXWRK = MAX( MAXWRK, 2*N + ( N - 1 )*ILAENV( 1,
188: $ 'DORGHR', ' ', N, 1, N, -1 ) )
189: CALL DHSEQR( 'S', 'V', N, 1, N, A, LDA, WR, WI, VL, LDVL,
190: $ WORK, -1, INFO )
191: HSWORK = WORK( 1 )
192: MAXWRK = MAX( MAXWRK, N + 1, N + HSWORK )
193: MAXWRK = MAX( MAXWRK, 4*N )
194: ELSE IF( WANTVR ) THEN
195: MINWRK = 4*N
196: MAXWRK = MAX( MAXWRK, 2*N + ( N - 1 )*ILAENV( 1,
197: $ 'DORGHR', ' ', N, 1, N, -1 ) )
198: CALL DHSEQR( 'S', 'V', N, 1, N, A, LDA, WR, WI, VR, LDVR,
199: $ WORK, -1, INFO )
200: HSWORK = WORK( 1 )
201: MAXWRK = MAX( MAXWRK, N + 1, N + HSWORK )
202: MAXWRK = MAX( MAXWRK, 4*N )
203: ELSE
204: MINWRK = 3*N
205: CALL DHSEQR( 'E', 'N', N, 1, N, A, LDA, WR, WI, VR, LDVR,
206: $ WORK, -1, INFO )
207: HSWORK = WORK( 1 )
208: MAXWRK = MAX( MAXWRK, N + 1, N + HSWORK )
209: END IF
210: MAXWRK = MAX( MAXWRK, MINWRK )
211: END IF
212: WORK( 1 ) = MAXWRK
213: *
214: IF( LWORK.LT.MINWRK .AND. .NOT.LQUERY ) THEN
215: INFO = -13
216: END IF
217: END IF
218: *
219: IF( INFO.NE.0 ) THEN
220: CALL XERBLA( 'DGEEV ', -INFO )
221: RETURN
222: ELSE IF( LQUERY ) THEN
223: RETURN
224: END IF
225: *
226: * Quick return if possible
227: *
228: IF( N.EQ.0 )
229: $ RETURN
230: *
231: * Get machine constants
232: *
233: EPS = DLAMCH( 'P' )
234: SMLNUM = DLAMCH( 'S' )
235: BIGNUM = ONE / SMLNUM
236: CALL DLABAD( SMLNUM, BIGNUM )
237: SMLNUM = SQRT( SMLNUM ) / EPS
238: BIGNUM = ONE / SMLNUM
239: *
240: * Scale A if max element outside range [SMLNUM,BIGNUM]
241: *
242: ANRM = DLANGE( 'M', N, N, A, LDA, DUM )
243: SCALEA = .FALSE.
244: IF( ANRM.GT.ZERO .AND. ANRM.LT.SMLNUM ) THEN
245: SCALEA = .TRUE.
246: CSCALE = SMLNUM
247: ELSE IF( ANRM.GT.BIGNUM ) THEN
248: SCALEA = .TRUE.
249: CSCALE = BIGNUM
250: END IF
251: IF( SCALEA )
252: $ CALL DLASCL( 'G', 0, 0, ANRM, CSCALE, N, N, A, LDA, IERR )
253: *
254: * Balance the matrix
255: * (Workspace: need N)
256: *
257: IBAL = 1
258: CALL DGEBAL( 'B', N, A, LDA, ILO, IHI, WORK( IBAL ), IERR )
259: *
260: * Reduce to upper Hessenberg form
261: * (Workspace: need 3*N, prefer 2*N+N*NB)
262: *
263: ITAU = IBAL + N
264: IWRK = ITAU + N
265: CALL DGEHRD( N, ILO, IHI, A, LDA, WORK( ITAU ), WORK( IWRK ),
266: $ LWORK-IWRK+1, IERR )
267: *
268: IF( WANTVL ) THEN
269: *
270: * Want left eigenvectors
271: * Copy Householder vectors to VL
272: *
273: SIDE = 'L'
274: CALL DLACPY( 'L', N, N, A, LDA, VL, LDVL )
275: *
276: * Generate orthogonal matrix in VL
277: * (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB)
278: *
279: CALL DORGHR( N, ILO, IHI, VL, LDVL, WORK( ITAU ), WORK( IWRK ),
280: $ LWORK-IWRK+1, IERR )
281: *
282: * Perform QR iteration, accumulating Schur vectors in VL
283: * (Workspace: need N+1, prefer N+HSWORK (see comments) )
284: *
285: IWRK = ITAU
286: CALL DHSEQR( 'S', 'V', N, ILO, IHI, A, LDA, WR, WI, VL, LDVL,
287: $ WORK( IWRK ), LWORK-IWRK+1, INFO )
288: *
289: IF( WANTVR ) THEN
290: *
291: * Want left and right eigenvectors
292: * Copy Schur vectors to VR
293: *
294: SIDE = 'B'
295: CALL DLACPY( 'F', N, N, VL, LDVL, VR, LDVR )
296: END IF
297: *
298: ELSE IF( WANTVR ) THEN
299: *
300: * Want right eigenvectors
301: * Copy Householder vectors to VR
302: *
303: SIDE = 'R'
304: CALL DLACPY( 'L', N, N, A, LDA, VR, LDVR )
305: *
306: * Generate orthogonal matrix in VR
307: * (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB)
308: *
309: CALL DORGHR( N, ILO, IHI, VR, LDVR, WORK( ITAU ), WORK( IWRK ),
310: $ LWORK-IWRK+1, IERR )
311: *
312: * Perform QR iteration, accumulating Schur vectors in VR
313: * (Workspace: need N+1, prefer N+HSWORK (see comments) )
314: *
315: IWRK = ITAU
316: CALL DHSEQR( 'S', 'V', N, ILO, IHI, A, LDA, WR, WI, VR, LDVR,
317: $ WORK( IWRK ), LWORK-IWRK+1, INFO )
318: *
319: ELSE
320: *
321: * Compute eigenvalues only
322: * (Workspace: need N+1, prefer N+HSWORK (see comments) )
323: *
324: IWRK = ITAU
325: CALL DHSEQR( 'E', 'N', N, ILO, IHI, A, LDA, WR, WI, VR, LDVR,
326: $ WORK( IWRK ), LWORK-IWRK+1, INFO )
327: END IF
328: *
329: * If INFO > 0 from DHSEQR, then quit
330: *
331: IF( INFO.GT.0 )
332: $ GO TO 50
333: *
334: IF( WANTVL .OR. WANTVR ) THEN
335: *
336: * Compute left and/or right eigenvectors
337: * (Workspace: need 4*N)
338: *
339: CALL DTREVC( SIDE, 'B', SELECT, N, A, LDA, VL, LDVL, VR, LDVR,
340: $ N, NOUT, WORK( IWRK ), IERR )
341: END IF
342: *
343: IF( WANTVL ) THEN
344: *
345: * Undo balancing of left eigenvectors
346: * (Workspace: need N)
347: *
348: CALL DGEBAK( 'B', 'L', N, ILO, IHI, WORK( IBAL ), N, VL, LDVL,
349: $ IERR )
350: *
351: * Normalize left eigenvectors and make largest component real
352: *
353: DO 20 I = 1, N
354: IF( WI( I ).EQ.ZERO ) THEN
355: SCL = ONE / DNRM2( N, VL( 1, I ), 1 )
356: CALL DSCAL( N, SCL, VL( 1, I ), 1 )
357: ELSE IF( WI( I ).GT.ZERO ) THEN
358: SCL = ONE / DLAPY2( DNRM2( N, VL( 1, I ), 1 ),
359: $ DNRM2( N, VL( 1, I+1 ), 1 ) )
360: CALL DSCAL( N, SCL, VL( 1, I ), 1 )
361: CALL DSCAL( N, SCL, VL( 1, I+1 ), 1 )
362: DO 10 K = 1, N
363: WORK( IWRK+K-1 ) = VL( K, I )**2 + VL( K, I+1 )**2
364: 10 CONTINUE
365: K = IDAMAX( N, WORK( IWRK ), 1 )
366: CALL DLARTG( VL( K, I ), VL( K, I+1 ), CS, SN, R )
367: CALL DROT( N, VL( 1, I ), 1, VL( 1, I+1 ), 1, CS, SN )
368: VL( K, I+1 ) = ZERO
369: END IF
370: 20 CONTINUE
371: END IF
372: *
373: IF( WANTVR ) THEN
374: *
375: * Undo balancing of right eigenvectors
376: * (Workspace: need N)
377: *
378: CALL DGEBAK( 'B', 'R', N, ILO, IHI, WORK( IBAL ), N, VR, LDVR,
379: $ IERR )
380: *
381: * Normalize right eigenvectors and make largest component real
382: *
383: DO 40 I = 1, N
384: IF( WI( I ).EQ.ZERO ) THEN
385: SCL = ONE / DNRM2( N, VR( 1, I ), 1 )
386: CALL DSCAL( N, SCL, VR( 1, I ), 1 )
387: ELSE IF( WI( I ).GT.ZERO ) THEN
388: SCL = ONE / DLAPY2( DNRM2( N, VR( 1, I ), 1 ),
389: $ DNRM2( N, VR( 1, I+1 ), 1 ) )
390: CALL DSCAL( N, SCL, VR( 1, I ), 1 )
391: CALL DSCAL( N, SCL, VR( 1, I+1 ), 1 )
392: DO 30 K = 1, N
393: WORK( IWRK+K-1 ) = VR( K, I )**2 + VR( K, I+1 )**2
394: 30 CONTINUE
395: K = IDAMAX( N, WORK( IWRK ), 1 )
396: CALL DLARTG( VR( K, I ), VR( K, I+1 ), CS, SN, R )
397: CALL DROT( N, VR( 1, I ), 1, VR( 1, I+1 ), 1, CS, SN )
398: VR( K, I+1 ) = ZERO
399: END IF
400: 40 CONTINUE
401: END IF
402: *
403: * Undo scaling if necessary
404: *
405: 50 CONTINUE
406: IF( SCALEA ) THEN
407: CALL DLASCL( 'G', 0, 0, CSCALE, ANRM, N-INFO, 1, WR( INFO+1 ),
408: $ MAX( N-INFO, 1 ), IERR )
409: CALL DLASCL( 'G', 0, 0, CSCALE, ANRM, N-INFO, 1, WI( INFO+1 ),
410: $ MAX( N-INFO, 1 ), IERR )
411: IF( INFO.GT.0 ) THEN
412: CALL DLASCL( 'G', 0, 0, CSCALE, ANRM, ILO-1, 1, WR, N,
413: $ IERR )
414: CALL DLASCL( 'G', 0, 0, CSCALE, ANRM, ILO-1, 1, WI, N,
415: $ IERR )
416: END IF
417: END IF
418: *
419: WORK( 1 ) = MAXWRK
420: RETURN
421: *
422: * End of DGEEV
423: *
424: END
CVSweb interface <joel.bertrand@systella.fr>