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