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