Annotation of rpl/lapack/lapack/dlarrd.f, revision 1.19
1.12 bertrand 1: *> \brief \b DLARRD computes the eigenvalues of a symmetric tridiagonal matrix to suitable accuracy.
1.9 bertrand 2: *
3: * =========== DOCUMENTATION ===========
4: *
1.17 bertrand 5: * Online html documentation available at
6: * http://www.netlib.org/lapack/explore-html/
1.9 bertrand 7: *
8: *> \htmlonly
1.17 bertrand 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">
1.9 bertrand 15: *> [TXT]</a>
1.17 bertrand 16: *> \endhtmlonly
1.9 bertrand 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 )
1.17 bertrand 25: *
1.9 bertrand 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: * ..
1.17 bertrand 37: *
1.9 bertrand 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
1.15 bertrand 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'.
1.9 bertrand 99: *> \endverbatim
100: *>
101: *> \param[in] VU
102: *> \verbatim
103: *> VU is DOUBLE PRECISION
1.15 bertrand 104: *> If RANGE='V', the upper bound of the interval to
1.9 bertrand 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
1.15 bertrand 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'.
1.9 bertrand 117: *> \endverbatim
118: *>
119: *> \param[in] IU
120: *> \verbatim
121: *> IU is INTEGER
1.15 bertrand 122: *> If RANGE='I', the index of the
123: *> largest eigenvalue to be returned.
1.9 bertrand 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: *
1.17 bertrand 317: *> \author Univ. of Tennessee
318: *> \author Univ. of California Berkeley
319: *> \author Univ. of Colorado Denver
320: *> \author NAG Ltd.
1.9 bertrand 321: *
1.15 bertrand 322: *> \date June 2016
1.9 bertrand 323: *
1.17 bertrand 324: *> \ingroup OTHERauxiliary
1.9 bertrand 325: *
326: * =====================================================================
1.1 bertrand 327: SUBROUTINE DLARRD( RANGE, ORDER, N, VL, VU, IL, IU, GERS,
328: $ RELTOL, D, E, E2, PIVMIN, NSPLIT, ISPLIT,
329: $ M, W, WERR, WL, WU, IBLOCK, INDEXW,
330: $ WORK, IWORK, INFO )
331: *
1.19 ! bertrand 332: * -- LAPACK auxiliary routine (version 3.7.1) --
1.1 bertrand 333: * -- LAPACK is a software package provided by Univ. of Tennessee, --
334: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
1.15 bertrand 335: * June 2016
1.1 bertrand 336: *
337: * .. Scalar Arguments ..
338: CHARACTER ORDER, RANGE
339: INTEGER IL, INFO, IU, M, N, NSPLIT
340: DOUBLE PRECISION PIVMIN, RELTOL, VL, VU, WL, WU
341: * ..
342: * .. Array Arguments ..
343: INTEGER IBLOCK( * ), INDEXW( * ),
344: $ ISPLIT( * ), IWORK( * )
345: DOUBLE PRECISION D( * ), E( * ), E2( * ),
346: $ GERS( * ), W( * ), WERR( * ), WORK( * )
347: * ..
348: *
349: * =====================================================================
350: *
351: * .. Parameters ..
352: DOUBLE PRECISION ZERO, ONE, TWO, HALF, FUDGE
353: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0,
354: $ TWO = 2.0D0, HALF = ONE/TWO,
355: $ FUDGE = TWO )
356: INTEGER ALLRNG, VALRNG, INDRNG
357: PARAMETER ( ALLRNG = 1, VALRNG = 2, INDRNG = 3 )
358: * ..
359: * .. Local Scalars ..
360: LOGICAL NCNVRG, TOOFEW
361: INTEGER I, IB, IBEGIN, IDISCL, IDISCU, IE, IEND, IINFO,
362: $ IM, IN, IOFF, IOUT, IRANGE, ITMAX, ITMP1,
363: $ ITMP2, IW, IWOFF, J, JBLK, JDISC, JE, JEE, NB,
364: $ NWL, NWU
365: DOUBLE PRECISION ATOLI, EPS, GL, GU, RTOLI, TMP1, TMP2,
366: $ TNORM, UFLOW, WKILL, WLU, WUL
367:
368: * ..
369: * .. Local Arrays ..
370: INTEGER IDUMMA( 1 )
371: * ..
372: * .. External Functions ..
373: LOGICAL LSAME
374: INTEGER ILAENV
375: DOUBLE PRECISION DLAMCH
376: EXTERNAL LSAME, ILAENV, DLAMCH
377: * ..
378: * .. External Subroutines ..
379: EXTERNAL DLAEBZ
380: * ..
381: * .. Intrinsic Functions ..
382: INTRINSIC ABS, INT, LOG, MAX, MIN
383: * ..
384: * .. Executable Statements ..
385: *
386: INFO = 0
387: *
1.19 ! bertrand 388: * Quick return if possible
! 389: *
! 390: IF( N.LE.0 ) THEN
! 391: RETURN
! 392: END IF
! 393: *
1.1 bertrand 394: * Decode RANGE
395: *
396: IF( LSAME( RANGE, 'A' ) ) THEN
397: IRANGE = ALLRNG
398: ELSE IF( LSAME( RANGE, 'V' ) ) THEN
399: IRANGE = VALRNG
400: ELSE IF( LSAME( RANGE, 'I' ) ) THEN
401: IRANGE = INDRNG
402: ELSE
403: IRANGE = 0
404: END IF
405: *
406: * Check for Errors
407: *
408: IF( IRANGE.LE.0 ) THEN
409: INFO = -1
410: ELSE IF( .NOT.(LSAME(ORDER,'B').OR.LSAME(ORDER,'E')) ) THEN
411: INFO = -2
412: ELSE IF( N.LT.0 ) THEN
413: INFO = -3
414: ELSE IF( IRANGE.EQ.VALRNG ) THEN
415: IF( VL.GE.VU )
416: $ INFO = -5
417: ELSE IF( IRANGE.EQ.INDRNG .AND.
418: $ ( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) ) THEN
419: INFO = -6
420: ELSE IF( IRANGE.EQ.INDRNG .AND.
421: $ ( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) ) THEN
422: INFO = -7
423: END IF
424: *
425: IF( INFO.NE.0 ) THEN
426: RETURN
427: END IF
428:
429: * Initialize error flags
430: INFO = 0
431: NCNVRG = .FALSE.
432: TOOFEW = .FALSE.
433:
434: * Quick return if possible
435: M = 0
436: IF( N.EQ.0 ) RETURN
437:
438: * Simplification:
439: IF( IRANGE.EQ.INDRNG .AND. IL.EQ.1 .AND. IU.EQ.N ) IRANGE = 1
440:
441: * Get machine constants
442: EPS = DLAMCH( 'P' )
443: UFLOW = DLAMCH( 'U' )
444:
445:
446: * Special Case when N=1
447: * Treat case of 1x1 matrix for quick return
448: IF( N.EQ.1 ) THEN
449: IF( (IRANGE.EQ.ALLRNG).OR.
450: $ ((IRANGE.EQ.VALRNG).AND.(D(1).GT.VL).AND.(D(1).LE.VU)).OR.
451: $ ((IRANGE.EQ.INDRNG).AND.(IL.EQ.1).AND.(IU.EQ.1)) ) THEN
452: M = 1
453: W(1) = D(1)
454: * The computation error of the eigenvalue is zero
455: WERR(1) = ZERO
456: IBLOCK( 1 ) = 1
457: INDEXW( 1 ) = 1
458: ENDIF
459: RETURN
460: END IF
461:
462: * NB is the minimum vector length for vector bisection, or 0
463: * if only scalar is to be done.
464: NB = ILAENV( 1, 'DSTEBZ', ' ', N, -1, -1, -1 )
465: IF( NB.LE.1 ) NB = 0
466:
467: * Find global spectral radius
468: GL = D(1)
469: GU = D(1)
470: DO 5 I = 1,N
471: GL = MIN( GL, GERS( 2*I - 1))
472: GU = MAX( GU, GERS(2*I) )
473: 5 CONTINUE
474: * Compute global Gerschgorin bounds and spectral diameter
475: TNORM = MAX( ABS( GL ), ABS( GU ) )
476: GL = GL - FUDGE*TNORM*EPS*N - FUDGE*TWO*PIVMIN
477: GU = GU + FUDGE*TNORM*EPS*N + FUDGE*TWO*PIVMIN
478: * [JAN/28/2009] remove the line below since SPDIAM variable not use
479: * SPDIAM = GU - GL
480: * Input arguments for DLAEBZ:
481: * The relative tolerance. An interval (a,b] lies within
482: * "relative tolerance" if b-a < RELTOL*max(|a|,|b|),
483: RTOLI = RELTOL
484: * Set the absolute tolerance for interval convergence to zero to force
485: * interval convergence based on relative size of the interval.
486: * This is dangerous because intervals might not converge when RELTOL is
487: * small. But at least a very small number should be selected so that for
488: * strongly graded matrices, the code can get relatively accurate
489: * eigenvalues.
490: ATOLI = FUDGE*TWO*UFLOW + FUDGE*TWO*PIVMIN
491:
492: IF( IRANGE.EQ.INDRNG ) THEN
493:
494: * RANGE='I': Compute an interval containing eigenvalues
495: * IL through IU. The initial interval [GL,GU] from the global
496: * Gerschgorin bounds GL and GU is refined by DLAEBZ.
497: ITMAX = INT( ( LOG( TNORM+PIVMIN )-LOG( PIVMIN ) ) /
498: $ LOG( TWO ) ) + 2
499: WORK( N+1 ) = GL
500: WORK( N+2 ) = GL
501: WORK( N+3 ) = GU
502: WORK( N+4 ) = GU
503: WORK( N+5 ) = GL
504: WORK( N+6 ) = GU
505: IWORK( 1 ) = -1
506: IWORK( 2 ) = -1
507: IWORK( 3 ) = N + 1
508: IWORK( 4 ) = N + 1
509: IWORK( 5 ) = IL - 1
510: IWORK( 6 ) = IU
511: *
512: CALL DLAEBZ( 3, ITMAX, N, 2, 2, NB, ATOLI, RTOLI, PIVMIN,
513: $ D, E, E2, IWORK( 5 ), WORK( N+1 ), WORK( N+5 ), IOUT,
514: $ IWORK, W, IBLOCK, IINFO )
515: IF( IINFO .NE. 0 ) THEN
516: INFO = IINFO
517: RETURN
518: END IF
519: * On exit, output intervals may not be ordered by ascending negcount
520: IF( IWORK( 6 ).EQ.IU ) THEN
521: WL = WORK( N+1 )
522: WLU = WORK( N+3 )
523: NWL = IWORK( 1 )
524: WU = WORK( N+4 )
525: WUL = WORK( N+2 )
526: NWU = IWORK( 4 )
527: ELSE
528: WL = WORK( N+2 )
529: WLU = WORK( N+4 )
530: NWL = IWORK( 2 )
531: WU = WORK( N+3 )
532: WUL = WORK( N+1 )
533: NWU = IWORK( 3 )
534: END IF
535: * On exit, the interval [WL, WLU] contains a value with negcount NWL,
536: * and [WUL, WU] contains a value with negcount NWU.
537: IF( NWL.LT.0 .OR. NWL.GE.N .OR. NWU.LT.1 .OR. NWU.GT.N ) THEN
538: INFO = 4
539: RETURN
540: END IF
541:
542: ELSEIF( IRANGE.EQ.VALRNG ) THEN
543: WL = VL
544: WU = VU
545:
546: ELSEIF( IRANGE.EQ.ALLRNG ) THEN
547: WL = GL
548: WU = GU
549: ENDIF
550:
551:
552:
553: * Find Eigenvalues -- Loop Over blocks and recompute NWL and NWU.
554: * NWL accumulates the number of eigenvalues .le. WL,
555: * NWU accumulates the number of eigenvalues .le. WU
556: M = 0
557: IEND = 0
558: INFO = 0
559: NWL = 0
560: NWU = 0
561: *
562: DO 70 JBLK = 1, NSPLIT
563: IOFF = IEND
564: IBEGIN = IOFF + 1
565: IEND = ISPLIT( JBLK )
566: IN = IEND - IOFF
567: *
568: IF( IN.EQ.1 ) THEN
569: * 1x1 block
570: IF( WL.GE.D( IBEGIN )-PIVMIN )
571: $ NWL = NWL + 1
572: IF( WU.GE.D( IBEGIN )-PIVMIN )
573: $ NWU = NWU + 1
574: IF( IRANGE.EQ.ALLRNG .OR.
575: $ ( WL.LT.D( IBEGIN )-PIVMIN
576: $ .AND. WU.GE. D( IBEGIN )-PIVMIN ) ) THEN
577: M = M + 1
578: W( M ) = D( IBEGIN )
579: WERR(M) = ZERO
580: * The gap for a single block doesn't matter for the later
581: * algorithm and is assigned an arbitrary large value
582: IBLOCK( M ) = JBLK
583: INDEXW( M ) = 1
584: END IF
585:
586: * Disabled 2x2 case because of a failure on the following matrix
587: * RANGE = 'I', IL = IU = 4
588: * Original Tridiagonal, d = [
589: * -0.150102010615740E+00
590: * -0.849897989384260E+00
591: * -0.128208148052635E-15
592: * 0.128257718286320E-15
593: * ];
594: * e = [
595: * -0.357171383266986E+00
596: * -0.180411241501588E-15
597: * -0.175152352710251E-15
598: * ];
599: *
600: * ELSE IF( IN.EQ.2 ) THEN
601: ** 2x2 block
602: * DISC = SQRT( (HALF*(D(IBEGIN)-D(IEND)))**2 + E(IBEGIN)**2 )
603: * TMP1 = HALF*(D(IBEGIN)+D(IEND))
604: * L1 = TMP1 - DISC
605: * IF( WL.GE. L1-PIVMIN )
606: * $ NWL = NWL + 1
607: * IF( WU.GE. L1-PIVMIN )
608: * $ NWU = NWU + 1
609: * IF( IRANGE.EQ.ALLRNG .OR. ( WL.LT.L1-PIVMIN .AND. WU.GE.
610: * $ L1-PIVMIN ) ) THEN
611: * M = M + 1
612: * W( M ) = L1
613: ** The uncertainty of eigenvalues of a 2x2 matrix is very small
614: * WERR( M ) = EPS * ABS( W( M ) ) * TWO
615: * IBLOCK( M ) = JBLK
616: * INDEXW( M ) = 1
617: * ENDIF
618: * L2 = TMP1 + DISC
619: * IF( WL.GE. L2-PIVMIN )
620: * $ NWL = NWL + 1
621: * IF( WU.GE. L2-PIVMIN )
622: * $ NWU = NWU + 1
623: * IF( IRANGE.EQ.ALLRNG .OR. ( WL.LT.L2-PIVMIN .AND. WU.GE.
624: * $ L2-PIVMIN ) ) THEN
625: * M = M + 1
626: * W( M ) = L2
627: ** The uncertainty of eigenvalues of a 2x2 matrix is very small
628: * WERR( M ) = EPS * ABS( W( M ) ) * TWO
629: * IBLOCK( M ) = JBLK
630: * INDEXW( M ) = 2
631: * ENDIF
632: ELSE
633: * General Case - block of size IN >= 2
634: * Compute local Gerschgorin interval and use it as the initial
635: * interval for DLAEBZ
636: GU = D( IBEGIN )
637: GL = D( IBEGIN )
638: TMP1 = ZERO
639:
640: DO 40 J = IBEGIN, IEND
641: GL = MIN( GL, GERS( 2*J - 1))
642: GU = MAX( GU, GERS(2*J) )
643: 40 CONTINUE
644: * [JAN/28/2009]
645: * change SPDIAM by TNORM in lines 2 and 3 thereafter
646: * line 1: remove computation of SPDIAM (not useful anymore)
647: * SPDIAM = GU - GL
648: * GL = GL - FUDGE*SPDIAM*EPS*IN - FUDGE*PIVMIN
649: * GU = GU + FUDGE*SPDIAM*EPS*IN + FUDGE*PIVMIN
650: GL = GL - FUDGE*TNORM*EPS*IN - FUDGE*PIVMIN
651: GU = GU + FUDGE*TNORM*EPS*IN + FUDGE*PIVMIN
652: *
653: IF( IRANGE.GT.1 ) THEN
654: IF( GU.LT.WL ) THEN
655: * the local block contains none of the wanted eigenvalues
656: NWL = NWL + IN
657: NWU = NWU + IN
658: GO TO 70
659: END IF
660: * refine search interval if possible, only range (WL,WU] matters
661: GL = MAX( GL, WL )
662: GU = MIN( GU, WU )
663: IF( GL.GE.GU )
664: $ GO TO 70
665: END IF
666:
667: * Find negcount of initial interval boundaries GL and GU
668: WORK( N+1 ) = GL
669: WORK( N+IN+1 ) = GU
670: CALL DLAEBZ( 1, 0, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN,
671: $ D( IBEGIN ), E( IBEGIN ), E2( IBEGIN ),
672: $ IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IM,
673: $ IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO )
674: IF( IINFO .NE. 0 ) THEN
675: INFO = IINFO
676: RETURN
677: END IF
678: *
679: NWL = NWL + IWORK( 1 )
680: NWU = NWU + IWORK( IN+1 )
681: IWOFF = M - IWORK( 1 )
682:
683: * Compute Eigenvalues
684: ITMAX = INT( ( LOG( GU-GL+PIVMIN )-LOG( PIVMIN ) ) /
685: $ LOG( TWO ) ) + 2
686: CALL DLAEBZ( 2, ITMAX, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN,
687: $ D( IBEGIN ), E( IBEGIN ), E2( IBEGIN ),
688: $ IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IOUT,
689: $ IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO )
690: IF( IINFO .NE. 0 ) THEN
691: INFO = IINFO
692: RETURN
693: END IF
694: *
695: * Copy eigenvalues into W and IBLOCK
696: * Use -JBLK for block number for unconverged eigenvalues.
697: * Loop over the number of output intervals from DLAEBZ
698: DO 60 J = 1, IOUT
699: * eigenvalue approximation is middle point of interval
700: TMP1 = HALF*( WORK( J+N )+WORK( J+IN+N ) )
701: * semi length of error interval
702: TMP2 = HALF*ABS( WORK( J+N )-WORK( J+IN+N ) )
703: IF( J.GT.IOUT-IINFO ) THEN
704: * Flag non-convergence.
705: NCNVRG = .TRUE.
706: IB = -JBLK
707: ELSE
708: IB = JBLK
709: END IF
710: DO 50 JE = IWORK( J ) + 1 + IWOFF,
711: $ IWORK( J+IN ) + IWOFF
712: W( JE ) = TMP1
713: WERR( JE ) = TMP2
714: INDEXW( JE ) = JE - IWOFF
715: IBLOCK( JE ) = IB
716: 50 CONTINUE
717: 60 CONTINUE
718: *
719: M = M + IM
720: END IF
721: 70 CONTINUE
722:
723: * If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU
724: * If NWL+1 < IL or NWU > IU, discard extra eigenvalues.
725: IF( IRANGE.EQ.INDRNG ) THEN
726: IDISCL = IL - 1 - NWL
727: IDISCU = NWU - IU
728: *
729: IF( IDISCL.GT.0 ) THEN
730: IM = 0
731: DO 80 JE = 1, M
732: * Remove some of the smallest eigenvalues from the left so that
733: * at the end IDISCL =0. Move all eigenvalues up to the left.
734: IF( W( JE ).LE.WLU .AND. IDISCL.GT.0 ) THEN
735: IDISCL = IDISCL - 1
736: ELSE
737: IM = IM + 1
738: W( IM ) = W( JE )
739: WERR( IM ) = WERR( JE )
740: INDEXW( IM ) = INDEXW( JE )
741: IBLOCK( IM ) = IBLOCK( JE )
742: END IF
743: 80 CONTINUE
744: M = IM
745: END IF
746: IF( IDISCU.GT.0 ) THEN
747: * Remove some of the largest eigenvalues from the right so that
748: * at the end IDISCU =0. Move all eigenvalues up to the left.
749: IM=M+1
750: DO 81 JE = M, 1, -1
751: IF( W( JE ).GE.WUL .AND. IDISCU.GT.0 ) THEN
752: IDISCU = IDISCU - 1
753: ELSE
754: IM = IM - 1
755: W( IM ) = W( JE )
756: WERR( IM ) = WERR( JE )
757: INDEXW( IM ) = INDEXW( JE )
758: IBLOCK( IM ) = IBLOCK( JE )
759: END IF
760: 81 CONTINUE
761: JEE = 0
762: DO 82 JE = IM, M
763: JEE = JEE + 1
764: W( JEE ) = W( JE )
765: WERR( JEE ) = WERR( JE )
766: INDEXW( JEE ) = INDEXW( JE )
767: IBLOCK( JEE ) = IBLOCK( JE )
768: 82 CONTINUE
769: M = M-IM+1
770: END IF
771:
772: IF( IDISCL.GT.0 .OR. IDISCU.GT.0 ) THEN
773: * Code to deal with effects of bad arithmetic. (If N(w) is
774: * monotone non-decreasing, this should never happen.)
775: * Some low eigenvalues to be discarded are not in (WL,WLU],
776: * or high eigenvalues to be discarded are not in (WUL,WU]
777: * so just kill off the smallest IDISCL/largest IDISCU
778: * eigenvalues, by marking the corresponding IBLOCK = 0
779: IF( IDISCL.GT.0 ) THEN
780: WKILL = WU
781: DO 100 JDISC = 1, IDISCL
782: IW = 0
783: DO 90 JE = 1, M
784: IF( IBLOCK( JE ).NE.0 .AND.
785: $ ( W( JE ).LT.WKILL .OR. IW.EQ.0 ) ) THEN
786: IW = JE
787: WKILL = W( JE )
788: END IF
789: 90 CONTINUE
790: IBLOCK( IW ) = 0
791: 100 CONTINUE
792: END IF
793: IF( IDISCU.GT.0 ) THEN
794: WKILL = WL
795: DO 120 JDISC = 1, IDISCU
796: IW = 0
797: DO 110 JE = 1, M
798: IF( IBLOCK( JE ).NE.0 .AND.
799: $ ( W( JE ).GE.WKILL .OR. IW.EQ.0 ) ) THEN
800: IW = JE
801: WKILL = W( JE )
802: END IF
803: 110 CONTINUE
804: IBLOCK( IW ) = 0
805: 120 CONTINUE
806: END IF
807: * Now erase all eigenvalues with IBLOCK set to zero
808: IM = 0
809: DO 130 JE = 1, M
810: IF( IBLOCK( JE ).NE.0 ) THEN
811: IM = IM + 1
812: W( IM ) = W( JE )
813: WERR( IM ) = WERR( JE )
814: INDEXW( IM ) = INDEXW( JE )
815: IBLOCK( IM ) = IBLOCK( JE )
816: END IF
817: 130 CONTINUE
818: M = IM
819: END IF
820: IF( IDISCL.LT.0 .OR. IDISCU.LT.0 ) THEN
821: TOOFEW = .TRUE.
822: END IF
823: END IF
824: *
825: IF(( IRANGE.EQ.ALLRNG .AND. M.NE.N ).OR.
826: $ ( IRANGE.EQ.INDRNG .AND. M.NE.IU-IL+1 ) ) THEN
827: TOOFEW = .TRUE.
828: END IF
829:
830: * If ORDER='B', do nothing the eigenvalues are already sorted by
831: * block.
832: * If ORDER='E', sort the eigenvalues from smallest to largest
833:
834: IF( LSAME(ORDER,'E') .AND. NSPLIT.GT.1 ) THEN
835: DO 150 JE = 1, M - 1
836: IE = 0
837: TMP1 = W( JE )
838: DO 140 J = JE + 1, M
839: IF( W( J ).LT.TMP1 ) THEN
840: IE = J
841: TMP1 = W( J )
842: END IF
843: 140 CONTINUE
844: IF( IE.NE.0 ) THEN
845: TMP2 = WERR( IE )
846: ITMP1 = IBLOCK( IE )
847: ITMP2 = INDEXW( IE )
848: W( IE ) = W( JE )
849: WERR( IE ) = WERR( JE )
850: IBLOCK( IE ) = IBLOCK( JE )
851: INDEXW( IE ) = INDEXW( JE )
852: W( JE ) = TMP1
853: WERR( JE ) = TMP2
854: IBLOCK( JE ) = ITMP1
855: INDEXW( JE ) = ITMP2
856: END IF
857: 150 CONTINUE
858: END IF
859: *
860: INFO = 0
861: IF( NCNVRG )
862: $ INFO = INFO + 1
863: IF( TOOFEW )
864: $ INFO = INFO + 2
865: RETURN
866: *
867: * End of DLARRD
868: *
869: END
CVSweb interface <joel.bertrand@systella.fr>