Routine: PSSTEBZ()  File: SRC\psstebz.f

 
 
# lines: 872
  # code: 872
  # comment: 0
  # blank:0
# Variables:116
# Callers:2
# Callings:4
# Words:633
# Keywords:402
 

 

..
     .. Array Arguments ..
     ..
  Purpose
  =======
  PSSTEBZ computes the eigenvalues of a symmetric tridiagonal matrix in
  parallel. The user may ask for all eigenvalues, all eigenvalues in
  the interval [VL, VU], or the eigenvalues indexed IL through IU. A
  static partitioning of work is done at the beginning of PSSTEBZ which
  results in all processes finding an (almost) equal number of
  eigenvalues.
  NOTE : It is assumed that the user is on an IEEE machine. If the user
         is not on an IEEE mchine, set the compile time flag NO_IEEE
         to 1 (in SLmake.inc). The features of IEEE arithmetic that
         are needed for the "fast" Sturm Count are : (a) infinity
         arithmetic (b) the sign bit of a double precision floating
         point number is assumed be in the 32nd or 64th bit position
         (c) the sign of negative zero.
  See W. Kahan "Accurate Eigenvalues of a Symmetric Tridiagonal
  Matrix", Report CS41, Computer Science Dept., Stanford
  University, July 21, 1966.
  Arguments
  =========
  ICTXT   (global input) INTEGER
          The BLACS context handle.
  RANGE   (global input) CHARACTER
          Specifies which eigenvalues are to be found.
          = 'A': ("All")   all eigenvalues will be found.
          = 'V': ("Value") all eigenvalues in the interval
                           [VL, VU] will be found.
          = 'I': ("Index") the IL-th through IU-th eigenvalues (of the
                           entire matrix) will be found.
  ORDER   (global input) CHARACTER
          Specifies the order in which the eigenvalues and their block
          numbers are stored in W and IBLOCK.
          = 'B': ("By Block") the eigenvalues will be grouped by
                              split-off block (see IBLOCK, ISPLIT) and
                              ordered from smallest to largest within
                              the block.
          = 'E': ("Entire matrix")
                              the eigenvalues for the entire matrix
                              will be ordered from smallest to largest.
  N       (global input) INTEGER
          The order of the tridiagonal matrix T.  N >= 0.
  VL      (global input) REAL
          If RANGE='V', the lower bound of the interval to be searched
          for eigenvalues.  Eigenvalues less than VL will not be
          returned.  Not referenced if RANGE='A' or 'I'.
  VU      (global input) REAL
          If RANGE='V', the upper bound of the interval to be searched
          for eigenvalues.  Eigenvalues greater than VU will not be
          returned.  VU must be greater than VL.  Not referenced if
          RANGE='A' or 'I'.
  IL      (global input) INTEGER
          If RANGE='I', the index (from smallest to largest) of the
          smallest eigenvalue to be returned.  IL must be at least 1.
          Not referenced if RANGE='A' or 'V'.
  IU      (global input) INTEGER
          If RANGE='I', the index (from smallest to largest) of the
          largest eigenvalue to be returned.  IU must be at least IL
          and no greater than N.  Not referenced if RANGE='A' or 'V'.
  ABSTOL  (global input) REAL
          The absolute tolerance for the eigenvalues.  An eigenvalue
          (or cluster) is considered to be located if it has been
          determined to lie in an interval whose width is ABSTOL or
          less.  If ABSTOL is less than or equal to zero, then ULP*|T|
          will be used, where |T| means the 1-norm of T.
          Eigenvalues will be computed most accurately when ABSTOL is
          set to the underflow threshold SLAMCH('U'), not zero.
          Note : If eigenvectors are desired later by inverse iteration
          ( PSSTEIN ), ABSTOL should be set to 2*PSLAMCH('S').
  D       (global input) REAL array, dimension (N)
          The n diagonal elements of the tridiagonal matrix T.  To
          avoid overflow, the matrix must be scaled so that its largest
          entry is no greater than overflow**(1/2) * underflow**(1/4)
          in absolute value, and for greatest accuracy, it should not
          be much smaller than that.
  E       (global input) REAL array, dimension (N-1)
          The (n-1) off-diagonal elements of the tridiagonal matrix T.
          To avoid overflow, the matrix must be scaled so that its
          largest entry is no greater than overflow**(1/2) *
          underflow**(1/4) in absolute value, and for greatest
          accuracy, it should not be much smaller than that.
  M       (global output) INTEGER
          The actual number of eigenvalues found. 0 <= M <= N.
          (See also the description of INFO=2)
  NSPLIT  (global output) INTEGER
          The number of diagonal blocks in the matrix T.
          1 <= NSPLIT <= N.
  W       (global output) REAL array, dimension (N)
          On exit, the first M elements of W contain the eigenvalues
          on all processes.
  IBLOCK  (global output) INTEGER array, dimension (N)
          At each row/column j where E(j) is zero or small, the
          matrix T is considered to split into a block diagonal
          matrix.  On exit IBLOCK(i) specifies which block (from 1
          to the number of blocks) the eigenvalue W(i) belongs to.
          NOTE:  in the (theoretically impossible) event that bisection
          does not converge for some or all eigenvalues, INFO is set
          to 1 and the ones for which it did not are identified by a
          negative block number.
  ISPLIT  (global output) INTEGER array, dimension (N)
          The splitting points, at which T breaks up into submatrices.
          The first submatrix consists of rows/columns 1 to ISPLIT(1),
          the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),
          etc., and the NSPLIT-th consists of rows/columns
          ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.
          (Only the first NSPLIT elements will actually be used, but
          since the user cannot know a priori what value NSPLIT will
          have, N words must be reserved for ISPLIT.)
  WORK    (local workspace) REAL array, dimension ( MAX( 5*N, 7 ) )
  LWORK   (local input) INTEGER
          size of array WORK must be >= MAX( 5*N, 7 )
          If LWORK = -1, then LWORK is global input and a workspace
          query is assumed; the routine only calculates the minimum
          and optimal size for all work arrays. Each of these
          values is returned in the first entry of the corresponding
          work array, and no error message is issued by PXERBLA.
  IWORK   (local workspace) INTEGER array, dimension ( MAX( 4*N, 14 ) )
  LIWORK  (local input) INTEGER
          size of array IWORK must be >= MAX( 4*N, 14, NPROCS )
          If LIWORK = -1, then LIWORK is global input and a workspace
          query is assumed; the routine only calculates the minimum
          and optimal size for all work arrays. Each of these
          values is returned in the first entry of the corresponding
          work array, and no error message is issued by PXERBLA.
  INFO    (global output) INTEGER
          = 0 :  successful exit
          < 0 :  if INFO = -i, the i-th argument had an illegal value
          > 0 :  some or all of the eigenvalues failed to converge or
                 were not computed:
              = 1 : Bisection failed to converge for some eigenvalues;
                    these eigenvalues are flagged by a negative block
                    number.  The effect is that the eigenvalues may not
                    be as accurate as the absolute and relative
                    tolerances. This is generally caused by arithmetic
                    which is less accurate than PSLAMCH says.
              = 2 : There is a mismatch between the number of
                    eigenvalues output and the number desired.
              = 3 : RANGE='i', and the Gershgorin interval initially
                    used was incorrect. No eigenvalues were computed.
                    Probable cause: your machine has sloppy floating
                    point arithmetic.
                    Cure: Increase the PARAMETER "FUDGE", recompile,
                    and try again.
  Internal Parameters
  ===================
  RELFAC  REAL, default = 2.0
          The relative tolerance.  An interval [a,b] lies within
          "relative tolerance" if  b-a < RELFAC*ulp*max(|a|,|b|),
          where "ulp" is the machine precision (distance from 1 to
          the next larger floating point number.)
  FUDGE   REAL, default = 2.0
          A "fudge factor" to widen the Gershgorin intervals.  Ideally,
          a value of 1 should work, but on machines with sloppy
          arithmetic, this needs to be larger.  The default for
          publicly released versions should be large enough to handle
          the worst machine around.  Note that this has no effect
          on the accuracy of the solution.
  =====================================================================
     .. Intrinsic Functions ..

 
Display dynamic version Find AutoScroll Reload FontSize: - + Hide Comments Hide Blanks Frame FullScreen MailPrint

 
001        SUBROUTINE PSSTEBZ( ICTXT , RANGE , ORDER , N , VL , VU , IL , IU ,
002       $ABSTOL , D , E , M , NSPLIT , W , IBLOCK , ISPLIT ,
003       $WORK , LWORK , IWORK , LIWORK , INFO )
004  
005  *     -- ScaLAPACK routine(version 1.7) --
006  *     University of Tennessee , Knoxville , Oak Ridge National Laboratory ,
007  *     and University of California , Berkeley.
008  *     November 15 , 1997
009  
010  *     .. Scalar Arguments ..
011        CHARACTER ORDER , RANGE
012        INTEGER ICTXT , IL , INFO , IU , LIWORK , LWORK , M , N ,
013       $NSPLIT
014        REAL ABSTOL , VL , VU
015        INTRINSIC ABS , ICHAR , MAX , MIN , MOD , REAL
016  *     ..
017  *     .. External Functions ..
018        LOGICAL LSAME
019        INTEGER BLACS_PNUM
020        REAL PSLAMCH
021        EXTERNAL LSAME , BLACS_PNUM , PSLAMCH
022  *     ..
023  *     .. External Subroutines ..
024        EXTERNAL BLACS_FREEBUFF , BLACS_GET , BLACS_GRIDEXIT ,
025       $BLACS_GRIDINFO , BLACS_GRIDMAP , GLOBCHK ,
026       $IGEBR2D , IGEBS2D , IGERV2D , IGESD2D , IGSUM2D ,
027       $PSLAEBZ , PSLAIECT , PSLAPDCT , PSLASNBT , PXERBLA ,
028       $SGEBR2D , SGEBS2D , SGERV2D , SGESD2D , SLASRT2  
029  *     ..
030  *     .. Parameters ..
031        INTEGER BLOCK_CYCLIC_2D , DLEN_ , DTYPE_ , CTXT_ , M_ , N_ ,
032       $MB_ , NB_ , RSRC_ , CSRC_ , LLD_
033        PARAMETER( BLOCK_CYCLIC_2D = 1 , DLEN_ = 9 , DTYPE_ = 1 ,
034       $CTXT_ = 2 , M_ = 3 , N_ = 4 , MB_ = 5 , NB_ = 6 ,
035       $RSRC_ = 7 , CSRC_ = 8 , LLD_ = 9 )
036        INTEGER BIGNUM , DESCMULT
037        PARAMETER( BIGNUM = 10000 , DESCMULT = 100 )
038        REAL ZERO , ONE , TWO , FIVE , HALF
039        PARAMETER( ZERO = 0.0E + 0 , ONE = 1.0E + 0 , TWO = 2.0E + 0 ,
040       $FIVE = 5.0E + 0 , HALF = 1.0E + 0 / TWO )
041        REAL FUDGE , RELFAC
042        PARAMETER( FUDGE = 2.0E + 0 , RELFAC = 2.0E + 0 )
043  *     ..
044  *     .. Local Scalars ..
045        LOGICAL LQUERY
046        INTEGER BLKNO , FOUND , I , IBEGIN , IEFLAG , IEND , IFRST ,
047       $IINFO , ILAST , ILOAD , IM , IMYLOAD , IN , INDRIW1 ,
048       $INDRIW2 , INDRW1 , INDRW2 , INXTLOAD , IOFF ,
049       $IORDER , IOUT , IRANGE , IRECV , IREM , ITMP1 ,
050       $ITMP2 , J , JB , K , LAST , LEXTRA , LREQ , MYCOL ,
051       $MYROW , NALPHA , NBETA , NCMP , NEIGINT , NEXT , NGL ,
052       $NGLOB , NGU , NINT , NPCOL , NPROW , OFFSET ,
053       $ONEDCONTEXT , P , PREV , REXTRA , RREQ , SELF ,
054       $TORECV
055        REAL ALPHA , ATOLI , BETA , BNORM , DRECV , DSEND , GL ,
056       $GU , INITVL , INITVU , LSAVE , MID , PIVMIN , RELTOL ,
057       $SAFEMN , TMP1 , TMP2 , TNORM , ULP
058  *     ..
059  *     .. Local Arrays ..
060        INTEGER IDUM( 5 , 2 )
061  *     ..
062  *     .. Executable Statements ..
063  *     This is just to keep ftnchek happy
064        IF( BLOCK_CYCLIC_2D*CSRC_*CTXT_*DLEN_*DTYPE_*LLD_*MB_*M_*NB_*N_*
065       $    RSRC_.LT.0 )RETURN
066  
067  *         Set up process grid
068  
069            CALL BLACS_GRIDINFO( ICTXT , NPROW , NPCOL , MYROW , MYCOL )
070  
071            INFO = 0
072            M = 0
073  
074  *         Decode RANGE
075  
076            IF( LSAME( RANGE , 'A' ) ) THEN
077                IRANGE = 1
078            ELSE IF( LSAME( RANGE , 'V' ) ) THEN
079                IRANGE = 2
080            ELSE IF( LSAME( RANGE , 'I' ) ) THEN
081                IRANGE = 3
082            ELSE
083                IRANGE = 0
084            END IF
085  
086  *         Decode ORDER
087  
088            IF( LSAME( ORDER , 'B' ) ) THEN
089                IORDER = 2
090            ELSE IF( LSAME( ORDER , 'E' ) .OR. LSAME( ORDER , 'A' ) ) THEN
091                IORDER = 1
092            ELSE
093                IORDER = 0
094            END IF
095  
096  *         Check for Errors
097  
098            IF( NPROW.EQ. - 1 ) THEN
099                INFO = - 1
100            ELSE
101  
102  *             Get machine constants
103  
104                SAFEMN = PSLAMCH( ICTXT , 'S' )
105                ULP = PSLAMCH( ICTXT , 'P' )
106                RELTOL = ULP*RELFAC
107                IDUM( 1 , 1 ) = ICHAR( RANGE )
108                IDUM( 1 , 2 ) = 2
109                IDUM( 2 , 1 ) = ICHAR( ORDER )
110                IDUM( 2 , 2 ) = 3
111                IDUM( 3 , 1 ) = N
112                IDUM( 3 , 2 ) = 4
113                NGLOB = 5
114                IF( IRANGE.EQ.3 ) THEN
115                    IDUM( 4 , 1 ) = IL
116                    IDUM( 4 , 2 ) = 7
117                    IDUM( 5 , 1 ) = IU
118                    IDUM( 5 , 2 ) = 8
119                ELSE
120                    IDUM( 4 , 1 ) = 0
121                    IDUM( 4 , 2 ) = 0
122                    IDUM( 5 , 1 ) = 0
123                    IDUM( 5 , 2 ) = 0
124                END IF
125                IF( MYROW.EQ.0 .AND. MYCOL.EQ.0 ) THEN
126                    WORK( 1 ) = ABSTOL
127                    IF( IRANGE.EQ.2 ) THEN
128                        WORK( 2 ) = VL
129                        WORK( 3 ) = VU
130                    ELSE
131                        WORK( 2 ) = ZERO
132                        WORK( 3 ) = ZERO
133                    END IF
134                    CALL SGEBS2D( ICTXT , 'ALL' , ' ' , 3 , 1 , WORK , 3 )
135                ELSE
136                    CALL SGEBR2D( ICTXT , 'ALL' , ' ' , 3 , 1 , WORK , 3 , 0 , 0 )
137                END IF
138                LQUERY =( LWORK.EQ. - 1 .OR. LIWORK.EQ. - 1 )
139                IF( INFO.EQ.0 ) THEN
140                    IF( IRANGE.EQ.0 ) THEN
141                        INFO = - 2
142                    ELSE IF( IORDER.EQ.0 ) THEN
143                        INFO = - 3
144                    ELSE IF( IRANGE.EQ.2 .AND. VL.GE.VU ) THEN
145                        INFO = - 5
146                    ELSE IF( IRANGE.EQ.3 .AND.( IL.LT.1 .OR. IL.GT.MAX( 1 ,
147       $                N ) ) ) THEN
148                        INFO = - 6
149                    ELSE IF( IRANGE.EQ.3 .AND.( IU.LT.MIN( N ,
150       $                IL ) .OR. IU.GT.N ) ) THEN
151                        INFO = - 7
152                    ELSE IF( LWORK.LT.MAX( 5*N , 7 ) .AND. .NOT.LQUERY ) THEN
153                        INFO = - 18
154                    ELSE IF( LIWORK.LT.MAX( 4*N , 14 , NPROW*NPCOL ) .AND. .NOT.
155       $                LQUERY ) THEN
156                        INFO = - 20
157                    ELSE IF( IRANGE.EQ.2 .AND.( ABS( WORK( 2 ) - VL ).GT.FIVE*
158       $                ULP*ABS( VL ) ) ) THEN
159                        INFO = - 5
160                    ELSE IF( IRANGE.EQ.2 .AND.( ABS( WORK( 3 ) - VU ).GT.FIVE*
161       $                ULP*ABS( VU ) ) ) THEN
162                        INFO = - 6
163                    ELSE IF( ABS( WORK( 1 ) - ABSTOL ).GT.FIVE*ULP*ABS( ABSTOL ) )
164       $                THEN
165                        INFO = - 9
166                    END IF
167                END IF
168                IF( INFO.EQ.0 )
169       $            INFO = BIGNUM
170                    CALL GLOBCHK( ICTXT , NGLOB , IDUM , 5 , IWORK , INFO )
171                    IF( INFO.EQ.BIGNUM ) THEN
172                        INFO = 0
173                    ELSE IF( MOD( INFO , DESCMULT ).EQ.0 ) THEN
174                        INFO = - INFO / DESCMULT
175                    ELSE
176                        INFO = - INFO
177                    END IF
178                END IF
179                WORK( 1 ) = REAL( MAX( 5*N , 7 ) )
180                IWORK( 1 ) = MAX( 4*N , 14 , NPROW*NPCOL )
181  
182                IF( INFO.NE.0 ) THEN
183                    CALL PXERBLA( ICTXT , 'PSSTEBZ' , - INFO )
184                    RETURN
185                ELSE IF( LWORK.EQ. - 1 .AND. LIWORK.EQ. - 1 ) THEN
186                    RETURN
187                END IF
188  
189  *             Quick return if possible
190  
191                IF( N.EQ.0 )
192       $            RETURN
193  
194                    K = 1
195                    DO 20 I = 0 , NPROW - 1
196                        DO 10 J = 0 , NPCOL - 1
197                            IWORK( K ) = BLACS_PNUM( ICTXT , I , J )
198                            K = K + 1
199     10                 CONTINUE
200     20             CONTINUE
201  
202                    P = NPROW*NPCOL
203                    NPROW = 1
204                    NPCOL = P
205  
206                    CALL BLACS_GET( ICTXT , 10 , ONEDCONTEXT )
207                    CALL BLACS_GRIDMAP( ONEDCONTEXT , IWORK , NPROW , NPROW , NPCOL )
208                    CALL BLACS_GRIDINFO( ONEDCONTEXT , I , J , K , SELF )
209  
210  *                 Simplifications :
211  
212                    IF( IRANGE.EQ.3 .AND. IL.EQ.1 .AND. IU.EQ.N )
213       $                IRANGE = 1
214  
215                    NEXT = MOD( SELF + 1 , P )
216                    PREV = MOD( P + SELF - 1 , P )
217  
218  *                 Compute squares of off - diagonals , splitting points and pivmin.
219  *                 Interleave diagonals and off - diagonals.
220  
221                    INDRW1 = MAX( 2*N , 4 )
222                    INDRW2 = INDRW1 + 2*N
223                    INDRIW1 = MAX( 2*N , 8 )
224                    NSPLIT = 1
225                    WORK( INDRW1 + 2*N ) = ZERO
226                    PIVMIN = ONE
227  
228                    DO 30 I = 1 , N - 1
229                        TMP1 = E( I )**2
230                        J = 2*I
231                        WORK( INDRW1 + J - 1 ) = D( I )
232                        IF( ABS( D( I + 1 )*D( I ) )*ULP**2 + SAFEMN.GT.TMP1 ) THEN
233                            ISPLIT( NSPLIT ) = I
234                            NSPLIT = NSPLIT + 1
235                            WORK( INDRW1 + J ) = ZERO
236                        ELSE
237                            WORK( INDRW1 + J ) = TMP1
238                            PIVMIN = MAX( PIVMIN , TMP1 )
239                        END IF
240     30             CONTINUE
241                    WORK( INDRW1 + 2*N - 1 ) = D( N )
242                    ISPLIT( NSPLIT ) = N
243                    PIVMIN = PIVMIN*SAFEMN
244  
245  *                 Compute Gershgorin interval[gl , gu] for entire matrix
246  
247                    GU = D( 1 )
248                    GL = D( 1 )
249                    TMP1 = ZERO
250  
251                    DO 40 I = 1 , N - 1
252                        TMP2 = ABS( E( I ) )
253                        GU = MAX( GU , D( I ) + TMP1 + TMP2 )
254                        GL = MIN( GL , D( I ) - TMP1 - TMP2 )
255                        TMP1 = TMP2
256     40             CONTINUE
257                    GU = MAX( GU , D( N ) + TMP1 )
258                    GL = MIN( GL , D( N ) - TMP1 )
259                    TNORM = MAX( ABS( GL ) , ABS( GU ) )
260                    GL = GL - FUDGE*TNORM*ULP*N - FUDGE*TWO*PIVMIN
261                    GU = GU + FUDGE*TNORM*ULP*N + FUDGE*PIVMIN
262  
263                    IF( ABSTOL.LE.ZERO ) THEN
264                        ATOLI = ULP*TNORM
265                    ELSE
266                        ATOLI = ABSTOL
267                    END IF
268  
269  *                 Find out if on an IEEE machine , the sign bit is the
270  *                 32nd bit(Big Endian) or the 64th bit(Little Endian)
271  
272                    IF( IRANGE.EQ.1 .OR. NSPLIT.EQ.1 ) THEN
273                        CALL PSLASNBT( IEFLAG )
274                    ELSE
275                        IEFLAG = 0
276                    END IF
277                    LEXTRA = 0
278                    REXTRA = 0
279  
280  *                 Form Initial Interval containing desired eigenvalues
281  
282                    IF( IRANGE.EQ.1 ) THEN
283                        INITVL = GL
284                        INITVU = GU
285                        WORK( 1 ) = GL
286                        WORK( 2 ) = GU
287                        IWORK( 1 ) = 0
288                        IWORK( 2 ) = N
289                        IFRST = 1
290                        ILAST = N
291                    ELSE IF( IRANGE.EQ.2 ) THEN
292                        IF( VL.GT.GL ) THEN
293                            IF( IEFLAG.EQ.0 ) THEN
294                                CALL PSLAPDCT ( VL , N , WORK( INDRW1 + 1 ) , PIVMIN , IFRST )
295                            ELSE
296                                CALL PSLAIECT( VL , N , WORK( INDRW1 + 1 ) , IFRST )
297                            END IF
298                            IFRST = IFRST + 1
299                            INITVL = VL
300                        ELSE
301                            INITVL = GL
302                            IFRST = 1
303                        END IF
304                        IF( VU.LT.GU ) THEN
305                            IF( IEFLAG.EQ.0 ) THEN
306                                CALL PSLAPDCT ( VU , N , WORK( INDRW1 + 1 ) , PIVMIN , ILAST )
307                            ELSE
308                                CALL PSLAIECT( VU , N , WORK( INDRW1 + 1 ) , ILAST )
309                            END IF
310                            INITVU = VU
311                        ELSE
312                            INITVU = GU
313                            ILAST = N
314                        END IF
315                        WORK( 1 ) = INITVL
316                        WORK( 2 ) = INITVU
317                        IWORK( 1 ) = IFRST - 1
318                        IWORK( 2 ) = ILAST
319                    ELSE IF( IRANGE.EQ.3 ) THEN
320                        WORK( 1 ) = GL
321                        WORK( 2 ) = GU
322                        IWORK( 1 ) = 0
323                        IWORK( 2 ) = N
324                        IWORK( 5 ) = IL - 1
325                        IWORK( 6 ) = IU
326                        CALL PSLAEBZ ( 0 , N , 2 , 1 , ATOLI , RELTOL , PIVMIN ,
327       $                WORK( INDRW1 + 1 ) , IWORK( 5 ) , WORK , IWORK , NINT ,
328       $                LSAVE , IEFLAG , IINFO )
329                        IF( IINFO.NE.0 ) THEN
330                            INFO = 3
331                            GO TO 230
332                        END IF
333                        IF( NINT.GT.1 ) THEN
334                            IF( IWORK( 5 ).EQ.IL - 1 ) THEN
335                                WORK( 2 ) = WORK( 4 )
336                                IWORK( 2 ) = IWORK( 4 )
337                            ELSE
338                                WORK( 1 ) = WORK( 3 )
339                                IWORK( 1 ) = IWORK( 3 )
340                            END IF
341                            IF( IWORK( 1 ).LT.0 .OR. IWORK( 1 ).GT.IL - 1 .OR.
342       $                    IWORK( 2 ).LE.MIN( IU - 1 , IWORK( 1 ) ) .OR.
343       $                    IWORK( 2 ).GT.N ) THEN
344                            INFO = 3
345                            GO TO 230
346                        END IF
347                    END IF
348                    LEXTRA = IL - 1 - IWORK( 1 )
349                    REXTRA = IWORK( 2 ) - IU
350                    INITVL = WORK( 1 )
351                    INITVU = WORK( 2 )
352                    IFRST = IL
353                    ILAST = IU
354                END IF
355  *             NVL = IFRST - 1
356  *             NVU = ILAST
357                GL = INITVL
358                GU = INITVU
359                NGL = IWORK( 1 )
360                NGU = IWORK( 2 )
361                IM = 0
362                FOUND = 0
363                INDRIW2 = INDRIW1 + NGU - NGL
364                IEND = 0
365                IF( IFRST.GT.ILAST )
366       $            GO TO 100
367                    IF( IFRST.EQ.1 .AND. ILAST.EQ.N )
368       $                IRANGE = 1
369  
370  *                     Find Eigenvalues -- Loop Over Blocks
371  
372                        DO 90 JB = 1 , NSPLIT
373                            IOFF = IEND
374                            IBEGIN = IOFF + 1
375                            IEND = ISPLIT( JB )
376                            IN = IEND - IOFF
377                            IF( JB.NE.1 ) THEN
378                                IF( IRANGE.NE.1 ) THEN
379                                    FOUND = IM
380  
381  *                                 Find total number of eigenvalues found thus far
382  
383                                    CALL IGSUM2D( ONEDCONTEXT , 'All' , ' ' , 1 , 1 , FOUND , 1 ,
384       $                            - 1 , - 1 )
385                                ELSE
386                                    FOUND = IOFF
387                                END IF
388                            END IF
389  *                         IF( SELF.GE.P )
390  *                         $ GO TO 30
391                            IF( IN.NE.N ) THEN
392  
393  *                             Compute Gershgorin interval[gl , gu] for split matrix
394  
395                                GU = D( IBEGIN )
396                                GL = D( IBEGIN )
397                                TMP1 = ZERO
398  
399                                DO 50 J = IBEGIN , IEND - 1
400                                    TMP2 = ABS( E( J ) )
401                                    GU = MAX( GU , D( J ) + TMP1 + TMP2 )
402                                    GL = MIN( GL , D( J ) - TMP1 - TMP2 )
403                                    TMP1 = TMP2
404     50                         CONTINUE
405  
406                                GU = MAX( GU , D( IEND ) + TMP1 )
407                                GL = MIN( GL , D( IEND ) - TMP1 )
408                                BNORM = MAX( ABS( GL ) , ABS( GU ) )
409                                GL = GL - FUDGE*BNORM*ULP*IN - FUDGE*PIVMIN
410                                GU = GU + FUDGE*BNORM*ULP*IN + FUDGE*PIVMIN
411  
412  *                             Compute ATOLI for the current submatrix
413  
414                                IF( ABSTOL.LE.ZERO ) THEN
415                                    ATOLI = ULP*BNORM
416                                ELSE
417                                    ATOLI = ABSTOL
418                                END IF
419  
420                                IF( GL.LT.INITVL ) THEN
421                                    GL = INITVL
422                                    IF( IEFLAG.EQ.0 ) THEN
423                                        CALL PSLAPDCT ( GL , IN , WORK( INDRW1 + 2*IOFF + 1 ) ,
424       $                                PIVMIN , NGL )
425                                    ELSE
426                                        CALL PSLAIECT( GL , IN , WORK( INDRW1 + 2*IOFF + 1 ) , NGL )
427                                    END IF
428                                ELSE
429                                    NGL = 0
430                                END IF
431                                IF( GU.GT.INITVU ) THEN
432                                    GU = INITVU
433                                    IF( IEFLAG.EQ.0 ) THEN
434                                        CALL PSLAPDCT ( GU , IN , WORK( INDRW1 + 2*IOFF + 1 ) ,
435       $                                PIVMIN , NGU )
436                                    ELSE
437                                        CALL PSLAIECT( GU , IN , WORK( INDRW1 + 2*IOFF + 1 ) , NGU )
438                                    END IF
439                                ELSE
440                                    NGU = IN
441                                END IF
442                                IF( NGL.GE.NGU )
443       $                            GO TO 90
444                                    WORK( 1 ) = GL
445                                    WORK( 2 ) = GU
446                                    IWORK( 1 ) = NGL
447                                    IWORK( 2 ) = NGU
448                                END IF
449                                OFFSET = FOUND - NGL
450                                BLKNO = JB
451  
452  *                             Do a static partitioning of work so that each process
453  *                             has to find an(almost) equal number of eigenvalues
454  
455                                NCMP = NGU - NGL
456                                ILOAD = NCMP / P
457                                IREM = NCMP - ILOAD*P
458                                ITMP1 = MOD( SELF - FOUND , P )
459                                IF( ITMP1.LT.0 )
460       $                            ITMP1 = ITMP1 + P
461                                    IF( ITMP1.LT.IREM ) THEN
462                                        IMYLOAD = ILOAD + 1
463                                    ELSE
464                                        IMYLOAD = ILOAD
465                                    END IF
466                                    IF( IMYLOAD.EQ.0 ) THEN
467                                        GO TO 90
468                                    ELSE IF( IN.EQ.1 ) THEN
469                                        WORK( INDRW2 + IM + 1 ) = WORK( INDRW1 + 2*IOFF + 1 )
470                                        IWORK( INDRIW1 + IM + 1 ) = BLKNO
471                                        IWORK( INDRIW2 + IM + 1 ) = OFFSET + 1
472                                        IM = IM + 1
473                                        GO TO 90
474                                    ELSE
475                                        INXTLOAD = ILOAD
476                                        ITMP2 = MOD( SELF + 1 - FOUND , P )
477                                        IF( ITMP2.LT.0 )
478       $                                    ITMP2 = ITMP2 + P
479                                            IF( ITMP2.LT.IREM )
480       $                                        INXTLOAD = INXTLOAD + 1
481                                                LREQ = NGL + ITMP1*ILOAD + MIN( IREM , ITMP1 )
482                                                RREQ = LREQ + IMYLOAD
483                                                IWORK( 5 ) = LREQ
484                                                IWORK( 6 ) = RREQ
485                                                TMP1 = WORK( 1 )
486                                                ITMP1 = IWORK( 1 )
487                                                CALL PSLAEBZ ( 1 , IN , 1 , 1 , ATOLI , RELTOL , PIVMIN ,
488       $                                        WORK( INDRW1 + 2*IOFF + 1 ) , IWORK( 5 ) , WORK ,
489       $                                        IWORK , NINT , LSAVE , IEFLAG , IINFO )
490                                                ALPHA = WORK( 1 )
491                                                BETA = WORK( 2 )
492                                                NALPHA = IWORK( 1 )
493                                                NBETA = IWORK( 2 )
494                                                DSEND = BETA
495                                                IF( NBETA.GT.RREQ + INXTLOAD ) THEN
496                                                    NBETA = RREQ
497                                                    DSEND = ALPHA
498                                                END IF
499                                                LAST = MOD( FOUND + MIN( NGU - NGL , P ) - 1 , P )
500                                                IF( LAST.LT.0 )
501       $                                            LAST = LAST + P
502                                                    IF( SELF.NE.LAST ) THEN
503                                                        CALL SGESD2D( ONEDCONTEXT , 1 , 1 , DSEND , 1 , 0 , NEXT )
504                                                        CALL IGESD2D( ONEDCONTEXT , 1 , 1 , NBETA , 1 , 0 , NEXT )
505                                                    END IF
506                                                    IF( SELF.NE.MOD( FOUND , P ) ) THEN
507                                                        CALL SGERV2D( ONEDCONTEXT , 1 , 1 , DRECV , 1 , 0 , PREV )
508                                                        CALL IGERV2D( ONEDCONTEXT , 1 , 1 , IRECV , 1 , 0 , PREV )
509                                                    ELSE
510                                                        DRECV = TMP1
511                                                        IRECV = ITMP1
512                                                    END IF
513                                                    WORK( 1 ) = MAX( LSAVE , DRECV )
514                                                    IWORK( 1 ) = IRECV
515                                                    ALPHA = MAX( ALPHA , WORK( 1 ) )
516                                                    NALPHA = MAX( NALPHA , IRECV )
517                                                    IF( BETA - ALPHA.LE.MAX( ATOLI , RELTOL*MAX( ABS( ALPHA ) ,
518       $                                            ABS( BETA ) ) ) ) THEN
519                                                    MID = HALF*( ALPHA + BETA )
520                                                    DO 60 J = OFFSET + NALPHA + 1 , OFFSET + NBETA
521                                                    WORK( INDRW2 + IM + 1 ) = MID
522                                                    IWORK( INDRIW1 + IM + 1 ) = BLKNO
523                                                    IWORK( INDRIW2 + IM + 1 ) = J
524                                                    IM = IM + 1
525     60                                             CONTINUE
526                                                    WORK( 2 ) = ALPHA
527                                                    IWORK( 2 ) = NALPHA
528                                                END IF
529                                            END IF
530                                            NEIGINT = IWORK( 2 ) - IWORK( 1 )
531                                            IF( NEIGINT.LE.0 )
532       $                                        GO TO 90
533  
534  *                                             Call the main computational routine
535  
536                                                CALL PSLAEBZ ( 2 , IN , NEIGINT , 1 , ATOLI , RELTOL , PIVMIN ,
537       $                                        WORK( INDRW1 + 2*IOFF + 1 ) , IWORK , WORK , IWORK ,
538       $                                        IOUT , LSAVE , IEFLAG , IINFO )
539                                                IF( IINFO.NE.0 ) THEN
540                                                    INFO = 1
541                                                END IF
542                                                DO 80 I = 1 , IOUT
543                                                    MID = HALF*( WORK( 2*I - 1 ) + WORK( 2*I ) )
544                                                    IF( I.GT.IOUT - IINFO )
545       $                                                BLKNO = - BLKNO
546                                                        DO 70 J = OFFSET + IWORK( 2*I - 1 ) + 1 ,
547       $                                                OFFSET + IWORK( 2*I )
548                                                        WORK( INDRW2 + IM + 1 ) = MID
549                                                        IWORK( INDRIW1 + IM + 1 ) = BLKNO
550                                                        IWORK( INDRIW2 + IM + 1 ) = J
551                                                        IM = IM + 1
552     70                                                 CONTINUE
553     80                                         CONTINUE
554     90                 CONTINUE
555  
556  *                     Find out total number of eigenvalues computed
557  
558    100 CONTINUE
559        M = IM
560        CALL IGSUM2D( ONEDCONTEXT , 'ALL' , ' ' , 1 , 1 , M , 1 , - 1 , - 1 )
561  
562  *     Move the eigenvalues found to their final destinations
563  
564        DO 130 I = 1 , P
565            IF( SELF.EQ.I - 1 ) THEN
566                CALL IGEBS2D( ONEDCONTEXT , 'ALL' , ' ' , 1 , 1 , IM , 1 )
567                IF( IM.NE.0 ) THEN
568                    CALL IGEBS2D( ONEDCONTEXT , 'ALL' , ' ' , IM , 1 ,
569       $            IWORK( INDRIW2 + 1 ) , IM )
570                    CALL SGEBS2D( ONEDCONTEXT , 'ALL' , ' ' , IM , 1 ,
571       $            WORK( INDRW2 + 1 ) , IM )
572                    CALL IGEBS2D( ONEDCONTEXT , 'ALL' , ' ' , IM , 1 ,
573       $            IWORK( INDRIW1 + 1 ) , IM )
574                    DO 110 J = 1 , IM
575                        W( IWORK( INDRIW2 + J ) ) = WORK( INDRW2 + J )
576                        IBLOCK( IWORK( INDRIW2 + J ) ) = IWORK( INDRIW1 + J )
577    110             CONTINUE
578                END IF
579            ELSE
580                CALL IGEBR2D( ONEDCONTEXT , 'ALL' , ' ' , 1 , 1 , TORECV , 1 , 0 ,
581       $        I - 1 )
582                IF( TORECV.NE.0 ) THEN
583                    CALL IGEBR2D( ONEDCONTEXT , 'ALL' , ' ' , TORECV , 1 , IWORK ,
584       $            TORECV , 0 , I - 1 )
585                    CALL SGEBR2D( ONEDCONTEXT , 'ALL' , ' ' , TORECV , 1 , WORK ,
586       $            TORECV , 0 , I - 1 )
587                    CALL IGEBR2D( ONEDCONTEXT , 'ALL' , ' ' , TORECV , 1 ,
588       $            IWORK( N + 1 ) , TORECV , 0 , I - 1 )
589                    DO 120 J = 1 , TORECV
590                        W( IWORK( J ) ) = WORK( J )
591                        IBLOCK( IWORK( J ) ) = IWORK( N + J )
592    120             CONTINUE
593                END IF
594            END IF
595    130 CONTINUE
596        IF( NSPLIT.GT.1 .AND. IORDER.EQ.1 ) THEN
597  
598  *         Sort the eigenvalues
599  
600            DO 140 I = 1 , M
601                IWORK( M + I ) = I
602    140     CONTINUE
603            CALL SLASRT2 ( 'I' , M , W , IWORK( M + 1 ) , IINFO )
604            DO 150 I = 1 , M
605                IWORK( I ) = IBLOCK( I )
606    150     CONTINUE
607            DO 160 I = 1 , M
608                IBLOCK( I ) = IWORK( IWORK( M + I ) )
609    160     CONTINUE
610        END IF
611        IF( IRANGE.EQ.3 .AND.( LEXTRA.GT.0 .OR. REXTRA.GT.0 ) ) THEN
612  
613  *         Discard unwanted eigenvalues(occurs only when RANGE = 'I' ,
614  *         and eigenvalues IL , and / or IU are in a cluster)
615  
616            DO 170 I = 1 , M
617                WORK( I ) = W( I )
618                IWORK( I ) = I
619                IWORK( M + I ) = I
620    170     CONTINUE
621            DO 190 I = 1 , LEXTRA
622                ITMP1 = I
623                DO 180 J = I + 1 , M
624                    IF( WORK( J ).LT.WORK( ITMP1 ) ) THEN
625                        ITMP1 = J
626                    END IF
627    180         CONTINUE
628                TMP1 = WORK( I )
629                WORK( I ) = WORK( ITMP1 )
630                WORK( ITMP1 ) = TMP1
631                IWORK( IWORK( M + ITMP1 ) ) = I
632                IWORK( IWORK( M + I ) ) = ITMP1
633                ITMP2 = IWORK( M + I )
634                IWORK( M + I ) = IWORK( M + ITMP1 )
635                IWORK( M + ITMP1 ) = ITMP2
636    190     CONTINUE
637            DO 210 I = 1 , REXTRA
638                ITMP1 = M - I + 1
639                DO 200 J = M - I , LEXTRA + 1 , - 1
640                    IF( WORK( J ).GT.WORK( ITMP1 ) ) THEN
641                        ITMP1 = J
642                    END IF
643    200         CONTINUE
644                TMP1 = WORK( M - I + 1 )
645                WORK( M - I + 1 ) = WORK( ITMP1 )
646                WORK( ITMP1 ) = TMP1
647                IWORK( IWORK( M + ITMP1 ) ) = M - I + 1
648                IWORK( IWORK( 2*M - I + 1 ) ) = ITMP1
649                ITMP2 = IWORK( 2*M - I + 1 )
650                IWORK( 2*M - I + 1 ) = IWORK( M + ITMP1 )
651                IWORK( M + ITMP1 ) = ITMP2
652  *             IWORK( ITMP1 ) = 1
653    210     CONTINUE
654            J = 0
655            DO 220 I = 1 , M
656                IF( IWORK( I ).GT.LEXTRA .AND. IWORK( I ).LE.M - REXTRA ) THEN
657                    J = J + 1
658                    W( J ) = WORK( IWORK( I ) )
659                    IBLOCK( J ) = IBLOCK( I )
660                END IF
661    220     CONTINUE
662            M = M - LEXTRA - REXTRA
663        END IF
664        IF( M.NE.ILAST - IFRST + 1 ) THEN
665            INFO = 2
666        END IF
667  
668    230 CONTINUE
669        CALL BLACS_FREEBUFF( ONEDCONTEXT , 1 )
670        CALL BLACS_GRIDEXIT( ONEDCONTEXT )
671        RETURN
672  
673  *     End of PSSTEBZ
674  
675        END
676