⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cstedc.f

📁 计算矩阵的经典开源库.全世界都在用它.相信你也不能例外.
💻 F
字号:
      SUBROUTINE CSTEDC( COMPZ, N, D, E, Z, LDZ, WORK, LWORK, RWORK,     $                   LRWORK, IWORK, LIWORK, INFO )**  -- LAPACK routine (instrumented to count operations, version 3.0) --*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,*     Courant Institute, Argonne National Lab, and Rice University*     June 30, 1999**     .. Scalar Arguments ..      CHARACTER          COMPZ      INTEGER            INFO, LDZ, LIWORK, LRWORK, LWORK, N*     ..*     .. Array Arguments ..      INTEGER            IWORK( * )      REAL               D( * ), E( * ), RWORK( * )      COMPLEX            WORK( * ), Z( LDZ, * )*     ..*     Common block to return operation count and iteration count*     ITCNT is initialized to 0, OPS is only incremented*     .. Common blocks ..      COMMON             / LATIME / OPS, ITCNT*     ..*     .. Scalars in Common ..      REAL               ITCNT, OPS*     ..**  Purpose*  =======**  CSTEDC computes all eigenvalues and, optionally, eigenvectors of a*  symmetric tridiagonal matrix using the divide and conquer method.*  The eigenvectors of a full or band complex Hermitian matrix can also*  be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this*  matrix to tridiagonal form.**  This code makes very mild assumptions about floating point*  arithmetic. It will work on machines with a guard digit in*  add/subtract, or on those binary machines without guard digits*  which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2.*  It could conceivably fail on hexadecimal or decimal machines*  without guard digits, but we know of none.  See SLAED3 for details.**  Arguments*  =========**  COMPZ   (input) CHARACTER*1*          = 'N':  Compute eigenvalues only.*          = 'I':  Compute eigenvectors of tridiagonal matrix also.*          = 'V':  Compute eigenvectors of original Hermitian matrix*                  also.  On entry, Z contains the unitary matrix used*                  to reduce the original matrix to tridiagonal form.**  N       (input) INTEGER*          The dimension of the symmetric tridiagonal matrix.  N >= 0.**  D       (input/output) REAL array, dimension (N)*          On entry, the diagonal elements of the tridiagonal matrix.*          On exit, if INFO = 0, the eigenvalues in ascending order.**  E       (input/output) REAL array, dimension (N-1)*          On entry, the subdiagonal elements of the tridiagonal matrix.*          On exit, E has been destroyed.**  Z       (input/output) COMPLEX array, dimension (LDZ,N)*          On entry, if COMPZ = 'V', then Z contains the unitary*          matrix used in the reduction to tridiagonal form.*          On exit, if INFO = 0, then if COMPZ = 'V', Z contains the*          orthonormal eigenvectors of the original Hermitian matrix,*          and if COMPZ = 'I', Z contains the orthonormal eigenvectors*          of the symmetric tridiagonal matrix.*          If  COMPZ = 'N', then Z is not referenced.**  LDZ     (input) INTEGER*          The leading dimension of the array Z.  LDZ >= 1.*          If eigenvectors are desired, then LDZ >= max(1,N).**  WORK    (workspace/output) COMPLEX array, dimension (LWORK)*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.**  LWORK   (input) INTEGER*          The dimension of the array WORK.*          If COMPZ = 'N' or 'I', or N <= 1, LWORK must be at least 1.*          If COMPZ = 'V' and N > 1, LWORK must be at least N*N.**          If LWORK = -1, then a workspace query is assumed; the routine*          only calculates the optimal size of the WORK array, returns*          this value as the first entry of the WORK array, and no error*          message related to LWORK is issued by XERBLA.**  RWORK   (workspace/output) REAL array,*                                         dimension (LRWORK)*          On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK.**  LRWORK  (input) INTEGER*          The dimension of the array RWORK.*          If COMPZ = 'N' or N <= 1, LRWORK must be at least 1.*          If COMPZ = 'V' and N > 1, LRWORK must be at least*                         1 + 3*N + 2*N*lg N + 3*N**2 ,*                         where lg( N ) = smallest integer k such*                         that 2**k >= N.*          If COMPZ = 'I' and N > 1, LRWORK must be at least*                         1 + 4*N + 2*N**2 .**          If LRWORK = -1, then a workspace query is assumed; the*          routine only calculates the optimal size of the RWORK array,*          returns this value as the first entry of the RWORK array, and*          no error message related to LRWORK is issued by XERBLA.**  IWORK   (workspace/output) INTEGER array, dimension (LIWORK)*          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.**  LIWORK  (input) INTEGER*          The dimension of the array IWORK.*          If COMPZ = 'N' or N <= 1, LIWORK must be at least 1.*          If COMPZ = 'V' or N > 1,  LIWORK must be at least*                                    6 + 6*N + 5*N*lg N.*          If COMPZ = 'I' or N > 1,  LIWORK must be at least*                                    3 + 5*N .**          If LIWORK = -1, then a workspace query is assumed; the*          routine only calculates the optimal size of the IWORK array,*          returns this value as the first entry of the IWORK array, and*          no error message related to LIWORK is issued by XERBLA.**  INFO    (output) INTEGER*          = 0:  successful exit.*          < 0:  if INFO = -i, the i-th argument had an illegal value.*          > 0:  The algorithm failed to compute an eigenvalue while*                working on the submatrix lying in rows and columns*                INFO/(N+1) through mod(INFO,N+1).**  Further Details*  ===============**  Based on contributions by*     Jeff Rutter, Computer Science Division, University of California*     at Berkeley, USA**  =====================================================================**     .. Parameters ..      REAL               ZERO, ONE, TWO      PARAMETER          ( ZERO = 0.0E0, ONE = 1.0E0, TWO = 2.0E0 )*     ..*     .. Local Scalars ..      LOGICAL            LQUERY      INTEGER            END, I, ICOMPZ, II, J, K, LGN, LIWMIN, LL,     $                   LRWMIN, LWMIN, M, SMLSIZ, START      REAL               EPS, ORGNRM, P, TINY*     ..*     .. External Functions ..      LOGICAL            LSAME      INTEGER            ILAENV      REAL               SLAMCH, SLANST      EXTERNAL           ILAENV, LSAME, SLAMCH, SLANST*     ..*     .. External Subroutines ..      EXTERNAL           CLACPY, CLACRM, CLAED0, CSTEQR, CSWAP, SLASCL,     $                   SLASET, SSTEDC, SSTEQR, SSTERF, XERBLA*     ..*     .. Intrinsic Functions ..      INTRINSIC          ABS, INT, LOG, MAX, MOD, REAL, SQRT*     ..*     .. Executable Statements ..**     Test the input parameters.*      INFO = 0      LQUERY = ( LWORK.EQ.-1 .OR. LRWORK.EQ.-1 .OR. LIWORK.EQ.-1 )*      IF( LSAME( COMPZ, 'N' ) ) THEN         ICOMPZ = 0      ELSE IF( LSAME( COMPZ, 'V' ) ) THEN         ICOMPZ = 1      ELSE IF( LSAME( COMPZ, 'I' ) ) THEN         ICOMPZ = 2      ELSE         ICOMPZ = -1      END IF      IF( N.LE.1 .OR. ICOMPZ.LE.0 ) THEN         LWMIN = 1         LIWMIN = 1         LRWMIN = 1      ELSE         LGN = INT( LOG( REAL( N ) ) / LOG( TWO ) )         IF( 2**LGN.LT.N )     $      LGN = LGN + 1         IF( 2**LGN.LT.N )     $      LGN = LGN + 1         IF( ICOMPZ.EQ.1 ) THEN            LWMIN = N*N            LRWMIN = 1 + 3*N + 2*N*LGN + 3*N**2            LIWMIN = 6 + 6*N + 5*N*LGN         ELSE IF( ICOMPZ.EQ.2 ) THEN            LWMIN = 1            LRWMIN = 1 + 4*N + 2*N**2            LIWMIN = 3 + 5*N         END IF      END IF      IF( ICOMPZ.LT.0 ) THEN         INFO = -1      ELSE IF( N.LT.0 ) THEN         INFO = -2      ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1,     $         N ) ) ) THEN         INFO = -6      ELSE IF( LWORK.LT.LWMIN .AND. .NOT.LQUERY ) THEN         INFO = -8      ELSE IF( LRWORK.LT.LRWMIN .AND. .NOT.LQUERY ) THEN         INFO = -10      ELSE IF( LIWORK.LT.LIWMIN .AND. .NOT.LQUERY ) THEN         INFO = -12      END IF*      IF( INFO.EQ.0 ) THEN         WORK( 1 ) = LWMIN         RWORK( 1 ) = LRWMIN         IWORK( 1 ) = LIWMIN      END IF*      IF( INFO.NE.0 ) THEN         CALL XERBLA( 'CSTEDC', -INFO )         RETURN      ELSE IF( LQUERY ) THEN         RETURN       END IF**     Quick return if possible*      ITCNT = 0      IF( N.EQ.0 )     $   RETURN       IF( N.EQ.1 ) THEN         IF( ICOMPZ.NE.0 )     $      Z( 1, 1 ) = ONE         RETURN       END IF*      SMLSIZ = ILAENV( 9, 'CSTEDC', ' ', 0, 0, 0, 0 )**     If the following conditional clause is removed, then the routine*     will use the Divide and Conquer routine to compute only the*     eigenvalues, which requires (3N + 3N**2) real workspace and*     (2 + 5N + 2N lg(N)) integer workspace.*     Since on many architectures SSTERF is much faster than any other*     algorithm for finding eigenvalues only, it is used here*     as the default.**     If COMPZ = 'N', use SSTERF to compute the eigenvalues.*      IF( ICOMPZ.EQ.0 ) THEN         CALL SSTERF( N, D, E, INFO )         RETURN       END IF**     If N is smaller than the minimum divide size (SMLSIZ+1), then*     solve the problem with another solver.*      IF( N.LE.SMLSIZ ) THEN         IF( ICOMPZ.EQ.0 ) THEN            CALL SSTERF( N, D, E, INFO )            RETURN          ELSE IF( ICOMPZ.EQ.2 ) THEN            CALL CSTEQR( 'I', N, D, E, Z, LDZ, RWORK, INFO )            RETURN          ELSE            CALL CSTEQR( 'V', N, D, E, Z, LDZ, RWORK, INFO )            RETURN          END IF      END IF**     If COMPZ = 'I', we simply call SSTEDC instead.*      IF( ICOMPZ.EQ.2 ) THEN         CALL SLASET( 'Full', N, N, ZERO, ONE, RWORK, N )         LL = N*N + 1         CALL SSTEDC( 'I', N, D, E, RWORK, N, RWORK( LL ), LRWORK-LL+1,     $                IWORK, LIWORK, INFO )         DO 20 J = 1, N            DO 10 I = 1, N               Z( I, J ) = RWORK( ( J-1 )*N+I )   10       CONTINUE   20    CONTINUE         RETURN       END IF**     From now on, only option left to be handled is COMPZ = 'V',*     i.e. ICOMPZ = 1.**     Scale.*      ORGNRM = SLANST( 'M', N, D, E )      IF( ORGNRM.EQ.ZERO )     $   RETURN*      EPS = SLAMCH( 'Epsilon' )*      START = 1**     while ( START <= N )*   30 CONTINUE      IF( START.LE.N ) THEN**     Let END be the position of the next subdiagonal entry such that*     E( END ) <= TINY or END = N if no such subdiagonal exists.  The*     matrix identified by the elements between START and END*     constitutes an independent sub-problem.*         END = START   40    CONTINUE         IF( END.LT.N ) THEN            OPS = OPS + 4            TINY = EPS*SQRT( ABS( D( END ) ) )*SQRT( ABS( D( END+1 ) ) )            IF( ABS( E( END ) ).GT.TINY ) THEN               END = END + 1               GO TO 40            END IF         END IF**        (Sub) Problem determined.  Compute its size and solve it.*         M = END - START + 1         IF( M.GT.SMLSIZ ) THEN            INFO = SMLSIZ**           Scale.*            ORGNRM = SLANST( 'M', M, D( START ), E( START ) )            OPS = OPS + 2*M - 1            CALL SLASCL( 'G', 0, 0, ORGNRM, ONE, M, 1, D( START ), M,     $                   INFO )            CALL SLASCL( 'G', 0, 0, ORGNRM, ONE, M-1, 1, E( START ),     $                   M-1, INFO )*            CALL CLAED0( N, M, D( START ), E( START ), Z( 1, START ),     $                   LDZ, WORK, N, RWORK, IWORK, INFO )            IF( INFO.GT.0 ) THEN               INFO = ( INFO / ( M+1 )+START-1 )*( N+1 ) +     $                MOD( INFO, ( M+1 ) ) + START - 1               RETURN             END IF**           Scale back.*            OPS = OPS + M            CALL SLASCL( 'G', 0, 0, ONE, ORGNRM, M, 1, D( START ), M,     $                   INFO )*         ELSE            CALL SSTEQR( 'I', M, D( START ), E( START ), RWORK, M,     $                   RWORK( M*M+1 ), INFO )            OPS = OPS + 4*REAL( N )*M*M            CALL CLACRM( N, M, Z( 1, START ), LDZ, RWORK, M, WORK, N,     $                   RWORK( M*M+1 ) )            CALL CLACPY( 'A', N, M, WORK, N, Z( 1, START ), LDZ )            IF( INFO.GT.0 ) THEN               INFO = START*( N+1 ) + END               RETURN             END IF         END IF*         START = END + 1         GO TO 30      END IF**     endwhile**     If the problem split any number of times, then the eigenvalues*     will not be properly ordered.  Here we permute the eigenvalues*     (and the associated eigenvectors) into ascending order.*      IF( M.NE.N ) THEN**        Use Selection Sort to minimize swaps of eigenvectors*         DO 60 II = 2, N            I = II - 1            K = I            P = D( I )            DO 50 J = II, N               IF( D( J ).LT.P ) THEN                  K = J                  P = D( J )               END IF   50       CONTINUE            IF( K.NE.I ) THEN               D( K ) = D( I )               D( I ) = P               CALL CSWAP( N, Z( 1, I ), 1, Z( 1, K ), 1 )            END IF   60    CONTINUE      END IF*      WORK( 1 ) = LWMIN      RWORK( 1 ) = LRWMIN      IWORK( 1 ) = LIWMIN*      RETURN**     End of CSTEDC*      END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -