ScaLAPACK  2.0.2
ScaLAPACK: Scalable Linear Algebra PACKage
pzheevx.f
Go to the documentation of this file.
00001       SUBROUTINE PZHEEVX( JOBZ, RANGE, UPLO, N, A, IA, JA, DESCA, VL,
00002      $                    VU, IL, IU, ABSTOL, M, NZ, W, ORFAC, Z, IZ,
00003      $                    JZ, DESCZ, WORK, LWORK, RWORK, LRWORK, IWORK,
00004      $                    LIWORK, IFAIL, ICLUSTR, GAP, INFO )
00005 *
00006 *  -- ScaLAPACK routine (version 1.7) --
00007 *     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
00008 *     and University of California, Berkeley.
00009 *     May 25, 2001
00010 *
00011 *     .. Scalar Arguments ..
00012       CHARACTER          JOBZ, RANGE, UPLO
00013       INTEGER            IA, IL, INFO, IU, IZ, JA, JZ, LIWORK, LRWORK,
00014      $                   LWORK, M, N, NZ
00015       DOUBLE PRECISION   ABSTOL, ORFAC, VL, VU
00016 *     ..
00017 *     .. Array Arguments ..
00018       INTEGER            DESCA( * ), DESCZ( * ), ICLUSTR( * ),
00019      $                   IFAIL( * ), IWORK( * )
00020       DOUBLE PRECISION   GAP( * ), RWORK( * ), W( * )
00021       COMPLEX*16         A( * ), WORK( * ), Z( * )
00022 *     ..
00023 *
00024 *  Purpose
00025 *  =======
00026 *
00027 *  PZHEEVX computes selected eigenvalues and, optionally, eigenvectors
00028 *  of a complex hermitian matrix A by calling the recommended sequence
00029 *  of ScaLAPACK routines.  Eigenvalues/vectors can be selected by
00030 *  specifying a range of values or a range of indices for the desired
00031 *  eigenvalues.
00032 *
00033 *  Notes
00034 *  =====
00035 *
00036 *  Each global data object is described by an associated description
00037 *  vector.  This vector stores the information required to establish
00038 *  the mapping between an object element and its corresponding process
00039 *  and memory location.
00040 *
00041 *  Let A be a generic term for any 2D block cyclicly distributed array.
00042 *  Such a global array has an associated description vector DESCA.
00043 *  In the following comments, the character _ should be read as
00044 *  "of the global array".
00045 *
00046 *  NOTATION        STORED IN      EXPLANATION
00047 *  --------------- -------------- --------------------------------------
00048 *  DTYPE_A(global) DESCA( DTYPE_ )The descriptor type.  In this case,
00049 *                                 DTYPE_A = 1.
00050 *  CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
00051 *                                 the BLACS process grid A is distribu-
00052 *                                 ted over. The context itself is glo-
00053 *                                 bal, but the handle (the integer
00054 *                                 value) may vary.
00055 *  M_A    (global) DESCA( M_ )    The number of rows in the global
00056 *                                 array A.
00057 *  N_A    (global) DESCA( N_ )    The number of columns in the global
00058 *                                 array A.
00059 *  MB_A   (global) DESCA( MB_ )   The blocking factor used to distribute
00060 *                                 the rows of the array.
00061 *  NB_A   (global) DESCA( NB_ )   The blocking factor used to distribute
00062 *                                 the columns of the array.
00063 *  RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
00064 *                                 row of the array A is distributed.
00065 *  CSRC_A (global) DESCA( CSRC_ ) The process column over which the
00066 *                                 first column of the array A is
00067 *                                 distributed.
00068 *  LLD_A  (local)  DESCA( LLD_ )  The leading dimension of the local
00069 *                                 array.  LLD_A >= MAX(1,LOCr(M_A)).
00070 *
00071 *  Let K be the number of rows or columns of a distributed matrix,
00072 *  and assume that its process grid has dimension p x q.
00073 *  LOCr( K ) denotes the number of elements of K that a process
00074 *  would receive if K were distributed over the p processes of its
00075 *  process column.
00076 *  Similarly, LOCc( K ) denotes the number of elements of K that a
00077 *  process would receive if K were distributed over the q processes of
00078 *  its process row.
00079 *  The values of LOCr() and LOCc() may be determined via a call to the
00080 *  ScaLAPACK tool function, NUMROC:
00081 *          LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
00082 *          LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
00083 *  An upper bound for these quantities may be computed by:
00084 *          LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
00085 *          LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
00086 *
00087 *  PZHEEVX assumes IEEE 754 standard compliant arithmetic.  To port
00088 *  to a system which does not have IEEE 754 arithmetic, modify
00089 *  the appropriate SLmake.inc file to include the compiler switch
00090 *  -DNO_IEEE.  This switch only affects the compilation of pdlaiect.c.
00091 *
00092 *  Arguments
00093 *  =========
00094 *
00095 *     NP = the number of rows local to a given process.
00096 *     NQ = the number of columns local to a given process.
00097 *
00098 *  JOBZ    (global input) CHARACTER*1
00099 *          Specifies whether or not to compute the eigenvectors:
00100 *          = 'N':  Compute eigenvalues only.
00101 *          = 'V':  Compute eigenvalues and eigenvectors.
00102 *
00103 *  RANGE   (global input) CHARACTER*1
00104 *          = 'A': all eigenvalues will be found.
00105 *          = 'V': all eigenvalues in the interval [VL,VU] will be found.
00106 *          = 'I': the IL-th through IU-th eigenvalues will be found.
00107 *
00108 *  UPLO    (global input) CHARACTER*1
00109 *          Specifies whether the upper or lower triangular part of the
00110 *          Hermitian matrix A is stored:
00111 *          = 'U':  Upper triangular
00112 *          = 'L':  Lower triangular
00113 *
00114 *  N       (global input) INTEGER
00115 *          The number of rows and columns of the matrix A.  N >= 0.
00116 *
00117 *  A       (local input/workspace) block cyclic COMPLEX*16 array,
00118 *          global dimension (N, N),
00119 *          local dimension ( LLD_A, LOCc(JA+N-1) )
00120 *
00121 *          On entry, the Hermitian matrix A.  If UPLO = 'U', only the
00122 *          upper triangular part of A is used to define the elements of
00123 *          the Hermitian matrix.  If UPLO = 'L', only the lower
00124 *          triangular part of A is used to define the elements of the
00125 *          Hermitian matrix.
00126 *
00127 *          On exit, the lower triangle (if UPLO='L') or the upper
00128 *          triangle (if UPLO='U') of A, including the diagonal, is
00129 *          destroyed.
00130 *
00131 *  IA      (global input) INTEGER
00132 *          A's global row index, which points to the beginning of the
00133 *          submatrix which is to be operated on.
00134 *
00135 *  JA      (global input) INTEGER
00136 *          A's global column index, which points to the beginning of
00137 *          the submatrix which is to be operated on.
00138 *
00139 *  DESCA   (global and local input) INTEGER array of dimension DLEN_.
00140 *          The array descriptor for the distributed matrix A.
00141 *          If DESCA( CTXT_ ) is incorrect, PZHEEVX cannot guarantee
00142 *          correct error reporting.
00143 *
00144 *  VL      (global input) DOUBLE PRECISION
00145 *          If RANGE='V', the lower bound of the interval to be searched
00146 *          for eigenvalues.  Not referenced if RANGE = 'A' or 'I'.
00147 *
00148 *  VU      (global input) DOUBLE PRECISION
00149 *          If RANGE='V', the upper bound of the interval to be searched
00150 *          for eigenvalues.  Not referenced if RANGE = 'A' or 'I'.
00151 *
00152 *  IL      (global input) INTEGER
00153 *          If RANGE='I', the index (from smallest to largest) of the
00154 *          smallest eigenvalue to be returned.  IL >= 1.
00155 *          Not referenced if RANGE = 'A' or 'V'.
00156 *
00157 *  IU      (global input) INTEGER
00158 *          If RANGE='I', the index (from smallest to largest) of the
00159 *          largest eigenvalue to be returned.  min(IL,N) <= IU <= N.
00160 *          Not referenced if RANGE = 'A' or 'V'.
00161 *
00162 *  ABSTOL  (global input) DOUBLE PRECISION
00163 *          If JOBZ='V', setting ABSTOL to PDLAMCH( CONTEXT, 'U') yields
00164 *          the most orthogonal eigenvectors.
00165 *
00166 *          The absolute error tolerance for the eigenvalues.
00167 *          An approximate eigenvalue is accepted as converged
00168 *          when it is determined to lie in an interval [a,b]
00169 *          of width less than or equal to
00170 *
00171 *                  ABSTOL + EPS *   max( |a|,|b| ) ,
00172 *
00173 *          where EPS is the machine precision.  If ABSTOL is less than
00174 *          or equal to zero, then EPS*norm(T) will be used in its place,
00175 *          where norm(T) is the 1-norm of the tridiagonal matrix
00176 *          obtained by reducing A to tridiagonal form.
00177 *
00178 *          Eigenvalues will be computed most accurately when ABSTOL is
00179 *          set to twice the underflow threshold 2*PDLAMCH('S') not zero.
00180 *          If this routine returns with ((MOD(INFO,2).NE.0) .OR.
00181 *          (MOD(INFO/8,2).NE.0)), indicating that some eigenvalues or
00182 *          eigenvectors did not converge, try setting ABSTOL to
00183 *          2*PDLAMCH('S').
00184 *
00185 *          See "Computing Small Singular Values of Bidiagonal Matrices
00186 *          with Guaranteed High Relative Accuracy," by Demmel and
00187 *          Kahan, LAPACK Working Note #3.
00188 *
00189 *          See "On the correctness of Parallel Bisection in Floating
00190 *          Point" by Demmel, Dhillon and Ren, LAPACK Working Note #70
00191 *
00192 *  M       (global output) INTEGER
00193 *          Total number of eigenvalues found.  0 <= M <= N.
00194 *
00195 *  NZ      (global output) INTEGER
00196 *          Total number of eigenvectors computed.  0 <= NZ <= M.
00197 *          The number of columns of Z that are filled.
00198 *          If JOBZ .NE. 'V', NZ is not referenced.
00199 *          If JOBZ .EQ. 'V', NZ = M unless the user supplies
00200 *          insufficient space and PZHEEVX is not able to detect this
00201 *          before beginning computation.  To get all the eigenvectors
00202 *          requested, the user must supply both sufficient
00203 *          space to hold the eigenvectors in Z (M .LE. DESCZ(N_))
00204 *          and sufficient workspace to compute them.  (See LWORK below.)
00205 *          PZHEEVX is always able to detect insufficient space without
00206 *          computation unless RANGE .EQ. 'V'.
00207 *
00208 *  W       (global output) DOUBLE PRECISION array, dimension (N)
00209 *          On normal exit, the first M entries contain the selected
00210 *          eigenvalues in ascending order.
00211 *
00212 *  ORFAC   (global input) DOUBLE PRECISION
00213 *          Specifies which eigenvectors should be reorthogonalized.
00214 *          Eigenvectors that correspond to eigenvalues which are within
00215 *          tol=ORFAC*norm(A) of each other are to be reorthogonalized.
00216 *          However, if the workspace is insufficient (see LWORK),
00217 *          tol may be decreased until all eigenvectors to be
00218 *          reorthogonalized can be stored in one process.
00219 *          No reorthogonalization will be done if ORFAC equals zero.
00220 *          A default value of 10^-3 is used if ORFAC is negative.
00221 *          ORFAC should be identical on all processes.
00222 *
00223 *  Z       (local output) COMPLEX*16 array,
00224 *          global dimension (N, N),
00225 *          local dimension ( LLD_Z, LOCc(JZ+N-1) )
00226 *          If JOBZ = 'V', then on normal exit the first M columns of Z
00227 *          contain the orthonormal eigenvectors of the matrix
00228 *          corresponding to the selected eigenvalues.  If an eigenvector
00229 *          fails to converge, then that column of Z contains the latest
00230 *          approximation to the eigenvector, and the index of the
00231 *          eigenvector is returned in IFAIL.
00232 *          If JOBZ = 'N', then Z is not referenced.
00233 *
00234 *  IZ      (global input) INTEGER
00235 *          Z's global row index, which points to the beginning of the
00236 *          submatrix which is to be operated on.
00237 *
00238 *  JZ      (global input) INTEGER
00239 *          Z's global column index, which points to the beginning of
00240 *          the submatrix which is to be operated on.
00241 *
00242 *  DESCZ   (global and local input) INTEGER array of dimension DLEN_.
00243 *          The array descriptor for the distributed matrix Z.
00244 *          DESCZ( CTXT_ ) must equal DESCA( CTXT_ )
00245 *
00246 *  WORK    (local workspace/output) COMPLEX*16 array,
00247 *          dimension (LWORK)
00248 *          WORK(1) returns workspace adequate workspace to allow
00249 *          optimal performance.
00250 *
00251 *  LWORK   (local input) INTEGER
00252 *          Size of WORK array.  If only eigenvalues are requested:
00253 *            LWORK >= N + MAX( NB * ( NP0 + 1 ), 3 )
00254 *          If eigenvectors are requested:
00255 *            LWORK >= N + ( NP0 + MQ0 + NB ) * NB
00256 *          with NQ0 = NUMROC( NN, NB, 0, 0, NPCOL ).
00257 *
00258 *          For optimal performance, greater workspace is needed, i.e.
00259 *            LWORK >= MAX( LWORK, NHETRD_LWORK )
00260 *          Where LWORK is as defined above, and
00261 *          NHETRD_LWORK = N + 2*( ANB+1 )*( 4*NPS+2 ) +
00262 *            ( NPS + 1 ) * NPS
00263 *
00264 *          ICTXT = DESCA( CTXT_ )
00265 *          ANB = PJLAENV( ICTXT, 3, 'PZHETTRD', 'L', 0, 0, 0, 0 )
00266 *          SQNPC = SQRT( DBLE( NPROW * NPCOL ) )
00267 *          NPS = MAX( NUMROC( N, 1, 0, 0, SQNPC ), 2*ANB )
00268 *
00269 *          NUMROC is a ScaLAPACK tool functions;
00270 *          PJLAENV is a ScaLAPACK envionmental inquiry function
00271 *          MYROW, MYCOL, NPROW and NPCOL can be determined by calling
00272 *          the subroutine BLACS_GRIDINFO.
00273 *
00274 *          If LWORK = -1, then LWORK is global input and a workspace
00275 *          query is assumed; the routine only calculates the
00276 *          optimal size for all work arrays. Each of these
00277 *          values is returned in the first entry of the corresponding
00278 *          work array, and no error message is issued by PXERBLA.
00279 *
00280 *  RWORK   (local workspace/output) DOUBLE PRECISION array,
00281 *             dimension max(3,LRWORK)
00282 *          On return, WORK(1) contains the optimal amount of
00283 *          workspace required for efficient execution.
00284 *          if JOBZ='N' RWORK(1) = optimal amount of workspace
00285 *             required to compute eigenvalues efficiently
00286 *          if JOBZ='V' RWORK(1) = optimal amount of workspace
00287 *             required to compute eigenvalues and eigenvectors
00288 *             efficiently with no guarantee on orthogonality.
00289 *             If RANGE='V', it is assumed that all eigenvectors
00290 *             may be required.
00291 *
00292 *  LRWORK   (local input) INTEGER
00293 *          Size of RWORK
00294 *          See below for definitions of variables used to define LRWORK.
00295 *          If no eigenvectors are requested (JOBZ = 'N') then
00296 *             LRWORK >= 5 * NN + 4 * N
00297 *          If eigenvectors are requested (JOBZ = 'V' ) then
00298 *             the amount of workspace required to guarantee that all
00299 *             eigenvectors are computed is:
00300 *             LRWORK >= 4*N + MAX( 5*NN, NP0 * MQ0 ) +
00301 *               ICEIL( NEIG, NPROW*NPCOL)*NN
00302 *
00303 *             The computed eigenvectors may not be orthogonal if the
00304 *             minimal workspace is supplied and ORFAC is too small.
00305 *             If you want to guarantee orthogonality (at the cost
00306 *             of potentially poor performance) you should add
00307 *             the following to LRWORK:
00308 *                (CLUSTERSIZE-1)*N
00309 *             where CLUSTERSIZE is the number of eigenvalues in the
00310 *             largest cluster, where a cluster is defined as a set of
00311 *             close eigenvalues: { W(K),...,W(K+CLUSTERSIZE-1) |
00312 *                                  W(J+1) <= W(J) + ORFAC*2*norm(A) }
00313 *          Variable definitions:
00314 *             NEIG = number of eigenvectors requested
00315 *             NB = DESCA( MB_ ) = DESCA( NB_ ) =
00316 *                  DESCZ( MB_ ) = DESCZ( NB_ )
00317 *             NN = MAX( N, NB, 2 )
00318 *             DESCA( RSRC_ ) = DESCA( NB_ ) = DESCZ( RSRC_ ) =
00319 *                              DESCZ( CSRC_ ) = 0
00320 *             NP0 = NUMROC( NN, NB, 0, 0, NPROW )
00321 *             MQ0 = NUMROC( MAX( NEIG, NB, 2 ), NB, 0, 0, NPCOL )
00322 *             ICEIL( X, Y ) is a ScaLAPACK function returning
00323 *             ceiling(X/Y)
00324 *
00325 *          When LRWORK is too small:
00326 *             If LRWORK is too small to guarantee orthogonality,
00327 *             PZHEEVX attempts to maintain orthogonality in
00328 *             the clusters with the smallest
00329 *             spacing between the eigenvalues.
00330 *             If LRWORK is too small to compute all the eigenvectors
00331 *             requested, no computation is performed and INFO=-25
00332 *             is returned.  Note that when RANGE='V', PZHEEVX does
00333 *             not know how many eigenvectors are requested until
00334 *             the eigenvalues are computed.  Therefore, when RANGE='V'
00335 *             and as long as LRWORK is large enough to allow PZHEEVX to
00336 *             compute the eigenvalues, PZHEEVX will compute the
00337 *             eigenvalues and as many eigenvectors as it can.
00338 *
00339 *          Relationship between workspace, orthogonality & performance:
00340 *             If CLUSTERSIZE >= N/SQRT(NPROW*NPCOL), then providing
00341 *             enough space to compute all the eigenvectors
00342 *             orthogonally will cause serious degradation in
00343 *             performance. In the limit (i.e. CLUSTERSIZE = N-1)
00344 *             PZSTEIN will perform no better than ZSTEIN on 1
00345 *             processor.
00346 *             For CLUSTERSIZE = N/SQRT(NPROW*NPCOL) reorthogonalizing
00347 *             all eigenvectors will increase the total execution time
00348 *             by a factor of 2 or more.
00349 *             For CLUSTERSIZE > N/SQRT(NPROW*NPCOL) execution time will
00350 *             grow as the square of the cluster size, all other factors
00351 *             remaining equal and assuming enough workspace.  Less
00352 *             workspace means less reorthogonalization but faster
00353 *             execution.
00354 *
00355 *          If LRWORK = -1, then LRWORK is global input and a workspace
00356 *          query is assumed; the routine only calculates the size
00357 *          required for optimal performance for all work arrays. Each of
00358 *          these values is returned in the first entry of the
00359 *          corresponding work arrays, and no error message is issued by
00360 *          PXERBLA.
00361 *
00362 *  IWORK   (local workspace) INTEGER array
00363 *          On return, IWORK(1) contains the amount of integer workspace
00364 *          required.
00365 *
00366 *  LIWORK  (local input) INTEGER
00367 *          size of IWORK
00368 *          LIWORK >= 6 * NNP
00369 *          Where:
00370 *            NNP = MAX( N, NPROW*NPCOL + 1, 4 )
00371 *          If LIWORK = -1, then LIWORK is global input and a workspace
00372 *          query is assumed; the routine only calculates the minimum
00373 *          and optimal size for all work arrays. Each of these
00374 *          values is returned in the first entry of the corresponding
00375 *          work array, and no error message is issued by PXERBLA.
00376 *
00377 *  IFAIL   (global output) INTEGER array, dimension (N)
00378 *          If JOBZ = 'V', then on normal exit, the first M elements of
00379 *          IFAIL are zero.  If (MOD(INFO,2).NE.0) on exit, then
00380 *          IFAIL contains the
00381 *          indices of the eigenvectors that failed to converge.
00382 *          If JOBZ = 'N', then IFAIL is not referenced.
00383 *
00384 *  ICLUSTR (global output) integer array, dimension (2*NPROW*NPCOL)
00385 *          This array contains indices of eigenvectors corresponding to
00386 *          a cluster of eigenvalues that could not be reorthogonalized
00387 *          due to insufficient workspace (see LWORK, ORFAC and INFO).
00388 *          Eigenvectors corresponding to clusters of eigenvalues indexed
00389 *          ICLUSTR(2*I-1) to ICLUSTR(2*I), could not be
00390 *          reorthogonalized due to lack of workspace. Hence the
00391 *          eigenvectors corresponding to these clusters may not be
00392 *          orthogonal.  ICLUSTR() is a zero terminated array.
00393 *          (ICLUSTR(2*K).NE.0 .AND. ICLUSTR(2*K+1).EQ.0) if and only if
00394 *          K is the number of clusters
00395 *          ICLUSTR is not referenced if JOBZ = 'N'
00396 *
00397 *  GAP     (global output) DOUBLE PRECISION array,
00398 *             dimension (NPROW*NPCOL)
00399 *          This array contains the gap between eigenvalues whose
00400 *          eigenvectors could not be reorthogonalized. The output
00401 *          values in this array correspond to the clusters indicated
00402 *          by the array ICLUSTR. As a result, the dot product between
00403 *          eigenvectors correspoding to the I^th cluster may be as high
00404 *          as ( C * n ) / GAP(I) where C is a small constant.
00405 *
00406 *  INFO    (global output) INTEGER
00407 *          = 0:  successful exit
00408 *          < 0:  If the i-th argument is an array and the j-entry had
00409 *                an illegal value, then INFO = -(i*100+j), if the i-th
00410 *                argument is a scalar and had an illegal value, then
00411 *                INFO = -i.
00412 *          > 0:  if (MOD(INFO,2).NE.0), then one or more eigenvectors
00413 *                  failed to converge.  Their indices are stored
00414 *                  in IFAIL.  Ensure ABSTOL=2.0*PDLAMCH( 'U' )
00415 *                  Send e-mail to scalapack@cs.utk.edu
00416 *                if (MOD(INFO/2,2).NE.0),then eigenvectors corresponding
00417 *                  to one or more clusters of eigenvalues could not be
00418 *                  reorthogonalized because of insufficient workspace.
00419 *                  The indices of the clusters are stored in the array
00420 *                  ICLUSTR.
00421 *                if (MOD(INFO/4,2).NE.0), then space limit prevented
00422 *                  PZHEEVX from computing all of the eigenvectors
00423 *                  between VL and VU.  The number of eigenvectors
00424 *                  computed is returned in NZ.
00425 *                if (MOD(INFO/8,2).NE.0), then PZSTEBZ failed to compute
00426 *                  eigenvalues.  Ensure ABSTOL=2.0*PDLAMCH( 'U' )
00427 *                  Send e-mail to scalapack@cs.utk.edu
00428 *
00429 *  Alignment requirements
00430 *  ======================
00431 *
00432 *  The distributed submatrices A(IA:*, JA:*) and C(IC:IC+M-1,JC:JC+N-1)
00433 *  must verify some alignment properties, namely the following
00434 *  expressions should be true:
00435 *
00436 *  ( MB_A.EQ.NB_A.EQ.MB_Z .AND. IROFFA.EQ.IROFFZ .AND. IROFFA.EQ.0 .AND.
00437 *    IAROW.EQ.IZROW )
00438 *  where
00439 *  IROFFA = MOD( IA-1, MB_A ) and ICOFFA = MOD( JA-1, NB_A ).
00440 *
00441 *  =====================================================================
00442 *
00443 *  Differences between PZHEEVX and ZHEEVX
00444 *  ======================================
00445 *
00446 *  A, LDA -> A, IA, JA, DESCA
00447 *  Z, LDZ -> Z, IZ, JZ, DESCZ
00448 *  WORKSPACE needs are larger for PZHEEVX.
00449 *  LIWORK parameter added
00450 *
00451 *  ORFAC, ICLUSTER() and GAP() parameters added
00452 *  meaning of INFO is changed
00453 *
00454 *  Functional differences:
00455 *  PZHEEVX does not promise orthogonality for eigenvectors associated
00456 *  with tighly clustered eigenvalues.
00457 *  PZHEEVX does not reorthogonalize eigenvectors
00458 *  that are on different processes. The extent of reorthogonalization
00459 *  is controlled by the input parameter LWORK.
00460 *
00461 *  Version 1.4 limitations:
00462 *     DESCA(MB_) = DESCA(NB_)
00463 *     DESCA(M_) = DESCZ(M_)
00464 *     DESCA(N_) = DESCZ(N_)
00465 *     DESCA(MB_) = DESCZ(MB_)
00466 *     DESCA(NB_) = DESCZ(NB_)
00467 *     DESCA(RSRC_) = DESCZ(RSRC_)
00468 *
00469 *     .. Parameters ..
00470       INTEGER            BLOCK_CYCLIC_2D, DLEN_, DTYPE_, CTXT_, M_, N_,
00471      $                   MB_, NB_, RSRC_, CSRC_, LLD_
00472       PARAMETER          ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
00473      $                   CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
00474      $                   RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
00475       DOUBLE PRECISION   ZERO, ONE, TEN, FIVE
00476       PARAMETER          ( ZERO = 0.0D+0, ONE = 1.0D+0, TEN = 10.0D+0,
00477      $                   FIVE = 5.0D+0 )
00478       INTEGER            IERREIN, IERRCLS, IERRSPC, IERREBZ
00479       PARAMETER          ( IERREIN = 1, IERRCLS = 2, IERRSPC = 4,
00480      $                   IERREBZ = 8 )
00481 *     ..
00482 *     .. Local Scalars ..
00483       LOGICAL            ALLEIG, INDEIG, LOWER, LQUERY, QUICKRETURN,
00484      $                   VALEIG, WANTZ
00485       CHARACTER          ORDER
00486       INTEGER            ANB, CSRC_A, I, IAROW, ICOFFA, ICTXT, IINFO,
00487      $                   INDD, INDD2, INDE, INDE2, INDIBL, INDISP,
00488      $                   INDRWORK, INDTAU, INDWORK, IROFFA, IROFFZ,
00489      $                   ISCALE, ISIZESTEBZ, ISIZESTEIN, IZROW,
00490      $                   LALLWORK, LIWMIN, LLRWORK, LLWORK, LRWMIN,
00491      $                   LRWOPT, LWMIN, LWOPT, MAXEIGS, MB_A, MQ0,
00492      $                   MYCOL, MYROW, NB, NB_A, NEIG, NHETRD_LWOPT, NN,
00493      $                   NNP, NP0, NPCOL, NPROCS, NPROW, NPS, NQ0,
00494      $                   NSPLIT, NZZ, OFFSET, RSRC_A, RSRC_Z, SIZEHEEVX,
00495      $                   SIZESTEIN, SQNPC
00496       DOUBLE PRECISION   ABSTLL, ANRM, BIGNUM, EPS, RMAX, RMIN, SAFMIN,
00497      $                   SIGMA, SMLNUM, VLL, VUU
00498 *     ..
00499 *     .. Local Arrays ..
00500       INTEGER            IDUM1( 4 ), IDUM2( 4 )
00501 *     ..
00502 *     .. External Functions ..
00503       LOGICAL            LSAME
00504       INTEGER            ICEIL, INDXG2P, NUMROC, PJLAENV
00505       DOUBLE PRECISION   PDLAMCH, PZLANHE
00506       EXTERNAL           LSAME, ICEIL, INDXG2P, NUMROC, PJLAENV,
00507      $                   PDLAMCH, PZLANHE
00508 *     ..
00509 *     .. External Subroutines ..
00510       EXTERNAL           BLACS_GRIDINFO, CHK1MAT, DGEBR2D, DGEBS2D,
00511      $                   DLASRT, DSCAL, IGAMN2D, PCHK1MAT, PCHK2MAT,
00512      $                   PDLARED1D, PDSTEBZ, PXERBLA, PZELGET, PZHENTRD,
00513      $                   PZLASCL, PZSTEIN, PZUNMTR
00514 *     ..
00515 *     .. Intrinsic Functions ..
00516       INTRINSIC          ABS, DBLE, DCMPLX, ICHAR, INT, MAX, MIN, MOD,
00517      $                   SQRT
00518 *     ..
00519 *     .. Executable Statements ..
00520 *       This is just to keep ftnchek and toolpack/1 happy
00521       IF( BLOCK_CYCLIC_2D*CSRC_*CTXT_*DLEN_*DTYPE_*LLD_*MB_*M_*NB_*N_*
00522      $    RSRC_.LT.0 )RETURN
00523 *
00524       QUICKRETURN = ( N.EQ.0 )
00525 *
00526 *     Test the input arguments.
00527 *
00528       ICTXT = DESCA( CTXT_ )
00529       CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
00530       INFO = 0
00531 *
00532       WANTZ = LSAME( JOBZ, 'V' )
00533       IF( NPROW.EQ.-1 ) THEN
00534          INFO = -( 800+CTXT_ )
00535       ELSE IF( WANTZ ) THEN
00536          IF( ICTXT.NE.DESCZ( CTXT_ ) ) THEN
00537             INFO = -( 2100+CTXT_ )
00538          END IF
00539       END IF
00540       IF( INFO.EQ.0 ) THEN
00541          CALL CHK1MAT( N, 4, N, 4, IA, JA, DESCA, 8, INFO )
00542          IF( WANTZ )
00543      $      CALL CHK1MAT( N, 4, N, 4, IZ, JZ, DESCZ, 21, INFO )
00544 *
00545          IF( INFO.EQ.0 ) THEN
00546 *
00547 *     Get machine constants.
00548 *
00549             SAFMIN = PDLAMCH( ICTXT, 'Safe minimum' )
00550             EPS = PDLAMCH( ICTXT, 'Precision' )
00551             SMLNUM = SAFMIN / EPS
00552             BIGNUM = ONE / SMLNUM
00553             RMIN = SQRT( SMLNUM )
00554             RMAX = MIN( SQRT( BIGNUM ), ONE / SQRT( SQRT( SAFMIN ) ) )
00555 *
00556             NPROCS = NPROW*NPCOL
00557             LOWER = LSAME( UPLO, 'L' )
00558             ALLEIG = LSAME( RANGE, 'A' )
00559             VALEIG = LSAME( RANGE, 'V' )
00560             INDEIG = LSAME( RANGE, 'I' )
00561 *
00562 *     Set up pointers into the WORK array
00563 *
00564             INDTAU = 1
00565             INDWORK = INDTAU + N
00566             LLWORK = LWORK - INDWORK + 1
00567 *
00568 *     Set up pointers into the RWORK array
00569 *
00570             INDE = 1
00571             INDD = INDE + N
00572             INDD2 = INDD + N
00573             INDE2 = INDD2 + N
00574             INDRWORK = INDE2 + N
00575             LLRWORK = LRWORK - INDRWORK + 1
00576 *
00577 *     Set up pointers into the IWORK array
00578 *
00579             ISIZESTEIN = 3*N + NPROCS + 1
00580             ISIZESTEBZ = MAX( 4*N, 14, NPROCS )
00581             INDIBL = ( MAX( ISIZESTEIN, ISIZESTEBZ ) ) + 1
00582             INDISP = INDIBL + N
00583 *
00584 *     Compute the total amount of space needed
00585 *
00586             LQUERY = .FALSE.
00587             IF( LWORK.EQ.-1 .OR. LIWORK.EQ.-1 .OR. LRWORK.EQ.-1 )
00588      $         LQUERY = .TRUE.
00589 *
00590             NNP = MAX( N, NPROCS+1, 4 )
00591             LIWMIN = 6*NNP
00592 *
00593             NPROCS = NPROW*NPCOL
00594             NB_A = DESCA( NB_ )
00595             MB_A = DESCA( MB_ )
00596             NB = NB_A
00597             NN = MAX( N, NB, 2 )
00598 *
00599             RSRC_A = DESCA( RSRC_ )
00600             CSRC_A = DESCA( CSRC_ )
00601             IROFFA = MOD( IA-1, MB_A )
00602             ICOFFA = MOD( JA-1, NB_A )
00603             IAROW = INDXG2P( 1, NB_A, MYROW, RSRC_A, NPROW )
00604             NP0 = NUMROC( N+IROFFA, NB, 0, 0, NPROW )
00605             MQ0 = NUMROC( N+ICOFFA, NB, 0, 0, NPCOL )
00606             IF( WANTZ ) THEN
00607                RSRC_Z = DESCZ( RSRC_ )
00608                IROFFZ = MOD( IZ-1, MB_A )
00609                IZROW = INDXG2P( 1, NB_A, MYROW, RSRC_Z, NPROW )
00610             ELSE
00611                IROFFZ = 0
00612                IZROW = 0
00613             END IF
00614 *
00615             IF( ( .NOT.WANTZ ) .OR. ( VALEIG .AND. ( .NOT.LQUERY ) ) )
00616      $           THEN
00617                LWMIN = N + MAX( NB*( NP0+1 ), 3 )
00618                LWOPT = LWMIN
00619                LRWMIN = 5*NN + 4*N
00620                IF( WANTZ ) THEN
00621                   MQ0 = NUMROC( MAX( N, NB, 2 ), NB, 0, 0, NPCOL )
00622                   LRWOPT = 4*N + MAX( 5*NN, NP0*MQ0 ) +
00623      $                     ICEIL( N, NPROW*NPCOL )*NN
00624                ELSE
00625                   LRWOPT = LRWMIN
00626                END IF
00627                NEIG = 0
00628             ELSE
00629                IF( ALLEIG .OR. VALEIG ) THEN
00630                   NEIG = N
00631                ELSE IF( INDEIG ) THEN
00632                   NEIG = IU - IL + 1
00633                END IF
00634                MQ0 = NUMROC( MAX( NEIG, NB, 2 ), NB, 0, 0, NPCOL )
00635                NQ0 = NUMROC( NN, NB, 0, 0, NPCOL )
00636                LWMIN = N + ( NP0+NQ0+NB )*NB
00637                LRWMIN = 4*N + MAX( 5*NN, NP0*MQ0 ) +
00638      $                  ICEIL( NEIG, NPROW*NPCOL )*NN
00639                LRWOPT = LRWMIN
00640                LWOPT = LWMIN
00641 *
00642             END IF
00643 *
00644 *           Compute how much workspace is needed to use the
00645 *           new TRD code
00646 *
00647             ANB = PJLAENV( ICTXT, 3, 'PZHETTRD', 'L', 0, 0, 0, 0 )
00648             SQNPC = INT( SQRT( DBLE( NPROW*NPCOL ) ) )
00649             NPS = MAX( NUMROC( N, 1, 0, 0, SQNPC ), 2*ANB )
00650             NHETRD_LWOPT = 2*( ANB+1 )*( 4*NPS+2 ) + ( NPS+2 )*NPS
00651             LWOPT = MAX( LWOPT, N+NHETRD_LWOPT )
00652 *
00653          END IF
00654          IF( INFO.EQ.0 ) THEN
00655             IF( MYROW.EQ.0 .AND. MYCOL.EQ.0 ) THEN
00656                RWORK( 1 ) = ABSTOL
00657                IF( VALEIG ) THEN
00658                   RWORK( 2 ) = VL
00659                   RWORK( 3 ) = VU
00660                ELSE
00661                   RWORK( 2 ) = ZERO
00662                   RWORK( 3 ) = ZERO
00663                END IF
00664                CALL DGEBS2D( ICTXT, 'ALL', ' ', 3, 1, RWORK, 3 )
00665             ELSE
00666                CALL DGEBR2D( ICTXT, 'ALL', ' ', 3, 1, RWORK, 3, 0, 0 )
00667             END IF
00668             IF( .NOT.( WANTZ .OR. LSAME( JOBZ, 'N' ) ) ) THEN
00669                INFO = -1
00670             ELSE IF( .NOT.( ALLEIG .OR. VALEIG .OR. INDEIG ) ) THEN
00671                INFO = -2
00672             ELSE IF( .NOT.( LOWER .OR. LSAME( UPLO, 'U' ) ) ) THEN
00673                INFO = -3
00674             ELSE IF( VALEIG .AND. N.GT.0 .AND. VU.LE.VL ) THEN
00675                INFO = -10
00676             ELSE IF( INDEIG .AND. ( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) )
00677      $                THEN
00678                INFO = -11
00679             ELSE IF( INDEIG .AND. ( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) )
00680      $                THEN
00681                INFO = -12
00682             ELSE IF( LWORK.LT.LWMIN .AND. LWORK.NE.-1 ) THEN
00683                INFO = -23
00684             ELSE IF( LRWORK.LT.LRWMIN .AND. LRWORK.NE.-1 ) THEN
00685                INFO = -25
00686             ELSE IF( LIWORK.LT.LIWMIN .AND. LIWORK.NE.-1 ) THEN
00687                INFO = -27
00688             ELSE IF( VALEIG .AND. ( ABS( RWORK( 2 )-VL ).GT.FIVE*EPS*
00689      $               ABS( VL ) ) ) THEN
00690                INFO = -9
00691             ELSE IF( VALEIG .AND. ( ABS( RWORK( 3 )-VU ).GT.FIVE*EPS*
00692      $               ABS( VU ) ) ) THEN
00693                INFO = -10
00694             ELSE IF( ABS( RWORK( 1 )-ABSTOL ).GT.FIVE*EPS*
00695      $               ABS( ABSTOL ) ) THEN
00696                INFO = -13
00697             ELSE IF( IROFFA.NE.0 ) THEN
00698                INFO = -6
00699             ELSE IF( DESCA( MB_ ).NE.DESCA( NB_ ) ) THEN
00700                INFO = -( 800+NB_ )
00701             END IF
00702             IF( WANTZ ) THEN
00703                IF( IROFFA.NE.IROFFZ ) THEN
00704                   INFO = -19
00705                ELSE IF( IAROW.NE.IZROW ) THEN
00706                   INFO = -19
00707                ELSE IF( DESCA( M_ ).NE.DESCZ( M_ ) ) THEN
00708                   INFO = -( 2100+M_ )
00709                ELSE IF( DESCA( N_ ).NE.DESCZ( N_ ) ) THEN
00710                   INFO = -( 2100+N_ )
00711                ELSE IF( DESCA( MB_ ).NE.DESCZ( MB_ ) ) THEN
00712                   INFO = -( 2100+MB_ )
00713                ELSE IF( DESCA( NB_ ).NE.DESCZ( NB_ ) ) THEN
00714                   INFO = -( 2100+NB_ )
00715                ELSE IF( DESCA( RSRC_ ).NE.DESCZ( RSRC_ ) ) THEN
00716                   INFO = -( 2100+RSRC_ )
00717                ELSE IF( DESCA( CSRC_ ).NE.DESCZ( CSRC_ ) ) THEN
00718                   INFO = -( 2100+CSRC_ )
00719                ELSE IF( ICTXT.NE.DESCZ( CTXT_ ) ) THEN
00720                   INFO = -( 2100+CTXT_ )
00721                END IF
00722             END IF
00723          END IF
00724          IF( WANTZ ) THEN
00725             IDUM1( 1 ) = ICHAR( 'V' )
00726          ELSE
00727             IDUM1( 1 ) = ICHAR( 'N' )
00728          END IF
00729          IDUM2( 1 ) = 1
00730          IF( LOWER ) THEN
00731             IDUM1( 2 ) = ICHAR( 'L' )
00732          ELSE
00733             IDUM1( 2 ) = ICHAR( 'U' )
00734          END IF
00735          IDUM2( 2 ) = 2
00736          IF( ALLEIG ) THEN
00737             IDUM1( 3 ) = ICHAR( 'A' )
00738          ELSE IF( INDEIG ) THEN
00739             IDUM1( 3 ) = ICHAR( 'I' )
00740          ELSE
00741             IDUM1( 3 ) = ICHAR( 'V' )
00742          END IF
00743          IDUM2( 3 ) = 3
00744          IF( LQUERY ) THEN
00745             IDUM1( 4 ) = -1
00746          ELSE
00747             IDUM1( 4 ) = 1
00748          END IF
00749          IDUM2( 4 ) = 4
00750          IF( WANTZ ) THEN
00751             CALL PCHK2MAT( N, 4, N, 4, IA, JA, DESCA, 8, N, 4, N, 4, IZ,
00752      $                     JZ, DESCZ, 21, 4, IDUM1, IDUM2, INFO )
00753          ELSE
00754             CALL PCHK1MAT( N, 4, N, 4, IA, JA, DESCA, 8, 4, IDUM1,
00755      $                     IDUM2, INFO )
00756          END IF
00757          WORK( 1 ) = DCMPLX( LWOPT )
00758          RWORK( 1 ) = DBLE( LRWOPT )
00759          IWORK( 1 ) = LIWMIN
00760       END IF
00761 *
00762       IF( INFO.NE.0 ) THEN
00763          CALL PXERBLA( ICTXT, 'PZHEEVX', -INFO )
00764          RETURN
00765       ELSE IF( LQUERY ) THEN
00766          RETURN
00767       END IF
00768 *
00769 *     Quick return if possible
00770 *
00771       IF( QUICKRETURN ) THEN
00772          IF( WANTZ ) THEN
00773             NZ = 0
00774             ICLUSTR( 1 ) = 0
00775          END IF
00776          M = 0
00777          WORK( 1 ) = DCMPLX( LWOPT )
00778          RWORK( 1 ) = DBLE( LRWMIN )
00779          IWORK( 1 ) = LIWMIN
00780          RETURN
00781       END IF
00782 *
00783 *     Scale matrix to allowable range, if necessary.
00784 *
00785       ABSTLL = ABSTOL
00786       ISCALE = 0
00787       IF( VALEIG ) THEN
00788          VLL = VL
00789          VUU = VU
00790       ELSE
00791          VLL = ZERO
00792          VUU = ZERO
00793       END IF
00794 *
00795       ANRM = PZLANHE( 'M', UPLO, N, A, IA, JA, DESCA,
00796      $       RWORK( INDRWORK ) )
00797 *
00798       IF( ANRM.GT.ZERO .AND. ANRM.LT.RMIN ) THEN
00799          ISCALE = 1
00800          SIGMA = RMIN / ANRM
00801          ANRM = ANRM*SIGMA
00802       ELSE IF( ANRM.GT.RMAX ) THEN
00803          ISCALE = 1
00804          SIGMA = RMAX / ANRM
00805          ANRM = ANRM*SIGMA
00806       END IF
00807 *
00808       IF( ISCALE.EQ.1 ) THEN
00809          CALL PZLASCL( UPLO, ONE, SIGMA, N, N, A, IA, JA, DESCA, IINFO )
00810          IF( ABSTOL.GT.0 )
00811      $      ABSTLL = ABSTOL*SIGMA
00812          IF( VALEIG ) THEN
00813             VLL = VL*SIGMA
00814             VUU = VU*SIGMA
00815             IF( VUU.EQ.VLL ) THEN
00816                VUU = VUU + 2*MAX( ABS( VUU )*EPS, SAFMIN )
00817             END IF
00818          END IF
00819       END IF
00820 *
00821 *     Call PZHENTRD to reduce Hermitian matrix to tridiagonal form.
00822 *
00823       LALLWORK = LLRWORK
00824 *
00825       CALL PZHENTRD( UPLO, N, A, IA, JA, DESCA, RWORK( INDD ),
00826      $               RWORK( INDE ), WORK( INDTAU ), WORK( INDWORK ),
00827      $               LLWORK, RWORK( INDRWORK ), LLRWORK, IINFO )
00828 *
00829 *
00830 *     Copy the values of D, E to all processes
00831 *
00832 *     Here PxLARED1D is used to redistribute the tridiagonal matrix.
00833 *     PxLARED1D, however, doesn't yet work with arbritary matrix
00834 *     distributions so we have PxELGET as a backup.
00835 *
00836       OFFSET = 0
00837       IF( IA.EQ.1 .AND. JA.EQ.1 .AND. RSRC_A.EQ.0 .AND. CSRC_A.EQ.0 )
00838      $     THEN
00839          CALL PDLARED1D( N, IA, JA, DESCA, RWORK( INDD ),
00840      $                   RWORK( INDD2 ), RWORK( INDRWORK ), LLRWORK )
00841 *
00842          CALL PDLARED1D( N, IA, JA, DESCA, RWORK( INDE ),
00843      $                   RWORK( INDE2 ), RWORK( INDRWORK ), LLRWORK )
00844          IF( .NOT.LOWER )
00845      $      OFFSET = 1
00846       ELSE
00847          DO 10 I = 1, N
00848             CALL PZELGET( 'A', ' ', WORK( INDD2+I-1 ), A, I+IA-1,
00849      $                    I+JA-1, DESCA )
00850             RWORK( INDD2+I-1 ) = DBLE( WORK( INDD2+I-1 ) )
00851    10    CONTINUE
00852          IF( LSAME( UPLO, 'U' ) ) THEN
00853             DO 20 I = 1, N - 1
00854                CALL PZELGET( 'A', ' ', WORK( INDE2+I-1 ), A, I+IA-1,
00855      $                       I+JA, DESCA )
00856                RWORK( INDE2+I-1 ) = DBLE( WORK( INDE2+I-1 ) )
00857    20       CONTINUE
00858          ELSE
00859             DO 30 I = 1, N - 1
00860                CALL PZELGET( 'A', ' ', WORK( INDE2+I-1 ), A, I+IA,
00861      $                       I+JA-1, DESCA )
00862                RWORK( INDE2+I-1 ) = DBLE( WORK( INDE2+I-1 ) )
00863    30       CONTINUE
00864          END IF
00865       END IF
00866 *
00867 *     Call PDSTEBZ and, if eigenvectors are desired, PZSTEIN.
00868 *
00869       IF( WANTZ ) THEN
00870          ORDER = 'B'
00871       ELSE
00872          ORDER = 'E'
00873       END IF
00874 *
00875       CALL PDSTEBZ( ICTXT, RANGE, ORDER, N, VLL, VUU, IL, IU, ABSTLL,
00876      $              RWORK( INDD2 ), RWORK( INDE2+OFFSET ), M, NSPLIT, W,
00877      $              IWORK( INDIBL ), IWORK( INDISP ), RWORK( INDRWORK ),
00878      $              LLRWORK, IWORK( 1 ), ISIZESTEBZ, IINFO )
00879 *
00880 *
00881 *     IF PDSTEBZ fails, the error propogates to INFO, but
00882 *     we do not propogate the eigenvalue(s) which failed because:
00883 *     1)  This should never happen if the user specifies
00884 *         ABSTOL = 2 * PDLAMCH( 'U' )
00885 *     2)  PDSTEIN will confirm/deny whether the eigenvalues are
00886 *         close enough.
00887 *
00888       IF( IINFO.NE.0 ) THEN
00889          INFO = INFO + IERREBZ
00890          DO 40 I = 1, M
00891             IWORK( INDIBL+I-1 ) = ABS( IWORK( INDIBL+I-1 ) )
00892    40    CONTINUE
00893       END IF
00894       IF( WANTZ ) THEN
00895 *
00896          IF( VALEIG ) THEN
00897 *
00898 *           Compute the maximum number of eigenvalues that we can
00899 *           compute in the
00900 *           workspace that we have, and that we can store in Z.
00901 *
00902 *           Loop through the possibilities looking for the largest
00903 *           NZ that we can feed to PZSTEIN and PZUNMTR
00904 *
00905 *           Since all processes must end up with the same value
00906 *           of NZ, we first compute the minimum of LALLWORK
00907 *
00908             CALL IGAMN2D( ICTXT, 'A', ' ', 1, 1, LALLWORK, 1, 1, 1, -1,
00909      $                    -1, -1 )
00910 *
00911             MAXEIGS = DESCZ( N_ )
00912 *
00913             DO 50 NZ = MIN( MAXEIGS, M ), 0, -1
00914                MQ0 = NUMROC( NZ, NB, 0, 0, NPCOL )
00915                SIZESTEIN = ICEIL( NZ, NPROCS )*N + MAX( 5*N, NP0*MQ0 )
00916                SIZEHEEVX = SIZESTEIN
00917                IF( SIZEHEEVX.LE.LALLWORK )
00918      $            GO TO 60
00919    50       CONTINUE
00920    60       CONTINUE
00921          ELSE
00922             NZ = M
00923          END IF
00924          NZ = MAX( NZ, 0 )
00925          IF( NZ.NE.M ) THEN
00926             INFO = INFO + IERRSPC
00927 *
00928             DO 70 I = 1, M
00929                IFAIL( I ) = 0
00930    70       CONTINUE
00931 *
00932 *     The following code handles a rare special case
00933 *       - NZ .NE. M means that we don't have enough room to store
00934 *         all the vectors.
00935 *       - NSPLIT .GT. 1 means that the matrix split
00936 *     In this case, we cannot simply take the first NZ eigenvalues
00937 *     because PDSTEBZ sorts the eigenvalues by block when
00938 *     a split occurs.  So, we have to make another call to
00939 *     PDSTEBZ with a new upper limit - VUU.
00940 *
00941             IF( NSPLIT.GT.1 ) THEN
00942                CALL DLASRT( 'I', M, W, IINFO )
00943                NZZ = 0
00944                IF( NZ.GT.0 ) THEN
00945 *
00946                   VUU = W( NZ ) - TEN*( EPS*ANRM+SAFMIN )
00947                   IF( VLL.GE.VUU ) THEN
00948                      NZZ = 0
00949                   ELSE
00950                      CALL PDSTEBZ( ICTXT, RANGE, ORDER, N, VLL, VUU, IL,
00951      $                             IU, ABSTLL, RWORK( INDD2 ),
00952      $                             RWORK( INDE2+OFFSET ), NZZ, NSPLIT,
00953      $                             W, IWORK( INDIBL ), IWORK( INDISP ),
00954      $                             RWORK( INDRWORK ), LLRWORK,
00955      $                             IWORK( 1 ), ISIZESTEBZ, IINFO )
00956                   END IF
00957 *
00958                   IF( MOD( INFO / IERREBZ, 1 ).EQ.0 ) THEN
00959                      IF( NZZ.GT.NZ .OR. IINFO.NE.0 ) THEN
00960                         INFO = INFO + IERREBZ
00961                      END IF
00962                   END IF
00963                END IF
00964                NZ = MIN( NZ, NZZ )
00965 *
00966             END IF
00967          END IF
00968          CALL PZSTEIN( N, RWORK( INDD2 ), RWORK( INDE2+OFFSET ), NZ, W,
00969      $                 IWORK( INDIBL ), IWORK( INDISP ), ORFAC, Z, IZ,
00970      $                 JZ, DESCZ, RWORK( INDRWORK ), LALLWORK,
00971      $                 IWORK( 1 ), ISIZESTEIN, IFAIL, ICLUSTR, GAP,
00972      $                 IINFO )
00973 *
00974          IF( IINFO.GE.NZ+1 )
00975      $      INFO = INFO + IERRCLS
00976          IF( MOD( IINFO, NZ+1 ).NE.0 )
00977      $      INFO = INFO + IERREIN
00978 *
00979 *     Z = Q * Z
00980 *
00981 *
00982          IF( NZ.GT.0 ) THEN
00983             CALL PZUNMTR( 'L', UPLO, 'N', N, NZ, A, IA, JA, DESCA,
00984      $                    WORK( INDTAU ), Z, IZ, JZ, DESCZ,
00985      $                    WORK( INDWORK ), LLWORK, IINFO )
00986          END IF
00987 *
00988       END IF
00989 *
00990 *     If matrix was scaled, then rescale eigenvalues appropriately.
00991 *
00992       IF( ISCALE.EQ.1 ) THEN
00993          CALL DSCAL( M, ONE / SIGMA, W, 1 )
00994       END IF
00995 *
00996       WORK( 1 ) = DCMPLX( LWOPT )
00997       RWORK( 1 ) = DBLE( LRWOPT )
00998       IWORK( 1 ) = LIWMIN
00999 *
01000       RETURN
01001 *
01002 *     End of PZHEEVX
01003 *
01004       END