1: SUBROUTINE DTGEVC( SIDE, HOWMNY, SELECT, N, S, LDS, P, LDP, VL,
2: $ LDVL, VR, LDVR, MM, M, WORK, INFO )
3: *
4: * -- LAPACK 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 HOWMNY, SIDE
11: INTEGER INFO, LDP, LDS, LDVL, LDVR, M, MM, N
12: * ..
13: * .. Array Arguments ..
14: LOGICAL SELECT( * )
15: DOUBLE PRECISION P( LDP, * ), S( LDS, * ), VL( LDVL, * ),
16: $ VR( LDVR, * ), WORK( * )
17: * ..
18: *
19: *
20: * Purpose
21: * =======
22: *
23: * DTGEVC computes some or all of the right and/or left eigenvectors of
24: * a pair of real matrices (S,P), where S is a quasi-triangular matrix
25: * and P is upper triangular. Matrix pairs of this type are produced by
26: * the generalized Schur factorization of a matrix pair (A,B):
27: *
28: * A = Q*S*Z**T, B = Q*P*Z**T
29: *
30: * as computed by DGGHRD + DHGEQZ.
31: *
32: * The right eigenvector x and the left eigenvector y of (S,P)
33: * corresponding to an eigenvalue w are defined by:
34: *
35: * S*x = w*P*x, (y**H)*S = w*(y**H)*P,
36: *
37: * where y**H denotes the conjugate tranpose of y.
38: * The eigenvalues are not input to this routine, but are computed
39: * directly from the diagonal blocks of S and P.
40: *
41: * This routine returns the matrices X and/or Y of right and left
42: * eigenvectors of (S,P), or the products Z*X and/or Q*Y,
43: * where Z and Q are input matrices.
44: * If Q and Z are the orthogonal factors from the generalized Schur
45: * factorization of a matrix pair (A,B), then Z*X and Q*Y
46: * are the matrices of right and left eigenvectors of (A,B).
47: *
48: * Arguments
49: * =========
50: *
51: * SIDE (input) CHARACTER*1
52: * = 'R': compute right eigenvectors only;
53: * = 'L': compute left eigenvectors only;
54: * = 'B': compute both right and left eigenvectors.
55: *
56: * HOWMNY (input) CHARACTER*1
57: * = 'A': compute all right and/or left eigenvectors;
58: * = 'B': compute all right and/or left eigenvectors,
59: * backtransformed by the matrices in VR and/or VL;
60: * = 'S': compute selected right and/or left eigenvectors,
61: * specified by the logical array SELECT.
62: *
63: * SELECT (input) LOGICAL array, dimension (N)
64: * If HOWMNY='S', SELECT specifies the eigenvectors to be
65: * computed. If w(j) is a real eigenvalue, the corresponding
66: * real eigenvector is computed if SELECT(j) is .TRUE..
67: * If w(j) and w(j+1) are the real and imaginary parts of a
68: * complex eigenvalue, the corresponding complex eigenvector
69: * is computed if either SELECT(j) or SELECT(j+1) is .TRUE.,
70: * and on exit SELECT(j) is set to .TRUE. and SELECT(j+1) is
71: * set to .FALSE..
72: * Not referenced if HOWMNY = 'A' or 'B'.
73: *
74: * N (input) INTEGER
75: * The order of the matrices S and P. N >= 0.
76: *
77: * S (input) DOUBLE PRECISION array, dimension (LDS,N)
78: * The upper quasi-triangular matrix S from a generalized Schur
79: * factorization, as computed by DHGEQZ.
80: *
81: * LDS (input) INTEGER
82: * The leading dimension of array S. LDS >= max(1,N).
83: *
84: * P (input) DOUBLE PRECISION array, dimension (LDP,N)
85: * The upper triangular matrix P from a generalized Schur
86: * factorization, as computed by DHGEQZ.
87: * 2-by-2 diagonal blocks of P corresponding to 2-by-2 blocks
88: * of S must be in positive diagonal form.
89: *
90: * LDP (input) INTEGER
91: * The leading dimension of array P. LDP >= max(1,N).
92: *
93: * VL (input/output) DOUBLE PRECISION array, dimension (LDVL,MM)
94: * On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must
95: * contain an N-by-N matrix Q (usually the orthogonal matrix Q
96: * of left Schur vectors returned by DHGEQZ).
97: * On exit, if SIDE = 'L' or 'B', VL contains:
98: * if HOWMNY = 'A', the matrix Y of left eigenvectors of (S,P);
99: * if HOWMNY = 'B', the matrix Q*Y;
100: * if HOWMNY = 'S', the left eigenvectors of (S,P) specified by
101: * SELECT, stored consecutively in the columns of
102: * VL, in the same order as their eigenvalues.
103: *
104: * A complex eigenvector corresponding to a complex eigenvalue
105: * is stored in two consecutive columns, the first holding the
106: * real part, and the second the imaginary part.
107: *
108: * Not referenced if SIDE = 'R'.
109: *
110: * LDVL (input) INTEGER
111: * The leading dimension of array VL. LDVL >= 1, and if
112: * SIDE = 'L' or 'B', LDVL >= N.
113: *
114: * VR (input/output) DOUBLE PRECISION array, dimension (LDVR,MM)
115: * On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must
116: * contain an N-by-N matrix Z (usually the orthogonal matrix Z
117: * of right Schur vectors returned by DHGEQZ).
118: *
119: * On exit, if SIDE = 'R' or 'B', VR contains:
120: * if HOWMNY = 'A', the matrix X of right eigenvectors of (S,P);
121: * if HOWMNY = 'B' or 'b', the matrix Z*X;
122: * if HOWMNY = 'S' or 's', the right eigenvectors of (S,P)
123: * specified by SELECT, stored consecutively in the
124: * columns of VR, in the same order as their
125: * eigenvalues.
126: *
127: * A complex eigenvector corresponding to a complex eigenvalue
128: * is stored in two consecutive columns, the first holding the
129: * real part and the second the imaginary part.
130: *
131: * Not referenced if SIDE = 'L'.
132: *
133: * LDVR (input) INTEGER
134: * The leading dimension of the array VR. LDVR >= 1, and if
135: * SIDE = 'R' or 'B', LDVR >= N.
136: *
137: * MM (input) INTEGER
138: * The number of columns in the arrays VL and/or VR. MM >= M.
139: *
140: * M (output) INTEGER
141: * The number of columns in the arrays VL and/or VR actually
142: * used to store the eigenvectors. If HOWMNY = 'A' or 'B', M
143: * is set to N. Each selected real eigenvector occupies one
144: * column and each selected complex eigenvector occupies two
145: * columns.
146: *
147: * WORK (workspace) DOUBLE PRECISION array, dimension (6*N)
148: *
149: * INFO (output) INTEGER
150: * = 0: successful exit.
151: * < 0: if INFO = -i, the i-th argument had an illegal value.
152: * > 0: the 2-by-2 block (INFO:INFO+1) does not have a complex
153: * eigenvalue.
154: *
155: * Further Details
156: * ===============
157: *
158: * Allocation of workspace:
159: * ---------- -- ---------
160: *
161: * WORK( j ) = 1-norm of j-th column of A, above the diagonal
162: * WORK( N+j ) = 1-norm of j-th column of B, above the diagonal
163: * WORK( 2*N+1:3*N ) = real part of eigenvector
164: * WORK( 3*N+1:4*N ) = imaginary part of eigenvector
165: * WORK( 4*N+1:5*N ) = real part of back-transformed eigenvector
166: * WORK( 5*N+1:6*N ) = imaginary part of back-transformed eigenvector
167: *
168: * Rowwise vs. columnwise solution methods:
169: * ------- -- ---------- -------- -------
170: *
171: * Finding a generalized eigenvector consists basically of solving the
172: * singular triangular system
173: *
174: * (A - w B) x = 0 (for right) or: (A - w B)**H y = 0 (for left)
175: *
176: * Consider finding the i-th right eigenvector (assume all eigenvalues
177: * are real). The equation to be solved is:
178: * n i
179: * 0 = sum C(j,k) v(k) = sum C(j,k) v(k) for j = i,. . .,1
180: * k=j k=j
181: *
182: * where C = (A - w B) (The components v(i+1:n) are 0.)
183: *
184: * The "rowwise" method is:
185: *
186: * (1) v(i) := 1
187: * for j = i-1,. . .,1:
188: * i
189: * (2) compute s = - sum C(j,k) v(k) and
190: * k=j+1
191: *
192: * (3) v(j) := s / C(j,j)
193: *
194: * Step 2 is sometimes called the "dot product" step, since it is an
195: * inner product between the j-th row and the portion of the eigenvector
196: * that has been computed so far.
197: *
198: * The "columnwise" method consists basically in doing the sums
199: * for all the rows in parallel. As each v(j) is computed, the
200: * contribution of v(j) times the j-th column of C is added to the
201: * partial sums. Since FORTRAN arrays are stored columnwise, this has
202: * the advantage that at each step, the elements of C that are accessed
203: * are adjacent to one another, whereas with the rowwise method, the
204: * elements accessed at a step are spaced LDS (and LDP) words apart.
205: *
206: * When finding left eigenvectors, the matrix in question is the
207: * transpose of the one in storage, so the rowwise method then
208: * actually accesses columns of A and B at each step, and so is the
209: * preferred method.
210: *
211: * =====================================================================
212: *
213: * .. Parameters ..
214: DOUBLE PRECISION ZERO, ONE, SAFETY
215: PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0,
216: $ SAFETY = 1.0D+2 )
217: * ..
218: * .. Local Scalars ..
219: LOGICAL COMPL, COMPR, IL2BY2, ILABAD, ILALL, ILBACK,
220: $ ILBBAD, ILCOMP, ILCPLX, LSA, LSB
221: INTEGER I, IBEG, IEIG, IEND, IHWMNY, IINFO, IM, ISIDE,
222: $ J, JA, JC, JE, JR, JW, NA, NW
223: DOUBLE PRECISION ACOEF, ACOEFA, ANORM, ASCALE, BCOEFA, BCOEFI,
224: $ BCOEFR, BIG, BIGNUM, BNORM, BSCALE, CIM2A,
225: $ CIM2B, CIMAGA, CIMAGB, CRE2A, CRE2B, CREALA,
226: $ CREALB, DMIN, SAFMIN, SALFAR, SBETA, SCALE,
227: $ SMALL, TEMP, TEMP2, TEMP2I, TEMP2R, ULP, XMAX,
228: $ XSCALE
229: * ..
230: * .. Local Arrays ..
231: DOUBLE PRECISION BDIAG( 2 ), SUM( 2, 2 ), SUMS( 2, 2 ),
232: $ SUMP( 2, 2 )
233: * ..
234: * .. External Functions ..
235: LOGICAL LSAME
236: DOUBLE PRECISION DLAMCH
237: EXTERNAL LSAME, DLAMCH
238: * ..
239: * .. External Subroutines ..
240: EXTERNAL DGEMV, DLABAD, DLACPY, DLAG2, DLALN2, XERBLA
241: * ..
242: * .. Intrinsic Functions ..
243: INTRINSIC ABS, MAX, MIN
244: * ..
245: * .. Executable Statements ..
246: *
247: * Decode and Test the input parameters
248: *
249: IF( LSAME( HOWMNY, 'A' ) ) THEN
250: IHWMNY = 1
251: ILALL = .TRUE.
252: ILBACK = .FALSE.
253: ELSE IF( LSAME( HOWMNY, 'S' ) ) THEN
254: IHWMNY = 2
255: ILALL = .FALSE.
256: ILBACK = .FALSE.
257: ELSE IF( LSAME( HOWMNY, 'B' ) ) THEN
258: IHWMNY = 3
259: ILALL = .TRUE.
260: ILBACK = .TRUE.
261: ELSE
262: IHWMNY = -1
263: ILALL = .TRUE.
264: END IF
265: *
266: IF( LSAME( SIDE, 'R' ) ) THEN
267: ISIDE = 1
268: COMPL = .FALSE.
269: COMPR = .TRUE.
270: ELSE IF( LSAME( SIDE, 'L' ) ) THEN
271: ISIDE = 2
272: COMPL = .TRUE.
273: COMPR = .FALSE.
274: ELSE IF( LSAME( SIDE, 'B' ) ) THEN
275: ISIDE = 3
276: COMPL = .TRUE.
277: COMPR = .TRUE.
278: ELSE
279: ISIDE = -1
280: END IF
281: *
282: INFO = 0
283: IF( ISIDE.LT.0 ) THEN
284: INFO = -1
285: ELSE IF( IHWMNY.LT.0 ) THEN
286: INFO = -2
287: ELSE IF( N.LT.0 ) THEN
288: INFO = -4
289: ELSE IF( LDS.LT.MAX( 1, N ) ) THEN
290: INFO = -6
291: ELSE IF( LDP.LT.MAX( 1, N ) ) THEN
292: INFO = -8
293: END IF
294: IF( INFO.NE.0 ) THEN
295: CALL XERBLA( 'DTGEVC', -INFO )
296: RETURN
297: END IF
298: *
299: * Count the number of eigenvectors to be computed
300: *
301: IF( .NOT.ILALL ) THEN
302: IM = 0
303: ILCPLX = .FALSE.
304: DO 10 J = 1, N
305: IF( ILCPLX ) THEN
306: ILCPLX = .FALSE.
307: GO TO 10
308: END IF
309: IF( J.LT.N ) THEN
310: IF( S( J+1, J ).NE.ZERO )
311: $ ILCPLX = .TRUE.
312: END IF
313: IF( ILCPLX ) THEN
314: IF( SELECT( J ) .OR. SELECT( J+1 ) )
315: $ IM = IM + 2
316: ELSE
317: IF( SELECT( J ) )
318: $ IM = IM + 1
319: END IF
320: 10 CONTINUE
321: ELSE
322: IM = N
323: END IF
324: *
325: * Check 2-by-2 diagonal blocks of A, B
326: *
327: ILABAD = .FALSE.
328: ILBBAD = .FALSE.
329: DO 20 J = 1, N - 1
330: IF( S( J+1, J ).NE.ZERO ) THEN
331: IF( P( J, J ).EQ.ZERO .OR. P( J+1, J+1 ).EQ.ZERO .OR.
332: $ P( J, J+1 ).NE.ZERO )ILBBAD = .TRUE.
333: IF( J.LT.N-1 ) THEN
334: IF( S( J+2, J+1 ).NE.ZERO )
335: $ ILABAD = .TRUE.
336: END IF
337: END IF
338: 20 CONTINUE
339: *
340: IF( ILABAD ) THEN
341: INFO = -5
342: ELSE IF( ILBBAD ) THEN
343: INFO = -7
344: ELSE IF( COMPL .AND. LDVL.LT.N .OR. LDVL.LT.1 ) THEN
345: INFO = -10
346: ELSE IF( COMPR .AND. LDVR.LT.N .OR. LDVR.LT.1 ) THEN
347: INFO = -12
348: ELSE IF( MM.LT.IM ) THEN
349: INFO = -13
350: END IF
351: IF( INFO.NE.0 ) THEN
352: CALL XERBLA( 'DTGEVC', -INFO )
353: RETURN
354: END IF
355: *
356: * Quick return if possible
357: *
358: M = IM
359: IF( N.EQ.0 )
360: $ RETURN
361: *
362: * Machine Constants
363: *
364: SAFMIN = DLAMCH( 'Safe minimum' )
365: BIG = ONE / SAFMIN
366: CALL DLABAD( SAFMIN, BIG )
367: ULP = DLAMCH( 'Epsilon' )*DLAMCH( 'Base' )
368: SMALL = SAFMIN*N / ULP
369: BIG = ONE / SMALL
370: BIGNUM = ONE / ( SAFMIN*N )
371: *
372: * Compute the 1-norm of each column of the strictly upper triangular
373: * part (i.e., excluding all elements belonging to the diagonal
374: * blocks) of A and B to check for possible overflow in the
375: * triangular solver.
376: *
377: ANORM = ABS( S( 1, 1 ) )
378: IF( N.GT.1 )
379: $ ANORM = ANORM + ABS( S( 2, 1 ) )
380: BNORM = ABS( P( 1, 1 ) )
381: WORK( 1 ) = ZERO
382: WORK( N+1 ) = ZERO
383: *
384: DO 50 J = 2, N
385: TEMP = ZERO
386: TEMP2 = ZERO
387: IF( S( J, J-1 ).EQ.ZERO ) THEN
388: IEND = J - 1
389: ELSE
390: IEND = J - 2
391: END IF
392: DO 30 I = 1, IEND
393: TEMP = TEMP + ABS( S( I, J ) )
394: TEMP2 = TEMP2 + ABS( P( I, J ) )
395: 30 CONTINUE
396: WORK( J ) = TEMP
397: WORK( N+J ) = TEMP2
398: DO 40 I = IEND + 1, MIN( J+1, N )
399: TEMP = TEMP + ABS( S( I, J ) )
400: TEMP2 = TEMP2 + ABS( P( I, J ) )
401: 40 CONTINUE
402: ANORM = MAX( ANORM, TEMP )
403: BNORM = MAX( BNORM, TEMP2 )
404: 50 CONTINUE
405: *
406: ASCALE = ONE / MAX( ANORM, SAFMIN )
407: BSCALE = ONE / MAX( BNORM, SAFMIN )
408: *
409: * Left eigenvectors
410: *
411: IF( COMPL ) THEN
412: IEIG = 0
413: *
414: * Main loop over eigenvalues
415: *
416: ILCPLX = .FALSE.
417: DO 220 JE = 1, N
418: *
419: * Skip this iteration if (a) HOWMNY='S' and SELECT=.FALSE., or
420: * (b) this would be the second of a complex pair.
421: * Check for complex eigenvalue, so as to be sure of which
422: * entry(-ies) of SELECT to look at.
423: *
424: IF( ILCPLX ) THEN
425: ILCPLX = .FALSE.
426: GO TO 220
427: END IF
428: NW = 1
429: IF( JE.LT.N ) THEN
430: IF( S( JE+1, JE ).NE.ZERO ) THEN
431: ILCPLX = .TRUE.
432: NW = 2
433: END IF
434: END IF
435: IF( ILALL ) THEN
436: ILCOMP = .TRUE.
437: ELSE IF( ILCPLX ) THEN
438: ILCOMP = SELECT( JE ) .OR. SELECT( JE+1 )
439: ELSE
440: ILCOMP = SELECT( JE )
441: END IF
442: IF( .NOT.ILCOMP )
443: $ GO TO 220
444: *
445: * Decide if (a) singular pencil, (b) real eigenvalue, or
446: * (c) complex eigenvalue.
447: *
448: IF( .NOT.ILCPLX ) THEN
449: IF( ABS( S( JE, JE ) ).LE.SAFMIN .AND.
450: $ ABS( P( JE, JE ) ).LE.SAFMIN ) THEN
451: *
452: * Singular matrix pencil -- return unit eigenvector
453: *
454: IEIG = IEIG + 1
455: DO 60 JR = 1, N
456: VL( JR, IEIG ) = ZERO
457: 60 CONTINUE
458: VL( IEIG, IEIG ) = ONE
459: GO TO 220
460: END IF
461: END IF
462: *
463: * Clear vector
464: *
465: DO 70 JR = 1, NW*N
466: WORK( 2*N+JR ) = ZERO
467: 70 CONTINUE
468: * T
469: * Compute coefficients in ( a A - b B ) y = 0
470: * a is ACOEF
471: * b is BCOEFR + i*BCOEFI
472: *
473: IF( .NOT.ILCPLX ) THEN
474: *
475: * Real eigenvalue
476: *
477: TEMP = ONE / MAX( ABS( S( JE, JE ) )*ASCALE,
478: $ ABS( P( JE, JE ) )*BSCALE, SAFMIN )
479: SALFAR = ( TEMP*S( JE, JE ) )*ASCALE
480: SBETA = ( TEMP*P( JE, JE ) )*BSCALE
481: ACOEF = SBETA*ASCALE
482: BCOEFR = SALFAR*BSCALE
483: BCOEFI = ZERO
484: *
485: * Scale to avoid underflow
486: *
487: SCALE = ONE
488: LSA = ABS( SBETA ).GE.SAFMIN .AND. ABS( ACOEF ).LT.SMALL
489: LSB = ABS( SALFAR ).GE.SAFMIN .AND. ABS( BCOEFR ).LT.
490: $ SMALL
491: IF( LSA )
492: $ SCALE = ( SMALL / ABS( SBETA ) )*MIN( ANORM, BIG )
493: IF( LSB )
494: $ SCALE = MAX( SCALE, ( SMALL / ABS( SALFAR ) )*
495: $ MIN( BNORM, BIG ) )
496: IF( LSA .OR. LSB ) THEN
497: SCALE = MIN( SCALE, ONE /
498: $ ( SAFMIN*MAX( ONE, ABS( ACOEF ),
499: $ ABS( BCOEFR ) ) ) )
500: IF( LSA ) THEN
501: ACOEF = ASCALE*( SCALE*SBETA )
502: ELSE
503: ACOEF = SCALE*ACOEF
504: END IF
505: IF( LSB ) THEN
506: BCOEFR = BSCALE*( SCALE*SALFAR )
507: ELSE
508: BCOEFR = SCALE*BCOEFR
509: END IF
510: END IF
511: ACOEFA = ABS( ACOEF )
512: BCOEFA = ABS( BCOEFR )
513: *
514: * First component is 1
515: *
516: WORK( 2*N+JE ) = ONE
517: XMAX = ONE
518: ELSE
519: *
520: * Complex eigenvalue
521: *
522: CALL DLAG2( S( JE, JE ), LDS, P( JE, JE ), LDP,
523: $ SAFMIN*SAFETY, ACOEF, TEMP, BCOEFR, TEMP2,
524: $ BCOEFI )
525: BCOEFI = -BCOEFI
526: IF( BCOEFI.EQ.ZERO ) THEN
527: INFO = JE
528: RETURN
529: END IF
530: *
531: * Scale to avoid over/underflow
532: *
533: ACOEFA = ABS( ACOEF )
534: BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
535: SCALE = ONE
536: IF( ACOEFA*ULP.LT.SAFMIN .AND. ACOEFA.GE.SAFMIN )
537: $ SCALE = ( SAFMIN / ULP ) / ACOEFA
538: IF( BCOEFA*ULP.LT.SAFMIN .AND. BCOEFA.GE.SAFMIN )
539: $ SCALE = MAX( SCALE, ( SAFMIN / ULP ) / BCOEFA )
540: IF( SAFMIN*ACOEFA.GT.ASCALE )
541: $ SCALE = ASCALE / ( SAFMIN*ACOEFA )
542: IF( SAFMIN*BCOEFA.GT.BSCALE )
543: $ SCALE = MIN( SCALE, BSCALE / ( SAFMIN*BCOEFA ) )
544: IF( SCALE.NE.ONE ) THEN
545: ACOEF = SCALE*ACOEF
546: ACOEFA = ABS( ACOEF )
547: BCOEFR = SCALE*BCOEFR
548: BCOEFI = SCALE*BCOEFI
549: BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
550: END IF
551: *
552: * Compute first two components of eigenvector
553: *
554: TEMP = ACOEF*S( JE+1, JE )
555: TEMP2R = ACOEF*S( JE, JE ) - BCOEFR*P( JE, JE )
556: TEMP2I = -BCOEFI*P( JE, JE )
557: IF( ABS( TEMP ).GT.ABS( TEMP2R )+ABS( TEMP2I ) ) THEN
558: WORK( 2*N+JE ) = ONE
559: WORK( 3*N+JE ) = ZERO
560: WORK( 2*N+JE+1 ) = -TEMP2R / TEMP
561: WORK( 3*N+JE+1 ) = -TEMP2I / TEMP
562: ELSE
563: WORK( 2*N+JE+1 ) = ONE
564: WORK( 3*N+JE+1 ) = ZERO
565: TEMP = ACOEF*S( JE, JE+1 )
566: WORK( 2*N+JE ) = ( BCOEFR*P( JE+1, JE+1 )-ACOEF*
567: $ S( JE+1, JE+1 ) ) / TEMP
568: WORK( 3*N+JE ) = BCOEFI*P( JE+1, JE+1 ) / TEMP
569: END IF
570: XMAX = MAX( ABS( WORK( 2*N+JE ) )+ABS( WORK( 3*N+JE ) ),
571: $ ABS( WORK( 2*N+JE+1 ) )+ABS( WORK( 3*N+JE+1 ) ) )
572: END IF
573: *
574: DMIN = MAX( ULP*ACOEFA*ANORM, ULP*BCOEFA*BNORM, SAFMIN )
575: *
576: * T
577: * Triangular solve of (a A - b B) y = 0
578: *
579: * T
580: * (rowwise in (a A - b B) , or columnwise in (a A - b B) )
581: *
582: IL2BY2 = .FALSE.
583: *
584: DO 160 J = JE + NW, N
585: IF( IL2BY2 ) THEN
586: IL2BY2 = .FALSE.
587: GO TO 160
588: END IF
589: *
590: NA = 1
591: BDIAG( 1 ) = P( J, J )
592: IF( J.LT.N ) THEN
593: IF( S( J+1, J ).NE.ZERO ) THEN
594: IL2BY2 = .TRUE.
595: BDIAG( 2 ) = P( J+1, J+1 )
596: NA = 2
597: END IF
598: END IF
599: *
600: * Check whether scaling is necessary for dot products
601: *
602: XSCALE = ONE / MAX( ONE, XMAX )
603: TEMP = MAX( WORK( J ), WORK( N+J ),
604: $ ACOEFA*WORK( J )+BCOEFA*WORK( N+J ) )
605: IF( IL2BY2 )
606: $ TEMP = MAX( TEMP, WORK( J+1 ), WORK( N+J+1 ),
607: $ ACOEFA*WORK( J+1 )+BCOEFA*WORK( N+J+1 ) )
608: IF( TEMP.GT.BIGNUM*XSCALE ) THEN
609: DO 90 JW = 0, NW - 1
610: DO 80 JR = JE, J - 1
611: WORK( ( JW+2 )*N+JR ) = XSCALE*
612: $ WORK( ( JW+2 )*N+JR )
613: 80 CONTINUE
614: 90 CONTINUE
615: XMAX = XMAX*XSCALE
616: END IF
617: *
618: * Compute dot products
619: *
620: * j-1
621: * SUM = sum conjg( a*S(k,j) - b*P(k,j) )*x(k)
622: * k=je
623: *
624: * To reduce the op count, this is done as
625: *
626: * _ j-1 _ j-1
627: * a*conjg( sum S(k,j)*x(k) ) - b*conjg( sum P(k,j)*x(k) )
628: * k=je k=je
629: *
630: * which may cause underflow problems if A or B are close
631: * to underflow. (E.g., less than SMALL.)
632: *
633: *
634: * A series of compiler directives to defeat vectorization
635: * for the next loop
636: *
637: *$PL$ CMCHAR=' '
638: CDIR$ NEXTSCALAR
639: C$DIR SCALAR
640: CDIR$ NEXT SCALAR
641: CVD$L NOVECTOR
642: CDEC$ NOVECTOR
643: CVD$ NOVECTOR
644: *VDIR NOVECTOR
645: *VOCL LOOP,SCALAR
646: CIBM PREFER SCALAR
647: *$PL$ CMCHAR='*'
648: *
649: DO 120 JW = 1, NW
650: *
651: *$PL$ CMCHAR=' '
652: CDIR$ NEXTSCALAR
653: C$DIR SCALAR
654: CDIR$ NEXT SCALAR
655: CVD$L NOVECTOR
656: CDEC$ NOVECTOR
657: CVD$ NOVECTOR
658: *VDIR NOVECTOR
659: *VOCL LOOP,SCALAR
660: CIBM PREFER SCALAR
661: *$PL$ CMCHAR='*'
662: *
663: DO 110 JA = 1, NA
664: SUMS( JA, JW ) = ZERO
665: SUMP( JA, JW ) = ZERO
666: *
667: DO 100 JR = JE, J - 1
668: SUMS( JA, JW ) = SUMS( JA, JW ) +
669: $ S( JR, J+JA-1 )*
670: $ WORK( ( JW+1 )*N+JR )
671: SUMP( JA, JW ) = SUMP( JA, JW ) +
672: $ P( JR, J+JA-1 )*
673: $ WORK( ( JW+1 )*N+JR )
674: 100 CONTINUE
675: 110 CONTINUE
676: 120 CONTINUE
677: *
678: *$PL$ CMCHAR=' '
679: CDIR$ NEXTSCALAR
680: C$DIR SCALAR
681: CDIR$ NEXT SCALAR
682: CVD$L NOVECTOR
683: CDEC$ NOVECTOR
684: CVD$ NOVECTOR
685: *VDIR NOVECTOR
686: *VOCL LOOP,SCALAR
687: CIBM PREFER SCALAR
688: *$PL$ CMCHAR='*'
689: *
690: DO 130 JA = 1, NA
691: IF( ILCPLX ) THEN
692: SUM( JA, 1 ) = -ACOEF*SUMS( JA, 1 ) +
693: $ BCOEFR*SUMP( JA, 1 ) -
694: $ BCOEFI*SUMP( JA, 2 )
695: SUM( JA, 2 ) = -ACOEF*SUMS( JA, 2 ) +
696: $ BCOEFR*SUMP( JA, 2 ) +
697: $ BCOEFI*SUMP( JA, 1 )
698: ELSE
699: SUM( JA, 1 ) = -ACOEF*SUMS( JA, 1 ) +
700: $ BCOEFR*SUMP( JA, 1 )
701: END IF
702: 130 CONTINUE
703: *
704: * T
705: * Solve ( a A - b B ) y = SUM(,)
706: * with scaling and perturbation of the denominator
707: *
708: CALL DLALN2( .TRUE., NA, NW, DMIN, ACOEF, S( J, J ), LDS,
709: $ BDIAG( 1 ), BDIAG( 2 ), SUM, 2, BCOEFR,
710: $ BCOEFI, WORK( 2*N+J ), N, SCALE, TEMP,
711: $ IINFO )
712: IF( SCALE.LT.ONE ) THEN
713: DO 150 JW = 0, NW - 1
714: DO 140 JR = JE, J - 1
715: WORK( ( JW+2 )*N+JR ) = SCALE*
716: $ WORK( ( JW+2 )*N+JR )
717: 140 CONTINUE
718: 150 CONTINUE
719: XMAX = SCALE*XMAX
720: END IF
721: XMAX = MAX( XMAX, TEMP )
722: 160 CONTINUE
723: *
724: * Copy eigenvector to VL, back transforming if
725: * HOWMNY='B'.
726: *
727: IEIG = IEIG + 1
728: IF( ILBACK ) THEN
729: DO 170 JW = 0, NW - 1
730: CALL DGEMV( 'N', N, N+1-JE, ONE, VL( 1, JE ), LDVL,
731: $ WORK( ( JW+2 )*N+JE ), 1, ZERO,
732: $ WORK( ( JW+4 )*N+1 ), 1 )
733: 170 CONTINUE
734: CALL DLACPY( ' ', N, NW, WORK( 4*N+1 ), N, VL( 1, JE ),
735: $ LDVL )
736: IBEG = 1
737: ELSE
738: CALL DLACPY( ' ', N, NW, WORK( 2*N+1 ), N, VL( 1, IEIG ),
739: $ LDVL )
740: IBEG = JE
741: END IF
742: *
743: * Scale eigenvector
744: *
745: XMAX = ZERO
746: IF( ILCPLX ) THEN
747: DO 180 J = IBEG, N
748: XMAX = MAX( XMAX, ABS( VL( J, IEIG ) )+
749: $ ABS( VL( J, IEIG+1 ) ) )
750: 180 CONTINUE
751: ELSE
752: DO 190 J = IBEG, N
753: XMAX = MAX( XMAX, ABS( VL( J, IEIG ) ) )
754: 190 CONTINUE
755: END IF
756: *
757: IF( XMAX.GT.SAFMIN ) THEN
758: XSCALE = ONE / XMAX
759: *
760: DO 210 JW = 0, NW - 1
761: DO 200 JR = IBEG, N
762: VL( JR, IEIG+JW ) = XSCALE*VL( JR, IEIG+JW )
763: 200 CONTINUE
764: 210 CONTINUE
765: END IF
766: IEIG = IEIG + NW - 1
767: *
768: 220 CONTINUE
769: END IF
770: *
771: * Right eigenvectors
772: *
773: IF( COMPR ) THEN
774: IEIG = IM + 1
775: *
776: * Main loop over eigenvalues
777: *
778: ILCPLX = .FALSE.
779: DO 500 JE = N, 1, -1
780: *
781: * Skip this iteration if (a) HOWMNY='S' and SELECT=.FALSE., or
782: * (b) this would be the second of a complex pair.
783: * Check for complex eigenvalue, so as to be sure of which
784: * entry(-ies) of SELECT to look at -- if complex, SELECT(JE)
785: * or SELECT(JE-1).
786: * If this is a complex pair, the 2-by-2 diagonal block
787: * corresponding to the eigenvalue is in rows/columns JE-1:JE
788: *
789: IF( ILCPLX ) THEN
790: ILCPLX = .FALSE.
791: GO TO 500
792: END IF
793: NW = 1
794: IF( JE.GT.1 ) THEN
795: IF( S( JE, JE-1 ).NE.ZERO ) THEN
796: ILCPLX = .TRUE.
797: NW = 2
798: END IF
799: END IF
800: IF( ILALL ) THEN
801: ILCOMP = .TRUE.
802: ELSE IF( ILCPLX ) THEN
803: ILCOMP = SELECT( JE ) .OR. SELECT( JE-1 )
804: ELSE
805: ILCOMP = SELECT( JE )
806: END IF
807: IF( .NOT.ILCOMP )
808: $ GO TO 500
809: *
810: * Decide if (a) singular pencil, (b) real eigenvalue, or
811: * (c) complex eigenvalue.
812: *
813: IF( .NOT.ILCPLX ) THEN
814: IF( ABS( S( JE, JE ) ).LE.SAFMIN .AND.
815: $ ABS( P( JE, JE ) ).LE.SAFMIN ) THEN
816: *
817: * Singular matrix pencil -- unit eigenvector
818: *
819: IEIG = IEIG - 1
820: DO 230 JR = 1, N
821: VR( JR, IEIG ) = ZERO
822: 230 CONTINUE
823: VR( IEIG, IEIG ) = ONE
824: GO TO 500
825: END IF
826: END IF
827: *
828: * Clear vector
829: *
830: DO 250 JW = 0, NW - 1
831: DO 240 JR = 1, N
832: WORK( ( JW+2 )*N+JR ) = ZERO
833: 240 CONTINUE
834: 250 CONTINUE
835: *
836: * Compute coefficients in ( a A - b B ) x = 0
837: * a is ACOEF
838: * b is BCOEFR + i*BCOEFI
839: *
840: IF( .NOT.ILCPLX ) THEN
841: *
842: * Real eigenvalue
843: *
844: TEMP = ONE / MAX( ABS( S( JE, JE ) )*ASCALE,
845: $ ABS( P( JE, JE ) )*BSCALE, SAFMIN )
846: SALFAR = ( TEMP*S( JE, JE ) )*ASCALE
847: SBETA = ( TEMP*P( JE, JE ) )*BSCALE
848: ACOEF = SBETA*ASCALE
849: BCOEFR = SALFAR*BSCALE
850: BCOEFI = ZERO
851: *
852: * Scale to avoid underflow
853: *
854: SCALE = ONE
855: LSA = ABS( SBETA ).GE.SAFMIN .AND. ABS( ACOEF ).LT.SMALL
856: LSB = ABS( SALFAR ).GE.SAFMIN .AND. ABS( BCOEFR ).LT.
857: $ SMALL
858: IF( LSA )
859: $ SCALE = ( SMALL / ABS( SBETA ) )*MIN( ANORM, BIG )
860: IF( LSB )
861: $ SCALE = MAX( SCALE, ( SMALL / ABS( SALFAR ) )*
862: $ MIN( BNORM, BIG ) )
863: IF( LSA .OR. LSB ) THEN
864: SCALE = MIN( SCALE, ONE /
865: $ ( SAFMIN*MAX( ONE, ABS( ACOEF ),
866: $ ABS( BCOEFR ) ) ) )
867: IF( LSA ) THEN
868: ACOEF = ASCALE*( SCALE*SBETA )
869: ELSE
870: ACOEF = SCALE*ACOEF
871: END IF
872: IF( LSB ) THEN
873: BCOEFR = BSCALE*( SCALE*SALFAR )
874: ELSE
875: BCOEFR = SCALE*BCOEFR
876: END IF
877: END IF
878: ACOEFA = ABS( ACOEF )
879: BCOEFA = ABS( BCOEFR )
880: *
881: * First component is 1
882: *
883: WORK( 2*N+JE ) = ONE
884: XMAX = ONE
885: *
886: * Compute contribution from column JE of A and B to sum
887: * (See "Further Details", above.)
888: *
889: DO 260 JR = 1, JE - 1
890: WORK( 2*N+JR ) = BCOEFR*P( JR, JE ) -
891: $ ACOEF*S( JR, JE )
892: 260 CONTINUE
893: ELSE
894: *
895: * Complex eigenvalue
896: *
897: CALL DLAG2( S( JE-1, JE-1 ), LDS, P( JE-1, JE-1 ), LDP,
898: $ SAFMIN*SAFETY, ACOEF, TEMP, BCOEFR, TEMP2,
899: $ BCOEFI )
900: IF( BCOEFI.EQ.ZERO ) THEN
901: INFO = JE - 1
902: RETURN
903: END IF
904: *
905: * Scale to avoid over/underflow
906: *
907: ACOEFA = ABS( ACOEF )
908: BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
909: SCALE = ONE
910: IF( ACOEFA*ULP.LT.SAFMIN .AND. ACOEFA.GE.SAFMIN )
911: $ SCALE = ( SAFMIN / ULP ) / ACOEFA
912: IF( BCOEFA*ULP.LT.SAFMIN .AND. BCOEFA.GE.SAFMIN )
913: $ SCALE = MAX( SCALE, ( SAFMIN / ULP ) / BCOEFA )
914: IF( SAFMIN*ACOEFA.GT.ASCALE )
915: $ SCALE = ASCALE / ( SAFMIN*ACOEFA )
916: IF( SAFMIN*BCOEFA.GT.BSCALE )
917: $ SCALE = MIN( SCALE, BSCALE / ( SAFMIN*BCOEFA ) )
918: IF( SCALE.NE.ONE ) THEN
919: ACOEF = SCALE*ACOEF
920: ACOEFA = ABS( ACOEF )
921: BCOEFR = SCALE*BCOEFR
922: BCOEFI = SCALE*BCOEFI
923: BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
924: END IF
925: *
926: * Compute first two components of eigenvector
927: * and contribution to sums
928: *
929: TEMP = ACOEF*S( JE, JE-1 )
930: TEMP2R = ACOEF*S( JE, JE ) - BCOEFR*P( JE, JE )
931: TEMP2I = -BCOEFI*P( JE, JE )
932: IF( ABS( TEMP ).GE.ABS( TEMP2R )+ABS( TEMP2I ) ) THEN
933: WORK( 2*N+JE ) = ONE
934: WORK( 3*N+JE ) = ZERO
935: WORK( 2*N+JE-1 ) = -TEMP2R / TEMP
936: WORK( 3*N+JE-1 ) = -TEMP2I / TEMP
937: ELSE
938: WORK( 2*N+JE-1 ) = ONE
939: WORK( 3*N+JE-1 ) = ZERO
940: TEMP = ACOEF*S( JE-1, JE )
941: WORK( 2*N+JE ) = ( BCOEFR*P( JE-1, JE-1 )-ACOEF*
942: $ S( JE-1, JE-1 ) ) / TEMP
943: WORK( 3*N+JE ) = BCOEFI*P( JE-1, JE-1 ) / TEMP
944: END IF
945: *
946: XMAX = MAX( ABS( WORK( 2*N+JE ) )+ABS( WORK( 3*N+JE ) ),
947: $ ABS( WORK( 2*N+JE-1 ) )+ABS( WORK( 3*N+JE-1 ) ) )
948: *
949: * Compute contribution from columns JE and JE-1
950: * of A and B to the sums.
951: *
952: CREALA = ACOEF*WORK( 2*N+JE-1 )
953: CIMAGA = ACOEF*WORK( 3*N+JE-1 )
954: CREALB = BCOEFR*WORK( 2*N+JE-1 ) -
955: $ BCOEFI*WORK( 3*N+JE-1 )
956: CIMAGB = BCOEFI*WORK( 2*N+JE-1 ) +
957: $ BCOEFR*WORK( 3*N+JE-1 )
958: CRE2A = ACOEF*WORK( 2*N+JE )
959: CIM2A = ACOEF*WORK( 3*N+JE )
960: CRE2B = BCOEFR*WORK( 2*N+JE ) - BCOEFI*WORK( 3*N+JE )
961: CIM2B = BCOEFI*WORK( 2*N+JE ) + BCOEFR*WORK( 3*N+JE )
962: DO 270 JR = 1, JE - 2
963: WORK( 2*N+JR ) = -CREALA*S( JR, JE-1 ) +
964: $ CREALB*P( JR, JE-1 ) -
965: $ CRE2A*S( JR, JE ) + CRE2B*P( JR, JE )
966: WORK( 3*N+JR ) = -CIMAGA*S( JR, JE-1 ) +
967: $ CIMAGB*P( JR, JE-1 ) -
968: $ CIM2A*S( JR, JE ) + CIM2B*P( JR, JE )
969: 270 CONTINUE
970: END IF
971: *
972: DMIN = MAX( ULP*ACOEFA*ANORM, ULP*BCOEFA*BNORM, SAFMIN )
973: *
974: * Columnwise triangular solve of (a A - b B) x = 0
975: *
976: IL2BY2 = .FALSE.
977: DO 370 J = JE - NW, 1, -1
978: *
979: * If a 2-by-2 block, is in position j-1:j, wait until
980: * next iteration to process it (when it will be j:j+1)
981: *
982: IF( .NOT.IL2BY2 .AND. J.GT.1 ) THEN
983: IF( S( J, J-1 ).NE.ZERO ) THEN
984: IL2BY2 = .TRUE.
985: GO TO 370
986: END IF
987: END IF
988: BDIAG( 1 ) = P( J, J )
989: IF( IL2BY2 ) THEN
990: NA = 2
991: BDIAG( 2 ) = P( J+1, J+1 )
992: ELSE
993: NA = 1
994: END IF
995: *
996: * Compute x(j) (and x(j+1), if 2-by-2 block)
997: *
998: CALL DLALN2( .FALSE., NA, NW, DMIN, ACOEF, S( J, J ),
999: $ LDS, BDIAG( 1 ), BDIAG( 2 ), WORK( 2*N+J ),
1000: $ N, BCOEFR, BCOEFI, SUM, 2, SCALE, TEMP,
1001: $ IINFO )
1002: IF( SCALE.LT.ONE ) THEN
1003: *
1004: DO 290 JW = 0, NW - 1
1005: DO 280 JR = 1, JE
1006: WORK( ( JW+2 )*N+JR ) = SCALE*
1007: $ WORK( ( JW+2 )*N+JR )
1008: 280 CONTINUE
1009: 290 CONTINUE
1010: END IF
1011: XMAX = MAX( SCALE*XMAX, TEMP )
1012: *
1013: DO 310 JW = 1, NW
1014: DO 300 JA = 1, NA
1015: WORK( ( JW+1 )*N+J+JA-1 ) = SUM( JA, JW )
1016: 300 CONTINUE
1017: 310 CONTINUE
1018: *
1019: * w = w + x(j)*(a S(*,j) - b P(*,j) ) with scaling
1020: *
1021: IF( J.GT.1 ) THEN
1022: *
1023: * Check whether scaling is necessary for sum.
1024: *
1025: XSCALE = ONE / MAX( ONE, XMAX )
1026: TEMP = ACOEFA*WORK( J ) + BCOEFA*WORK( N+J )
1027: IF( IL2BY2 )
1028: $ TEMP = MAX( TEMP, ACOEFA*WORK( J+1 )+BCOEFA*
1029: $ WORK( N+J+1 ) )
1030: TEMP = MAX( TEMP, ACOEFA, BCOEFA )
1031: IF( TEMP.GT.BIGNUM*XSCALE ) THEN
1032: *
1033: DO 330 JW = 0, NW - 1
1034: DO 320 JR = 1, JE
1035: WORK( ( JW+2 )*N+JR ) = XSCALE*
1036: $ WORK( ( JW+2 )*N+JR )
1037: 320 CONTINUE
1038: 330 CONTINUE
1039: XMAX = XMAX*XSCALE
1040: END IF
1041: *
1042: * Compute the contributions of the off-diagonals of
1043: * column j (and j+1, if 2-by-2 block) of A and B to the
1044: * sums.
1045: *
1046: *
1047: DO 360 JA = 1, NA
1048: IF( ILCPLX ) THEN
1049: CREALA = ACOEF*WORK( 2*N+J+JA-1 )
1050: CIMAGA = ACOEF*WORK( 3*N+J+JA-1 )
1051: CREALB = BCOEFR*WORK( 2*N+J+JA-1 ) -
1052: $ BCOEFI*WORK( 3*N+J+JA-1 )
1053: CIMAGB = BCOEFI*WORK( 2*N+J+JA-1 ) +
1054: $ BCOEFR*WORK( 3*N+J+JA-1 )
1055: DO 340 JR = 1, J - 1
1056: WORK( 2*N+JR ) = WORK( 2*N+JR ) -
1057: $ CREALA*S( JR, J+JA-1 ) +
1058: $ CREALB*P( JR, J+JA-1 )
1059: WORK( 3*N+JR ) = WORK( 3*N+JR ) -
1060: $ CIMAGA*S( JR, J+JA-1 ) +
1061: $ CIMAGB*P( JR, J+JA-1 )
1062: 340 CONTINUE
1063: ELSE
1064: CREALA = ACOEF*WORK( 2*N+J+JA-1 )
1065: CREALB = BCOEFR*WORK( 2*N+J+JA-1 )
1066: DO 350 JR = 1, J - 1
1067: WORK( 2*N+JR ) = WORK( 2*N+JR ) -
1068: $ CREALA*S( JR, J+JA-1 ) +
1069: $ CREALB*P( JR, J+JA-1 )
1070: 350 CONTINUE
1071: END IF
1072: 360 CONTINUE
1073: END IF
1074: *
1075: IL2BY2 = .FALSE.
1076: 370 CONTINUE
1077: *
1078: * Copy eigenvector to VR, back transforming if
1079: * HOWMNY='B'.
1080: *
1081: IEIG = IEIG - NW
1082: IF( ILBACK ) THEN
1083: *
1084: DO 410 JW = 0, NW - 1
1085: DO 380 JR = 1, N
1086: WORK( ( JW+4 )*N+JR ) = WORK( ( JW+2 )*N+1 )*
1087: $ VR( JR, 1 )
1088: 380 CONTINUE
1089: *
1090: * A series of compiler directives to defeat
1091: * vectorization for the next loop
1092: *
1093: *
1094: DO 400 JC = 2, JE
1095: DO 390 JR = 1, N
1096: WORK( ( JW+4 )*N+JR ) = WORK( ( JW+4 )*N+JR ) +
1097: $ WORK( ( JW+2 )*N+JC )*VR( JR, JC )
1098: 390 CONTINUE
1099: 400 CONTINUE
1100: 410 CONTINUE
1101: *
1102: DO 430 JW = 0, NW - 1
1103: DO 420 JR = 1, N
1104: VR( JR, IEIG+JW ) = WORK( ( JW+4 )*N+JR )
1105: 420 CONTINUE
1106: 430 CONTINUE
1107: *
1108: IEND = N
1109: ELSE
1110: DO 450 JW = 0, NW - 1
1111: DO 440 JR = 1, N
1112: VR( JR, IEIG+JW ) = WORK( ( JW+2 )*N+JR )
1113: 440 CONTINUE
1114: 450 CONTINUE
1115: *
1116: IEND = JE
1117: END IF
1118: *
1119: * Scale eigenvector
1120: *
1121: XMAX = ZERO
1122: IF( ILCPLX ) THEN
1123: DO 460 J = 1, IEND
1124: XMAX = MAX( XMAX, ABS( VR( J, IEIG ) )+
1125: $ ABS( VR( J, IEIG+1 ) ) )
1126: 460 CONTINUE
1127: ELSE
1128: DO 470 J = 1, IEND
1129: XMAX = MAX( XMAX, ABS( VR( J, IEIG ) ) )
1130: 470 CONTINUE
1131: END IF
1132: *
1133: IF( XMAX.GT.SAFMIN ) THEN
1134: XSCALE = ONE / XMAX
1135: DO 490 JW = 0, NW - 1
1136: DO 480 JR = 1, IEND
1137: VR( JR, IEIG+JW ) = XSCALE*VR( JR, IEIG+JW )
1138: 480 CONTINUE
1139: 490 CONTINUE
1140: END IF
1141: 500 CONTINUE
1142: END IF
1143: *
1144: RETURN
1145: *
1146: * End of DTGEVC
1147: *
1148: END
CVSweb interface <joel.bertrand@systella.fr>