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