|
ScaLAPACK
2.0.2
ScaLAPACK: Scalable Linear Algebra PACKage
|
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