PDSTEIN(l)
π PDSTEIN(l) β LAPACK routine, version 1.5 π
okay bestie, sit DOWN, because this one is a whole journey β¨ It's the PDSTEIN page from the LAPACK routine docs, and it's lowkey iconic. Manual name? PDSTEIN, section l. That's the one. Periodt.
πΈ NAME πΈ
PDSTEIN β compute the eigenvectors of a symmetric tridiagonal matrix in parallel, using inverse iteration π
β¨ SYNOPSIS β¨
SUBROUTINE PDSTEIN( 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( *
), Z( * )
yes the line wrapping in the original is exactly that chaotic, and we are keeping it, no cap π«Ά
π¦ PURPOSE π¦
PDSTEIN computes the eigenvectors of a symmetric tridiagonal matrix in parallel, using inverse iteration. The eigenvectors it finds correspond to user specified eigenvalues. β¨
Okay but here's the tea, bestie, and you need to hear it: PDSTEIN 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. PDSTEIN decides on the allocation of work among the processes and then calls DSTEIN2 (a modified LAPACK routine) on each individual process. 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. (fr fr, this is the move.)
π 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. π«
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". π§
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 grid A is 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)).
so many letters, I know, but stay with me, it's giving very much "organized" π
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
math but make it cute π β¨π
and that's the first half, bestie β do NOT close the tab, there's more coming π
π ARGUMENTS π
ok so first things first bestie, the lil legend: P = NPROW * NPCOL is the total number of processes. That's the squad size, remember it, it comes up everywhere. π
N(global input) INTEGER β the order of the tridiagonal matrixT. AndN >= 0, no negatives, she doesn't play like that. β¨D(global input) DOUBLE PRECISION array, dimension (N) β thendiagonal elements of the tridiagonal matrixT. The main character elements, honestly. πE(global input) DOUBLE PRECISION array, dimension (N-1) β the(n-1)off-diagonal elements of the tridiagonal matrixT. The supporting cast, still essential. π«ΆM(global input) INTEGER β the total number of eigenvectors we're trying to find.0 <= M <= N, no cap (well, actually cap atN, but you get me). πW(global input/global output) DOUBLE PRECISION array, dim (M) β okay so on input, the firstMelements ofWhold all the eigenvalues you want eigenvectors for. They need to be grouped by split-off block and ordered smallest to largest within each block. (What's expected here is the output arrayWfromPDSTEBZwithORDER='b', so like, go get that first.) This array should be replicated on all processes, fr fr. On output, the firstMelements contain the input eigenvalues in ascending order. Sorted, organized, slay. β¨
Note: to get orthogonal vectors, it's best if eigenvalues are computed to the highest accuracy possible β you do that by settingABSTOLto the underflow threshold =DLAMCH('U'). (ABSTOLis an input parameter toPDSTEBZ, iykyk.) πΈ
IBLOCK(global input) INTEGER array, dimension (N) β the submatrix indices that go with the corresponding eigenvalues inW. So1= eigenvalue belongs to the first submatrix from the top,2= second submatrix, etc. (Again, the output arrayIBLOCKfromPDSTEBZis what's expected here.) π¦ISPLIT(global input) INTEGER array, dimension (N) β the splitting points, aka whereTbreaks up into submatrices. So: the first submatrix is rows/columns1toISPLIT(1), the second is rows/columnsISPLIT(1)+1throughISPLIT(2), etc., and theNSPLIT-th is rows/columnsISPLIT(NSPLIT-1)+1throughISPLIT(NSPLIT)=N. (And yes, you guessed it, the output arrayISPLITfromPDSTEBZis expected here.) π₯ORFAC(global input) DOUBLE PRECISION βORFACdecides which eigenvectors get orthogonalized. Eigenvectors whose eigenvalues are withinORFAC*||T||of each other get the orthogonalization treatment. BUT β and this is important β if the workspace isn't enough (seeLWORK), this tolerance may get decreased until all the eigenvectors that need orthogonalizing can actually fit in one process. IfORFACequals zero, no orthogonalization happens at all, periodt. And ifORFACis negative, a default value of10^-3is used.ORFACshould be identical on all processes, no chaos. πZ(local output) DOUBLE PRECISION array, dimension (DESCZ(DLEN_), N/npcol + NB) βZcontains the computed eigenvectors that go with the specified eigenvalues. Any vector that fails to converge is set to its current iterate afterMAXITSiterations (seeDSTEIN2). On output,Zis distributed across thePprocesses in block cyclic format. πIZ(global input) INTEGER βZ's global row index, which points to the beginning of the submatrix that's about to be operated on. πJZ(global input) INTEGER βZ's global column index, which points 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. Her ID card, 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 orthogonalization you asked for (seeORFAC). Just so you know: this may overestimate the minimum workspace actually needed. π€·βοΈLWORK(local input) integer βLWORKcontrols how much orthogonalization can be done. The number of eigenvectors with storage allocated on each process is:
NVEC = floor(( LWORK- max(5*N,NP00*MQ00) )/N)
Eigenvectors corresponding to eigenvalue clusters of size NVEC - ceil(M/P) + 1 are guaranteed to be orthogonal (this orthogonality is similar to what you get from DSTEIN2). π
Note:LWORKmust be no smaller thanmax(5*N,NP00*MQ00) + ceil(M/P)*N, and it should have the same input value on all processes. It's the minimum value ofLWORKinput on different processes that's significant, so if one process cheaps out, that's the vibe for everyone.
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 it's a lil "just tell me the sizes" moment, no drama. β¨
IWORK(local workspace/global output) INTEGER array, dimension ( 3N+P+1 )* β on return,IWORK(1)contains the amount of integer workspace required. Also on return,IWORK(2)throughIWORK(P+2)indicate the eigenvectors computed by each process. ProcessIcomputes eigenvectors indexedIWORK(I+2)+1 thru' IWORK(I+3). Receipts, basically. π§ΎLIWORK(local input) INTEGER β size of arrayIWORK. Must be>= 3*N + P + 1.
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 the LWORK one. π
IFAIL(global output) integer array, dimension (M) β on a normal exit, every element ofIFAILis zero. If one or more eigenvectors fail to converge afterMAXITSiterations (just like inDSTEIN), thenINFO > 0gets returned. And ifmod(INFO,M+1)>0, then forI=1tomod(INFO,M+1), the eigenvector corresponding to eigenvalueW(IFAIL(I))failed to converge (Where means the array of eigenvalues on output). πICLUSTR(global output) integer array, dimension (2P)* β this output array holds indices of eigenvectors corresponding to a cluster of eigenvalues that could not be orthogonalized because the workspace wasn't enough (seeLWORK,ORFACandINFO). Eigenvectors corresponding to clusters of eigenvalues indexedICLUSTR(2*I-1)toICLUSTR(2*I),I = 1toINFO/(M+1), couldn't be orthogonalized due to lack of workspace. So yeah, the eigenvectors for those clusters may not be orthogonal, that's the tea.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 by the arrayICLUSTR. As a result, the dot product between eigenvectors corresponding to theI^thcluster may be as high as( O(n)*macheps ) / GAP(I). πINFO(global output) INTEGER β= 0: successful exit. we love to see it. π< 0: if thei-th argument is an array and thej-entry had an illegal value, thenINFO = -(i*100+j); if thei-th argument is a scalar and had an illegal value, thenINFO = -i. Also:< 0β ifINFO = -I, theI-th argument had an illegal value. π> 0: ifmod(INFO,M+1) = I, thenIeigenvectors failed to converge inMAXITSiterations. Their indices are stored in the arrayIFAIL. And ifINFO/(M+1) = I, then eigenvectors corresponding toIclusters of eigenvalues could not be orthogonalized due to insufficient workspace. The indices of those clusters are stored in the arrayICLUSTR. π
ok that's the whole page bestie, you're officially a PDSTEIN girlie now π this was LAPACK version 1.5, dated 12 May 1997, and the page is PDSTEIN(l). go forth and orthogonalize responsibly, ily, bye!! πβ¨π¦
π¦ 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