1: SUBROUTINE DLARRD( RANGE, ORDER, N, VL, VU, IL, IU, GERS,
2: $ RELTOL, D, E, E2, PIVMIN, NSPLIT, ISPLIT,
3: $ M, W, WERR, WL, WU, IBLOCK, INDEXW,
4: $ WORK, IWORK, INFO )
5: *
6: * -- LAPACK auxiliary routine (version 3.2.1) --
7: * -- LAPACK is a software package provided by Univ. of Tennessee, --
8: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
9: * -- April 2009 --
10: *
11: * .. Scalar Arguments ..
12: CHARACTER ORDER, RANGE
13: INTEGER IL, INFO, IU, M, N, NSPLIT
14: DOUBLE PRECISION PIVMIN, RELTOL, VL, VU, WL, WU
15: * ..
16: * .. Array Arguments ..
17: INTEGER IBLOCK( * ), INDEXW( * ),
18: $ ISPLIT( * ), IWORK( * )
19: DOUBLE PRECISION D( * ), E( * ), E2( * ),
20: $ GERS( * ), W( * ), WERR( * ), WORK( * )
21: * ..
22: *
23: * Purpose
24: * =======
25: *
26: * DLARRD computes the eigenvalues of a symmetric tridiagonal
27: * matrix T to suitable accuracy. This is an auxiliary code to be
28: * called from DSTEMR.
29: * The user may ask for all eigenvalues, all eigenvalues
30: * in the half-open interval (VL, VU], or the IL-th through IU-th
31: * eigenvalues.
32: *
33: * To avoid overflow, the matrix must be scaled so that its
34: * largest element is no greater than overflow**(1/2) *
35: * underflow**(1/4) in absolute value, and for greatest
36: * accuracy, it should not be much smaller than that.
37: *
38: * See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal
39: * Matrix", Report CS41, Computer Science Dept., Stanford
40: * University, July 21, 1966.
41: *
42: * Arguments
43: * =========
44: *
45: * RANGE (input) CHARACTER
46: * = 'A': ("All") all eigenvalues will be found.
47: * = 'V': ("Value") all eigenvalues in the half-open interval
48: * (VL, VU] will be found.
49: * = 'I': ("Index") the IL-th through IU-th eigenvalues (of the
50: * entire matrix) will be found.
51: *
52: * ORDER (input) CHARACTER
53: * = 'B': ("By Block") the eigenvalues will be grouped by
54: * split-off block (see IBLOCK, ISPLIT) and
55: * ordered from smallest to largest within
56: * the block.
57: * = 'E': ("Entire matrix")
58: * the eigenvalues for the entire matrix
59: * will be ordered from smallest to
60: * largest.
61: *
62: * N (input) INTEGER
63: * The order of the tridiagonal matrix T. N >= 0.
64: *
65: * VL (input) DOUBLE PRECISION
66: * VU (input) DOUBLE PRECISION
67: * If RANGE='V', the lower and upper bounds of the interval to
68: * be searched for eigenvalues. Eigenvalues less than or equal
69: * to VL, or greater than VU, will not be returned. VL < VU.
70: * Not referenced if RANGE = 'A' or 'I'.
71: *
72: * IL (input) INTEGER
73: * IU (input) INTEGER
74: * If RANGE='I', the indices (in ascending order) of the
75: * smallest and largest eigenvalues to be returned.
76: * 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.
77: * Not referenced if RANGE = 'A' or 'V'.
78: *
79: * GERS (input) DOUBLE PRECISION array, dimension (2*N)
80: * The N Gerschgorin intervals (the i-th Gerschgorin interval
81: * is (GERS(2*i-1), GERS(2*i)).
82: *
83: * RELTOL (input) DOUBLE PRECISION
84: * The minimum relative width of an interval. When an interval
85: * is narrower than RELTOL times the larger (in
86: * magnitude) endpoint, then it is considered to be
87: * sufficiently small, i.e., converged. Note: this should
88: * always be at least radix*machine epsilon.
89: *
90: * D (input) DOUBLE PRECISION array, dimension (N)
91: * The n diagonal elements of the tridiagonal matrix T.
92: *
93: * E (input) DOUBLE PRECISION array, dimension (N-1)
94: * The (n-1) off-diagonal elements of the tridiagonal matrix T.
95: *
96: * E2 (input) DOUBLE PRECISION array, dimension (N-1)
97: * The (n-1) squared off-diagonal elements of the tridiagonal matrix T.
98: *
99: * PIVMIN (input) DOUBLE PRECISION
100: * The minimum pivot allowed in the Sturm sequence for T.
101: *
102: * NSPLIT (input) INTEGER
103: * The number of diagonal blocks in the matrix T.
104: * 1 <= NSPLIT <= N.
105: *
106: * ISPLIT (input) INTEGER array, dimension (N)
107: * The splitting points, at which T breaks up into submatrices.
108: * The first submatrix consists of rows/columns 1 to ISPLIT(1),
109: * the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),
110: * etc., and the NSPLIT-th consists of rows/columns
111: * ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.
112: * (Only the first NSPLIT elements will actually be used, but
113: * since the user cannot know a priori what value NSPLIT will
114: * have, N words must be reserved for ISPLIT.)
115: *
116: * M (output) INTEGER
117: * The actual number of eigenvalues found. 0 <= M <= N.
118: * (See also the description of INFO=2,3.)
119: *
120: * W (output) DOUBLE PRECISION array, dimension (N)
121: * On exit, the first M elements of W will contain the
122: * eigenvalue approximations. DLARRD computes an interval
123: * I_j = (a_j, b_j] that includes eigenvalue j. The eigenvalue
124: * approximation is given as the interval midpoint
125: * W(j)= ( a_j + b_j)/2. The corresponding error is bounded by
126: * WERR(j) = abs( a_j - b_j)/2
127: *
128: * WERR (output) DOUBLE PRECISION array, dimension (N)
129: * The error bound on the corresponding eigenvalue approximation
130: * in W.
131: *
132: * WL (output) DOUBLE PRECISION
133: * WU (output) DOUBLE PRECISION
134: * The interval (WL, WU] contains all the wanted eigenvalues.
135: * If RANGE='V', then WL=VL and WU=VU.
136: * If RANGE='A', then WL and WU are the global Gerschgorin bounds
137: * on the spectrum.
138: * If RANGE='I', then WL and WU are computed by DLAEBZ from the
139: * index range specified.
140: *
141: * IBLOCK (output) INTEGER array, dimension (N)
142: * At each row/column j where E(j) is zero or small, the
143: * matrix T is considered to split into a block diagonal
144: * matrix. On exit, if INFO = 0, IBLOCK(i) specifies to which
145: * block (from 1 to the number of blocks) the eigenvalue W(i)
146: * belongs. (DLARRD may use the remaining N-M elements as
147: * workspace.)
148: *
149: * INDEXW (output) INTEGER array, dimension (N)
150: * The indices of the eigenvalues within each block (submatrix);
151: * for example, INDEXW(i)= j and IBLOCK(i)=k imply that the
152: * i-th eigenvalue W(i) is the j-th eigenvalue in block k.
153: *
154: * WORK (workspace) DOUBLE PRECISION array, dimension (4*N)
155: *
156: * IWORK (workspace) INTEGER array, dimension (3*N)
157: *
158: * INFO (output) INTEGER
159: * = 0: successful exit
160: * < 0: if INFO = -i, the i-th argument had an illegal value
161: * > 0: some or all of the eigenvalues failed to converge or
162: * were not computed:
163: * =1 or 3: Bisection failed to converge for some
164: * eigenvalues; these eigenvalues are flagged by a
165: * negative block number. The effect is that the
166: * eigenvalues may not be as accurate as the
167: * absolute and relative tolerances. This is
168: * generally caused by unexpectedly inaccurate
169: * arithmetic.
170: * =2 or 3: RANGE='I' only: Not all of the eigenvalues
171: * IL:IU were found.
172: * Effect: M < IU+1-IL
173: * Cause: non-monotonic arithmetic, causing the
174: * Sturm sequence to be non-monotonic.
175: * Cure: recalculate, using RANGE='A', and pick
176: * out eigenvalues IL:IU. In some cases,
177: * increasing the PARAMETER "FUDGE" may
178: * make things work.
179: * = 4: RANGE='I', and the Gershgorin interval
180: * initially used was too small. No eigenvalues
181: * were computed.
182: * Probable cause: your machine has sloppy
183: * floating-point arithmetic.
184: * Cure: Increase the PARAMETER "FUDGE",
185: * recompile, and try again.
186: *
187: * Internal Parameters
188: * ===================
189: *
190: * FUDGE DOUBLE PRECISION, default = 2
191: * A "fudge factor" to widen the Gershgorin intervals. Ideally,
192: * a value of 1 should work, but on machines with sloppy
193: * arithmetic, this needs to be larger. The default for
194: * publicly released versions should be large enough to handle
195: * the worst machine around. Note that this has no effect
196: * on accuracy of the solution.
197: *
198: * Based on contributions by
199: * W. Kahan, University of California, Berkeley, USA
200: * Beresford Parlett, University of California, Berkeley, USA
201: * Jim Demmel, University of California, Berkeley, USA
202: * Inderjit Dhillon, University of Texas, Austin, USA
203: * Osni Marques, LBNL/NERSC, USA
204: * Christof Voemel, University of California, Berkeley, USA
205: *
206: * =====================================================================
207: *
208: * .. Parameters ..
209: DOUBLE PRECISION ZERO, ONE, TWO, HALF, FUDGE
210: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0,
211: $ TWO = 2.0D0, HALF = ONE/TWO,
212: $ FUDGE = TWO )
213: INTEGER ALLRNG, VALRNG, INDRNG
214: PARAMETER ( ALLRNG = 1, VALRNG = 2, INDRNG = 3 )
215: * ..
216: * .. Local Scalars ..
217: LOGICAL NCNVRG, TOOFEW
218: INTEGER I, IB, IBEGIN, IDISCL, IDISCU, IE, IEND, IINFO,
219: $ IM, IN, IOFF, IOUT, IRANGE, ITMAX, ITMP1,
220: $ ITMP2, IW, IWOFF, J, JBLK, JDISC, JE, JEE, NB,
221: $ NWL, NWU
222: DOUBLE PRECISION ATOLI, EPS, GL, GU, RTOLI, TMP1, TMP2,
223: $ TNORM, UFLOW, WKILL, WLU, WUL
224:
225: * ..
226: * .. Local Arrays ..
227: INTEGER IDUMMA( 1 )
228: * ..
229: * .. External Functions ..
230: LOGICAL LSAME
231: INTEGER ILAENV
232: DOUBLE PRECISION DLAMCH
233: EXTERNAL LSAME, ILAENV, DLAMCH
234: * ..
235: * .. External Subroutines ..
236: EXTERNAL DLAEBZ
237: * ..
238: * .. Intrinsic Functions ..
239: INTRINSIC ABS, INT, LOG, MAX, MIN
240: * ..
241: * .. Executable Statements ..
242: *
243: INFO = 0
244: *
245: * Decode RANGE
246: *
247: IF( LSAME( RANGE, 'A' ) ) THEN
248: IRANGE = ALLRNG
249: ELSE IF( LSAME( RANGE, 'V' ) ) THEN
250: IRANGE = VALRNG
251: ELSE IF( LSAME( RANGE, 'I' ) ) THEN
252: IRANGE = INDRNG
253: ELSE
254: IRANGE = 0
255: END IF
256: *
257: * Check for Errors
258: *
259: IF( IRANGE.LE.0 ) THEN
260: INFO = -1
261: ELSE IF( .NOT.(LSAME(ORDER,'B').OR.LSAME(ORDER,'E')) ) THEN
262: INFO = -2
263: ELSE IF( N.LT.0 ) THEN
264: INFO = -3
265: ELSE IF( IRANGE.EQ.VALRNG ) THEN
266: IF( VL.GE.VU )
267: $ INFO = -5
268: ELSE IF( IRANGE.EQ.INDRNG .AND.
269: $ ( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) ) THEN
270: INFO = -6
271: ELSE IF( IRANGE.EQ.INDRNG .AND.
272: $ ( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) ) THEN
273: INFO = -7
274: END IF
275: *
276: IF( INFO.NE.0 ) THEN
277: RETURN
278: END IF
279:
280: * Initialize error flags
281: INFO = 0
282: NCNVRG = .FALSE.
283: TOOFEW = .FALSE.
284:
285: * Quick return if possible
286: M = 0
287: IF( N.EQ.0 ) RETURN
288:
289: * Simplification:
290: IF( IRANGE.EQ.INDRNG .AND. IL.EQ.1 .AND. IU.EQ.N ) IRANGE = 1
291:
292: * Get machine constants
293: EPS = DLAMCH( 'P' )
294: UFLOW = DLAMCH( 'U' )
295:
296:
297: * Special Case when N=1
298: * Treat case of 1x1 matrix for quick return
299: IF( N.EQ.1 ) THEN
300: IF( (IRANGE.EQ.ALLRNG).OR.
301: $ ((IRANGE.EQ.VALRNG).AND.(D(1).GT.VL).AND.(D(1).LE.VU)).OR.
302: $ ((IRANGE.EQ.INDRNG).AND.(IL.EQ.1).AND.(IU.EQ.1)) ) THEN
303: M = 1
304: W(1) = D(1)
305: * The computation error of the eigenvalue is zero
306: WERR(1) = ZERO
307: IBLOCK( 1 ) = 1
308: INDEXW( 1 ) = 1
309: ENDIF
310: RETURN
311: END IF
312:
313: * NB is the minimum vector length for vector bisection, or 0
314: * if only scalar is to be done.
315: NB = ILAENV( 1, 'DSTEBZ', ' ', N, -1, -1, -1 )
316: IF( NB.LE.1 ) NB = 0
317:
318: * Find global spectral radius
319: GL = D(1)
320: GU = D(1)
321: DO 5 I = 1,N
322: GL = MIN( GL, GERS( 2*I - 1))
323: GU = MAX( GU, GERS(2*I) )
324: 5 CONTINUE
325: * Compute global Gerschgorin bounds and spectral diameter
326: TNORM = MAX( ABS( GL ), ABS( GU ) )
327: GL = GL - FUDGE*TNORM*EPS*N - FUDGE*TWO*PIVMIN
328: GU = GU + FUDGE*TNORM*EPS*N + FUDGE*TWO*PIVMIN
329: * [JAN/28/2009] remove the line below since SPDIAM variable not use
330: * SPDIAM = GU - GL
331: * Input arguments for DLAEBZ:
332: * The relative tolerance. An interval (a,b] lies within
333: * "relative tolerance" if b-a < RELTOL*max(|a|,|b|),
334: RTOLI = RELTOL
335: * Set the absolute tolerance for interval convergence to zero to force
336: * interval convergence based on relative size of the interval.
337: * This is dangerous because intervals might not converge when RELTOL is
338: * small. But at least a very small number should be selected so that for
339: * strongly graded matrices, the code can get relatively accurate
340: * eigenvalues.
341: ATOLI = FUDGE*TWO*UFLOW + FUDGE*TWO*PIVMIN
342:
343: IF( IRANGE.EQ.INDRNG ) THEN
344:
345: * RANGE='I': Compute an interval containing eigenvalues
346: * IL through IU. The initial interval [GL,GU] from the global
347: * Gerschgorin bounds GL and GU is refined by DLAEBZ.
348: ITMAX = INT( ( LOG( TNORM+PIVMIN )-LOG( PIVMIN ) ) /
349: $ LOG( TWO ) ) + 2
350: WORK( N+1 ) = GL
351: WORK( N+2 ) = GL
352: WORK( N+3 ) = GU
353: WORK( N+4 ) = GU
354: WORK( N+5 ) = GL
355: WORK( N+6 ) = GU
356: IWORK( 1 ) = -1
357: IWORK( 2 ) = -1
358: IWORK( 3 ) = N + 1
359: IWORK( 4 ) = N + 1
360: IWORK( 5 ) = IL - 1
361: IWORK( 6 ) = IU
362: *
363: CALL DLAEBZ( 3, ITMAX, N, 2, 2, NB, ATOLI, RTOLI, PIVMIN,
364: $ D, E, E2, IWORK( 5 ), WORK( N+1 ), WORK( N+5 ), IOUT,
365: $ IWORK, W, IBLOCK, IINFO )
366: IF( IINFO .NE. 0 ) THEN
367: INFO = IINFO
368: RETURN
369: END IF
370: * On exit, output intervals may not be ordered by ascending negcount
371: IF( IWORK( 6 ).EQ.IU ) THEN
372: WL = WORK( N+1 )
373: WLU = WORK( N+3 )
374: NWL = IWORK( 1 )
375: WU = WORK( N+4 )
376: WUL = WORK( N+2 )
377: NWU = IWORK( 4 )
378: ELSE
379: WL = WORK( N+2 )
380: WLU = WORK( N+4 )
381: NWL = IWORK( 2 )
382: WU = WORK( N+3 )
383: WUL = WORK( N+1 )
384: NWU = IWORK( 3 )
385: END IF
386: * On exit, the interval [WL, WLU] contains a value with negcount NWL,
387: * and [WUL, WU] contains a value with negcount NWU.
388: IF( NWL.LT.0 .OR. NWL.GE.N .OR. NWU.LT.1 .OR. NWU.GT.N ) THEN
389: INFO = 4
390: RETURN
391: END IF
392:
393: ELSEIF( IRANGE.EQ.VALRNG ) THEN
394: WL = VL
395: WU = VU
396:
397: ELSEIF( IRANGE.EQ.ALLRNG ) THEN
398: WL = GL
399: WU = GU
400: ENDIF
401:
402:
403:
404: * Find Eigenvalues -- Loop Over blocks and recompute NWL and NWU.
405: * NWL accumulates the number of eigenvalues .le. WL,
406: * NWU accumulates the number of eigenvalues .le. WU
407: M = 0
408: IEND = 0
409: INFO = 0
410: NWL = 0
411: NWU = 0
412: *
413: DO 70 JBLK = 1, NSPLIT
414: IOFF = IEND
415: IBEGIN = IOFF + 1
416: IEND = ISPLIT( JBLK )
417: IN = IEND - IOFF
418: *
419: IF( IN.EQ.1 ) THEN
420: * 1x1 block
421: IF( WL.GE.D( IBEGIN )-PIVMIN )
422: $ NWL = NWL + 1
423: IF( WU.GE.D( IBEGIN )-PIVMIN )
424: $ NWU = NWU + 1
425: IF( IRANGE.EQ.ALLRNG .OR.
426: $ ( WL.LT.D( IBEGIN )-PIVMIN
427: $ .AND. WU.GE. D( IBEGIN )-PIVMIN ) ) THEN
428: M = M + 1
429: W( M ) = D( IBEGIN )
430: WERR(M) = ZERO
431: * The gap for a single block doesn't matter for the later
432: * algorithm and is assigned an arbitrary large value
433: IBLOCK( M ) = JBLK
434: INDEXW( M ) = 1
435: END IF
436:
437: * Disabled 2x2 case because of a failure on the following matrix
438: * RANGE = 'I', IL = IU = 4
439: * Original Tridiagonal, d = [
440: * -0.150102010615740E+00
441: * -0.849897989384260E+00
442: * -0.128208148052635E-15
443: * 0.128257718286320E-15
444: * ];
445: * e = [
446: * -0.357171383266986E+00
447: * -0.180411241501588E-15
448: * -0.175152352710251E-15
449: * ];
450: *
451: * ELSE IF( IN.EQ.2 ) THEN
452: ** 2x2 block
453: * DISC = SQRT( (HALF*(D(IBEGIN)-D(IEND)))**2 + E(IBEGIN)**2 )
454: * TMP1 = HALF*(D(IBEGIN)+D(IEND))
455: * L1 = TMP1 - DISC
456: * IF( WL.GE. L1-PIVMIN )
457: * $ NWL = NWL + 1
458: * IF( WU.GE. L1-PIVMIN )
459: * $ NWU = NWU + 1
460: * IF( IRANGE.EQ.ALLRNG .OR. ( WL.LT.L1-PIVMIN .AND. WU.GE.
461: * $ L1-PIVMIN ) ) THEN
462: * M = M + 1
463: * W( M ) = L1
464: ** The uncertainty of eigenvalues of a 2x2 matrix is very small
465: * WERR( M ) = EPS * ABS( W( M ) ) * TWO
466: * IBLOCK( M ) = JBLK
467: * INDEXW( M ) = 1
468: * ENDIF
469: * L2 = TMP1 + DISC
470: * IF( WL.GE. L2-PIVMIN )
471: * $ NWL = NWL + 1
472: * IF( WU.GE. L2-PIVMIN )
473: * $ NWU = NWU + 1
474: * IF( IRANGE.EQ.ALLRNG .OR. ( WL.LT.L2-PIVMIN .AND. WU.GE.
475: * $ L2-PIVMIN ) ) THEN
476: * M = M + 1
477: * W( M ) = L2
478: ** The uncertainty of eigenvalues of a 2x2 matrix is very small
479: * WERR( M ) = EPS * ABS( W( M ) ) * TWO
480: * IBLOCK( M ) = JBLK
481: * INDEXW( M ) = 2
482: * ENDIF
483: ELSE
484: * General Case - block of size IN >= 2
485: * Compute local Gerschgorin interval and use it as the initial
486: * interval for DLAEBZ
487: GU = D( IBEGIN )
488: GL = D( IBEGIN )
489: TMP1 = ZERO
490:
491: DO 40 J = IBEGIN, IEND
492: GL = MIN( GL, GERS( 2*J - 1))
493: GU = MAX( GU, GERS(2*J) )
494: 40 CONTINUE
495: * [JAN/28/2009]
496: * change SPDIAM by TNORM in lines 2 and 3 thereafter
497: * line 1: remove computation of SPDIAM (not useful anymore)
498: * SPDIAM = GU - GL
499: * GL = GL - FUDGE*SPDIAM*EPS*IN - FUDGE*PIVMIN
500: * GU = GU + FUDGE*SPDIAM*EPS*IN + FUDGE*PIVMIN
501: GL = GL - FUDGE*TNORM*EPS*IN - FUDGE*PIVMIN
502: GU = GU + FUDGE*TNORM*EPS*IN + FUDGE*PIVMIN
503: *
504: IF( IRANGE.GT.1 ) THEN
505: IF( GU.LT.WL ) THEN
506: * the local block contains none of the wanted eigenvalues
507: NWL = NWL + IN
508: NWU = NWU + IN
509: GO TO 70
510: END IF
511: * refine search interval if possible, only range (WL,WU] matters
512: GL = MAX( GL, WL )
513: GU = MIN( GU, WU )
514: IF( GL.GE.GU )
515: $ GO TO 70
516: END IF
517:
518: * Find negcount of initial interval boundaries GL and GU
519: WORK( N+1 ) = GL
520: WORK( N+IN+1 ) = GU
521: CALL DLAEBZ( 1, 0, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN,
522: $ D( IBEGIN ), E( IBEGIN ), E2( IBEGIN ),
523: $ IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IM,
524: $ IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO )
525: IF( IINFO .NE. 0 ) THEN
526: INFO = IINFO
527: RETURN
528: END IF
529: *
530: NWL = NWL + IWORK( 1 )
531: NWU = NWU + IWORK( IN+1 )
532: IWOFF = M - IWORK( 1 )
533:
534: * Compute Eigenvalues
535: ITMAX = INT( ( LOG( GU-GL+PIVMIN )-LOG( PIVMIN ) ) /
536: $ LOG( TWO ) ) + 2
537: CALL DLAEBZ( 2, ITMAX, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN,
538: $ D( IBEGIN ), E( IBEGIN ), E2( IBEGIN ),
539: $ IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IOUT,
540: $ IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO )
541: IF( IINFO .NE. 0 ) THEN
542: INFO = IINFO
543: RETURN
544: END IF
545: *
546: * Copy eigenvalues into W and IBLOCK
547: * Use -JBLK for block number for unconverged eigenvalues.
548: * Loop over the number of output intervals from DLAEBZ
549: DO 60 J = 1, IOUT
550: * eigenvalue approximation is middle point of interval
551: TMP1 = HALF*( WORK( J+N )+WORK( J+IN+N ) )
552: * semi length of error interval
553: TMP2 = HALF*ABS( WORK( J+N )-WORK( J+IN+N ) )
554: IF( J.GT.IOUT-IINFO ) THEN
555: * Flag non-convergence.
556: NCNVRG = .TRUE.
557: IB = -JBLK
558: ELSE
559: IB = JBLK
560: END IF
561: DO 50 JE = IWORK( J ) + 1 + IWOFF,
562: $ IWORK( J+IN ) + IWOFF
563: W( JE ) = TMP1
564: WERR( JE ) = TMP2
565: INDEXW( JE ) = JE - IWOFF
566: IBLOCK( JE ) = IB
567: 50 CONTINUE
568: 60 CONTINUE
569: *
570: M = M + IM
571: END IF
572: 70 CONTINUE
573:
574: * If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU
575: * If NWL+1 < IL or NWU > IU, discard extra eigenvalues.
576: IF( IRANGE.EQ.INDRNG ) THEN
577: IDISCL = IL - 1 - NWL
578: IDISCU = NWU - IU
579: *
580: IF( IDISCL.GT.0 ) THEN
581: IM = 0
582: DO 80 JE = 1, M
583: * Remove some of the smallest eigenvalues from the left so that
584: * at the end IDISCL =0. Move all eigenvalues up to the left.
585: IF( W( JE ).LE.WLU .AND. IDISCL.GT.0 ) THEN
586: IDISCL = IDISCL - 1
587: ELSE
588: IM = IM + 1
589: W( IM ) = W( JE )
590: WERR( IM ) = WERR( JE )
591: INDEXW( IM ) = INDEXW( JE )
592: IBLOCK( IM ) = IBLOCK( JE )
593: END IF
594: 80 CONTINUE
595: M = IM
596: END IF
597: IF( IDISCU.GT.0 ) THEN
598: * Remove some of the largest eigenvalues from the right so that
599: * at the end IDISCU =0. Move all eigenvalues up to the left.
600: IM=M+1
601: DO 81 JE = M, 1, -1
602: IF( W( JE ).GE.WUL .AND. IDISCU.GT.0 ) THEN
603: IDISCU = IDISCU - 1
604: ELSE
605: IM = IM - 1
606: W( IM ) = W( JE )
607: WERR( IM ) = WERR( JE )
608: INDEXW( IM ) = INDEXW( JE )
609: IBLOCK( IM ) = IBLOCK( JE )
610: END IF
611: 81 CONTINUE
612: JEE = 0
613: DO 82 JE = IM, M
614: JEE = JEE + 1
615: W( JEE ) = W( JE )
616: WERR( JEE ) = WERR( JE )
617: INDEXW( JEE ) = INDEXW( JE )
618: IBLOCK( JEE ) = IBLOCK( JE )
619: 82 CONTINUE
620: M = M-IM+1
621: END IF
622:
623: IF( IDISCL.GT.0 .OR. IDISCU.GT.0 ) THEN
624: * Code to deal with effects of bad arithmetic. (If N(w) is
625: * monotone non-decreasing, this should never happen.)
626: * Some low eigenvalues to be discarded are not in (WL,WLU],
627: * or high eigenvalues to be discarded are not in (WUL,WU]
628: * so just kill off the smallest IDISCL/largest IDISCU
629: * eigenvalues, by marking the corresponding IBLOCK = 0
630: IF( IDISCL.GT.0 ) THEN
631: WKILL = WU
632: DO 100 JDISC = 1, IDISCL
633: IW = 0
634: DO 90 JE = 1, M
635: IF( IBLOCK( JE ).NE.0 .AND.
636: $ ( W( JE ).LT.WKILL .OR. IW.EQ.0 ) ) THEN
637: IW = JE
638: WKILL = W( JE )
639: END IF
640: 90 CONTINUE
641: IBLOCK( IW ) = 0
642: 100 CONTINUE
643: END IF
644: IF( IDISCU.GT.0 ) THEN
645: WKILL = WL
646: DO 120 JDISC = 1, IDISCU
647: IW = 0
648: DO 110 JE = 1, M
649: IF( IBLOCK( JE ).NE.0 .AND.
650: $ ( W( JE ).GE.WKILL .OR. IW.EQ.0 ) ) THEN
651: IW = JE
652: WKILL = W( JE )
653: END IF
654: 110 CONTINUE
655: IBLOCK( IW ) = 0
656: 120 CONTINUE
657: END IF
658: * Now erase all eigenvalues with IBLOCK set to zero
659: IM = 0
660: DO 130 JE = 1, M
661: IF( IBLOCK( JE ).NE.0 ) THEN
662: IM = IM + 1
663: W( IM ) = W( JE )
664: WERR( IM ) = WERR( JE )
665: INDEXW( IM ) = INDEXW( JE )
666: IBLOCK( IM ) = IBLOCK( JE )
667: END IF
668: 130 CONTINUE
669: M = IM
670: END IF
671: IF( IDISCL.LT.0 .OR. IDISCU.LT.0 ) THEN
672: TOOFEW = .TRUE.
673: END IF
674: END IF
675: *
676: IF(( IRANGE.EQ.ALLRNG .AND. M.NE.N ).OR.
677: $ ( IRANGE.EQ.INDRNG .AND. M.NE.IU-IL+1 ) ) THEN
678: TOOFEW = .TRUE.
679: END IF
680:
681: * If ORDER='B', do nothing the eigenvalues are already sorted by
682: * block.
683: * If ORDER='E', sort the eigenvalues from smallest to largest
684:
685: IF( LSAME(ORDER,'E') .AND. NSPLIT.GT.1 ) THEN
686: DO 150 JE = 1, M - 1
687: IE = 0
688: TMP1 = W( JE )
689: DO 140 J = JE + 1, M
690: IF( W( J ).LT.TMP1 ) THEN
691: IE = J
692: TMP1 = W( J )
693: END IF
694: 140 CONTINUE
695: IF( IE.NE.0 ) THEN
696: TMP2 = WERR( IE )
697: ITMP1 = IBLOCK( IE )
698: ITMP2 = INDEXW( IE )
699: W( IE ) = W( JE )
700: WERR( IE ) = WERR( JE )
701: IBLOCK( IE ) = IBLOCK( JE )
702: INDEXW( IE ) = INDEXW( JE )
703: W( JE ) = TMP1
704: WERR( JE ) = TMP2
705: IBLOCK( JE ) = ITMP1
706: INDEXW( JE ) = ITMP2
707: END IF
708: 150 CONTINUE
709: END IF
710: *
711: INFO = 0
712: IF( NCNVRG )
713: $ INFO = INFO + 1
714: IF( TOOFEW )
715: $ INFO = INFO + 2
716: RETURN
717: *
718: * End of DLARRD
719: *
720: END
CVSweb interface <joel.bertrand@systella.fr>