PZSTEIN(l)
π¦ PZSTEIN(l) π¦
okay so this is the LAPACK routine PZSTEIN, version 1.5, and she is that girl. sit down, grab a snack, we're doing linear algebra bestie π
β¨ NAME β¨
PZSTEIN β computes the eigenvectors of a symmetric tridiagonal matrix in parallel, using inverse iteration. no cap, that's literally the whole job description π«Ά
πΈ SYNOPSIS πΈ
SUBROUTINE PZSTEIN( N, D, E, M, W, IBLOCK, ISPLIT, ORFAC, Z, IZ, JZ,
DESCZ, WORK, LWORK, IWORK, LIWORK, IFAIL, ICLUSTR,
GAP, INFO )
INTEGER INFO, IZ, JZ, LIWORK, LWORK, M, N
DOUBLE PRECISION ORFAC
INTEGER DESCZ( * ), IBLOCK( * ), ICLUSTR( * ), IFAIL( * ),
ISPLIT( * ), IWORK( * )
DOUBLE PRECISION D( * ), E( * ), GAP( * ), W( * ), WORK( *
)
COMPLEX*16 Z( * )
like look at all those arguments. main character energy fr fr π
π PURPOSE π
PZSTEIN computes the eigenvectors of a symmetric tridiagonal matrix in parallel, using inverse iteration. The eigenvectors found correspond to user specified eigenvalues. And here's the tea, bestie: PZSTEIN does not orthogonalize vectors that are on different processes. The extent of orthogonalization is controlled by the input parameter LWORK. Eigenvectors that are to be orthogonalized are computed by the same process. PZSTEIN decides on the allocation of work among the processes and then calls DSTEIN2 (a modified LAPACK routine) on each individual process. And if insufficient workspace is allocated, the expected orthogonalization may not be done. π
π Note : If the eigenvectors obtained are not orthogonal, increase LWORK and run the code again. that's it, that's the fix, just throw more workspace at it and try again.
π Notes π
Each global data object is described by an associated description vector. This vector stores the information required to establish the mapping between an object element and its corresponding process and memory location. iykyk π§
Let A be a generic term for any 2D block cyclicly distributed array. Such a global array has an associated description vector DESCA. In the following comments, the character _ should be read as "of the global array". periodt.
So here's the whole notation breakdown, one bullet at a time, because we're being thorough and we don't skip π
DTYPE_A(global) β stored inDESCA( DTYPE_ )β the descriptor type. In this case,DTYPE_A = 1.CTXT_A(global) β stored inDESCA( CTXT_ )β the BLACS context handle, indicating the BLACS process gridAis distributed over. The context itself is global, but the handle (the integer value) may vary.M_A(global) β stored inDESCA( M_ )β the number of rows in the global arrayA.N_A(global) β stored inDESCA( N_ )β the number of columns in the global arrayA.MB_A(global) β stored inDESCA( MB_ )β the blocking factor used to distribute the rows of the array.NB_A(global) β stored inDESCA( NB_ )β the blocking factor used to distribute the columns of the array.RSRC_A(global) β stored inDESCA( RSRC_ )β the process row over which the first row of the arrayAis distributed.CSRC_A(global) β stored inDESCA( CSRC_ )β the process column over which the first column of the arrayAis distributed.LLD_A(local) β stored inDESCA( LLD_ )β the leading dimension of the local array.LLD_A >= MAX(1,LOCr(M_A)).
Now let K be the number of rows or columns of a distributed matrix, and assume that its process grid has dimension p x q. π
LOCr( K ) denotes the number of elements of K that a process would receive if K were distributed over the p processes of its process column.
Similarly, LOCc( K ) denotes the number of elements of K that a process would receive if K were distributed over the q processes of its process row. π¦
The values of LOCr() and LOCc() may be determined via a call to the ScaLAPACK tool function, NUMROC:
LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
An upper bound for these quantities may be computed by:
LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
π ARGUMENTS π
okay bestie, here's the tea on every single one of these parameters. no skimming, we're reading them all, and yes there are a lot. hydrate first. π
P = NPROW * NPCOL is the total number of processes. that's it, that's the whole vibe. π«Ά
N(global input) INTEGER β the order of the tridiagonal matrixT. and like,N >= 0, obviously. no negative orders, that's not a thing. β¨D(global input) DOUBLE PRECISION array, dimension (N) β thendiagonal elements of the tridiagonal matrixT. the main character diagonal fr. πE(global input) DOUBLE PRECISION array, dimension (N-1) β the(n-1)off-diagonal elements of the tridiagonal matrixT. notice it'sN-1bestie, the off-diagonal is always one shorter, iykyk. π¦M(global input) INTEGER β the total number of eigenvectors to be found. range is0 <= M <= N. not greedy, not skimping. πW(global input/global output) DOUBLE PRECISION array, dim (M) β okay so on input, the firstMelements ofWhold all the eigenvalues you want eigenvectors for. these need to be grouped by split-off block and ordered smallest to largest within the block β the output arrayWfromPDSTEBZwithORDER='b'is exactly what's expected here. this array should be replicated on all processes, no gatekeeping. on output, the firstMelements contain the input eigenvalues in ascending order. β¨
note: to get orthogonal vectors, it's best if the eigenvalues are computed to the highest accuracy β you can do this by settingABSTOLto the underflow threshold =DLAMCH('U'). and yes,ABSTOLis an input parameter toPDSTEBZ, go look it up bestie. π
IBLOCK(global input) INTEGER array, dimension (N) β the submatrix indices that go with the corresponding eigenvalues inW.1for eigenvalues in the first submatrix from the top,2for the second submatrix, etc. (the output arrayIBLOCKfromPDSTEBZis expected here). πISPLIT(global input) INTEGER array, dimension (N) β the splitting points, aka whereTbreaks up into submatrices. first submatrix = rows/columns1toISPLIT(1), second = rows/columnsISPLIT(1)+1throughISPLIT(2), etc., and theNSPLIT-th = rows/columnsISPLIT(NSPLIT-1)+1throughISPLIT(NSPLIT)=N. (the output arrayISPLITfromPDSTEBZis expected here, same deal as before.) πΈORFAC(global input) DOUBLE PRECISION βORFACdecides which eigenvectors get orthogonalized. eigenvectors whose eigenvalues are withinORFAC*||T||of each other get the orthogonalization treatment. however β and this is important β if the workspace isn't enough (peepLWORK), this tolerance may be decreased until all the eigenvectors that need orthogonalizing can fit in one process. ifORFACequals zero, no orthogonalization happens at all, periodt. and ifORFACis negative, a default value of10^-3gets used.ORFACshould be identical on all processes, no exceptions. π€Z(local output) COMPLEX*16 array, dimension (DESCZ(DLEN_), N/npcol + NB) βZcontains the computed eigenvectors for the specified eigenvalues. any vector that fails to converge gets set to its current iterate afterMAXITSiterations (seeDSTEIN2). on output,Zis distributed across thePprocesses in block cyclic format. iconic distribution behavior honestly. πIZ(global input) INTEGER βZ's global row index, pointing to the beginning of the submatrix that's about to be operated on. πJZ(global input) INTEGER βZ's global column index, pointing to the beginning of the submatrix that's about to be operated on. πDESCZ(global and local input) INTEGER array of dimension DLEN_ β the array descriptor for the distributed matrixZ. the little ID card forZ, basically. πͺͺWORK(local workspace/global output) DOUBLE PRECISION array, dimension (LWORK) β on output,WORK(1)gives a lower bound on the workspace (LWORK) that guarantees the user-desired orthogonalization (checkORFAC). heads up though: this may overestimate the minimum workspace actually needed. πLWORK(local input) integer βLWORKcontrols how much orthogonalization can actually get done. the number of eigenvectors that get storage allocated on each process isNVEC = floor(( LWORK- max(5*N,NP00*MQ00) )/N). eigenvectors corresponding to eigenvalue clusters of sizeNVEC - ceil(M/P) + 1are guaranteed to be orthogonal (the orthogonality is similar to what you'd get fromZSTEIN2). π§
note:LWORKmust be no smaller thanmax(5*N,NP00*MQ00) + ceil(M/P)*N, and should have the same input value on all processes. it's the minimum value ofLWORKinput across the different processes that's significant. so like, the smallest one wins. π
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. so no yelling, it's a vibe check only. β¨
IWORK(local workspace/global output) INTEGER array, dimension ( 3*N+P+1 ) β on return,IWORK(1)contains the amount of integer workspace required. on return,IWORK(2)throughIWORK(P+2)indicate the eigenvectors computed by each process. processIcomputes eigenvectors indexedIWORK(I+2)+1thru'IWORK(I+3). yes it says thru', we keep it, that's the vibe. πLIWORK(local input) INTEGER β size of arrayIWORK. must be>= 3*N + P + 1. non-negotiable bestie. π
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. same energy as above, just the integer twin. π«Ά
IFAIL(global output) integer array, dimension (M) β on a normal exit, all elements ofIFAILare zero. π if one or more eigenvectors fail to converge afterMAXITSiterations (same as inZSTEIN), thenINFO > 0gets returned. ifmod(INFO,M+1)>0, then forI=1tomod(INFO,M+1), the eigenvector corresponding to eigenvalueW(IFAIL(I))failed to converge (Where = the array of eigenvalues on output). πICLUSTR(global output) integer array, dimension (2*P) β this output array holds the indices of eigenvectors corresponding to a cluster of eigenvalues that couldn't be orthogonalized because the workspace wasn't enough (peepLWORK,ORFACandINFO). eigenvectors for clusters indexedICLUSTR(2*I-1)toICLUSTR(2*I),I = 1toINFO/(M+1), couldn't be orthogonalized due to lack of workspace. so those eigenvectors corresponding to those clusters may not be orthogonal, periodt.ICLUSTRis a zero-terminated array β( ICLUSTR(2*K).NE.0 .AND. ICLUSTR(2*K+1).EQ.0 )if and only ifKis the number of clusters. π§GAP(global output) DOUBLE PRECISION array, dimension (P) β this output array holds the gap between eigenvalues whose eigenvectors couldn't be orthogonalized. theINFO/Moutput values in this array correspond to theINFO/(M+1)clusters indicated byICLUSTR. as a result, the dot product between eigenvectors for theI^thcluster may be as high as( O(n)*macheps ) / GAP(I). lowkey a warning, highkey just facts. πΈINFO(global output) INTEGER β the receipts:= 0: successful exit. we ate. π< 0: if the i-th argument is an array and the j-entry had an illegal value, thenINFO = -(i*100+j); if the i-th argument is a scalar and had an illegal value, thenINFO = -i. also:< 0: ifINFO = -I, the I-th argument had an illegal value. π> 0: ifmod(INFO,M+1) = I, thenIeigenvectors failed to converge inMAXITSiterations, and their indices are stored in the arrayIFAIL. ifINFO/(M+1) = I, then eigenvectors corresponding toIclusters of eigenvalues could not be orthogonalized due to insufficient workspace, and the indices of the clusters are stored in the arrayICLUSTR. π
and that's the whole page bestie!! you made it, I'm so proud of you fr fr. π₯Ήπ
this one's from LAPACK version 1.5, dated 12 May 1997, and it's PZSTEIN(l) β go forth and orthogonalize (or don't, if ORFAC is zero, lmao). bye bestie, love u, slay π
β¨
π¦ where this page comes from
- ubuntu jammy: scalapack-doc 1.5-11
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms