📄 trieige.f
字号:
SUBROUTINE TRIEIGE( RANGE, ORDER, N, VL, VU, IL, IU, ABSTOL, D, E,
$ M, NSPLIT, W, IBLOCK, ISPLIT, WORK, IWORK,
$ INFO )
*
*
* .. Scalar Arguments ..
CHARACTER ORDER, RANGE
INTEGER IL, INFO, IU, M, N, NSPLIT
REAL ABSTOL, VL, VU
* ..
* .. Array Arguments ..
INTEGER IBLOCK( * ), ISPLIT( * ), IWORK( * )
REAL D( * ), E( * ), W( * ), WORK( * )
* ..
*
* Purpose
* =======
*
* computes the eigenvalues of a symmetric tridiagonal
* matrix T. The user may ask for all eigenvalues, all eigenvalues
* in the half-open interval (VL, VU], or the IL-th through IU-th
* eigenvalues.
*
* To avoid overflow, the matrix must be scaled so that its
* largest element is no greater than overflow**(1/2) *
* underflow**(1/4) in absolute value, and for greatest
* accuracy, it should not be much smaller than that.
*
*
* Arguments
* =========
*
* RANGE (input) CHARACTER
* = 'A': ("All") all eigenvalues will be found.
* = 'V': ("Value") all eigenvalues in the half-open interval
* (VL, VU] will be found.
* = 'I': ("Index") the IL-th through IU-th eigenvalues (of the
* entire matrix) will be found.
*
* ORDER (input) CHARACTER
* = 'B': ("By Block") the eigenvalues will be grouped by
* split-off block (see IBLOCK, ISPLIT) and
* ordered from smallest to largest within
* the block.
* = 'E': ("Entire matrix")
* the eigenvalues for the entire matrix
* will be ordered from smallest to
* largest.
*
* N (input) INTEGER
* The order of the tridiagonal matrix T. N >= 0.
*
* VL (input) REAL
* VU (input) REAL
* If RANGE='V', the lower and upper bounds of the interval to
* be searched for eigenvalues. Eigenvalues less than or equal
* to VL, or greater than VU, will not be returned. VL < VU.
* Not referenced if RANGE = 'A' or 'I'.
*
* IL (input) INTEGER
* IU (input) INTEGER
* If RANGE='I', the indices (in ascending order) of the
* smallest and largest eigenvalues to be returned.
* 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.
* Not referenced if RANGE = 'A' or 'V'.
*
* ABSTOL (input) REAL
* The absolute tolerance for the eigenvalues. An eigenvalue
* (or cluster) is considered to be located if it has been
* determined to lie in an interval whose width is ABSTOL or
* less. If ABSTOL is less than or equal to zero, then ULP*|T|
* will be used, where |T| means the 1-norm of T.
*
* Eigenvalues will be computed most accurately when ABSTOL is
* set to twice the underflow threshold 2*SLAMCH('S'), not zero.
*
* D (input) REAL array, dimension (N)
* The n diagonal elements of the tridiagonal matrix T.
*
* E (input) REAL array, dimension (N-1)
* The (n-1) off-diagonal elements of the tridiagonal matrix T.
*
* M (output) INTEGER
* The actual number of eigenvalues found. 0 <= M <= N.
* (See also the description of INFO=2,3.)
*
* NSPLIT (output) INTEGER
* The number of diagonal blocks in the matrix T.
* 1 <= NSPLIT <= N.
*
* W (output) REAL array, dimension (N)
* On exit, the first M elements of W will contain the
* eigenvalues. (SSTEBZ may use the remaining N-M elements as
* workspace.)
*
* IBLOCK (output) INTEGER array, dimension (N)
* At each row/column j where E(j) is zero or small, the
* matrix T is considered to split into a block diagonal
* matrix. On exit, if INFO = 0, IBLOCK(i) specifies to which
* block (from 1 to the number of blocks) the eigenvalue W(i)
* belongs. (SSTEBZ may use the remaining N-M elements as
* workspace.)
*
* ISPLIT (output) INTEGER array, dimension (N)
* The splitting points, at which T breaks up into submatrices.
* The first submatrix consists of rows/columns 1 to ISPLIT(1),
* the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),
* etc., and the NSPLIT-th consists of rows/columns
* ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.
* (Only the first NSPLIT elements will actually be used, but
* since the user cannot know a priori what value NSPLIT will
* have, N words must be reserved for ISPLIT.)
*
* WORK (workspace) REAL array, dimension (4*N)
*
* IWORK (workspace) INTEGER array, dimension (3*N)
*
* INFO (output) INTEGER
* = 0: successful exit
* < 0: if INFO = -i, the i-th argument had an illegal value
* > 0: some or all of the eigenvalues failed to converge or
* were not computed:
* =1 or 3: Bisection failed to converge for some
* eigenvalues; these eigenvalues are flagged by a
* negative block number. The effect is that the
* eigenvalues may not be as accurate as the
* absolute and relative tolerances. This is
* generally caused by unexpectedly inaccurate
* arithmetic.
* =2 or 3: RANGE='I' only: Not all of the eigenvalues
* IL:IU were found.
* Effect: M < IU+1-IL
* Cause: non-monotonic arithmetic, causing the
* Sturm sequence to be non-monotonic.
* Cure: recalculate, using RANGE='A', and pick
* out eigenvalues IL:IU. In some cases,
* increasing the PARAMETER "FUDGE" may
* make things work.
* = 4: RANGE='I', and the Gershgorin interval
* initially used was too small. No eigenvalues
* were computed.
* Probable cause: your machine has sloppy
* floating-point arithmetic.
* Cure: Increase the PARAMETER "FUDGE",
* recompile, and try again.
*
* Internal Parameters
* ===================
*
* RELFAC REAL, default = 2.0e0
* The relative tolerance. An interval (a,b] lies within
* "relative tolerance" if b-a < RELFAC*ulp*max(|a|,|b|),
* where "ulp" is the machine precision (distance from 1 to
* the next larger floating point number.)
*
* FUDGE REAL, default = 2
* A "fudge factor" to widen the Gershgorin intervals. Ideally,
* a value of 1 should work, but on machines with sloppy
* arithmetic, this needs to be larger. The default for
* publicly released versions should be large enough to handle
* the worst machine around. Note that this has no effect
* on accuracy of the solution.
*
* =====================================================================
*
* .. Parameters ..
REAL ZERO, ONE, TWO, HALF
PARAMETER ( ZERO = 0.0E0, ONE = 1.0E0, TWO = 2.0E0,
$ HALF = 1.0E0 / TWO )
REAL FUDGE, RELFAC
PARAMETER ( FUDGE = 2.0E0, RELFAC = 2.0E0 )
* ..
* .. Local Scalars ..
LOGICAL NCNVRG, TOOFEW
INTEGER IB, IBEGIN, IDISCL, IDISCU, IE, IEND, IINFO,
$ IM, IN, IOFF, IORDER, IOUT, IRANGE, ITMAX,
$ ITMP1, IW, IWOFF, J, JB, JDISC, JE, NB, NWL,
$ NWU
REAL ATOLI, BNORM, GL, GU, PIVMIN, RTOLI, SAFEMN,
$ TMP1, TMP2, TNORM, ULP, WKILL, WL, WLU, WU, WUL
* ..
* .. Local Arrays ..
INTEGER IDUMMA( 1 )
* ..
* .. External Functions ..
LOGICAL LSAME
INTEGER ILAENV
REAL SLAMCH
EXTERNAL LSAME, ILAENV, SLAMCH
* ..
* .. External Subroutines ..
EXTERNAL SLAEBZ, XERBLA
* ..
* .. Intrinsic Functions ..
INTRINSIC ABS, INT, LOG, MAX, MIN, SQRT
* ..
* .. Executable Statements ..
*
INFO = 0
*
* Decode RANGE
*
IF( LSAME( RANGE, 'A' ) ) THEN
IRANGE = 1
ELSE IF( LSAME( RANGE, 'V' ) ) THEN
IRANGE = 2
ELSE IF( LSAME( RANGE, 'I' ) ) THEN
IRANGE = 3
ELSE
IRANGE = 0
END IF
*
* Decode ORDER
*
IF( LSAME( ORDER, 'B' ) ) THEN
IORDER = 2
ELSE IF( LSAME( ORDER, 'E' ) ) THEN
IORDER = 1
ELSE
IORDER = 0
END IF
*
* Check for Errors
*
IF( IRANGE.LE.0 ) THEN
INFO = -1
ELSE IF( IORDER.LE.0 ) THEN
INFO = -2
ELSE IF( N.LT.0 ) THEN
INFO = -3
ELSE IF( IRANGE.EQ.2 ) THEN
IF( VL.GE.VU ) INFO = -5
ELSE IF( IRANGE.EQ.3 .AND. ( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) )
$ THEN
INFO = -6
ELSE IF( IRANGE.EQ.3 .AND. ( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) )
$ THEN
INFO = -7
END IF
*
IF( INFO.NE.0 ) THEN
CALL XERBLA( 'SSTEBZ', -INFO )
RETURN
END IF
*
* Initialize error flags
*
INFO = 0
NCNVRG = .FALSE.
TOOFEW = .FALSE.
*
* Quick return if possible
*
M = 0
IF( N.EQ.0 )
$ RETURN
*
* Simplifications:
*
IF( IRANGE.EQ.3 .AND. IL.EQ.1 .AND. IU.EQ.N )
$ IRANGE = 1
*
* Get machine constants
* NB is the minimum vector length for vector bisection, or 0
* if only scalar is to be done.
*
SAFEMN = SLAMCH( 'S' )
ULP = SLAMCH( 'P' )
RTOLI = ULP*RELFAC
NB = ILAENV( 1, 'SSTEBZ', ' ', N, -1, -1, -1 )
IF( NB.LE.1 )
$ NB = 0
*
* Special Case when N=1
*
IF( N.EQ.1 ) THEN
NSPLIT = 1
ISPLIT( 1 ) = 1
IF( IRANGE.EQ.2 .AND. ( VL.GE.D( 1 ) .OR. VU.LT.D( 1 ) ) ) THEN
M = 0
ELSE
W( 1 ) = D( 1 )
IBLOCK( 1 ) = 1
M = 1
END IF
RETURN
END IF
*
* Compute Splitting Points
*
NSPLIT = 1
WORK( N ) = ZERO
PIVMIN = ONE
*
CDIR$ NOVECTOR
DO 10 J = 2, N
TMP1 = E( J-1 )**2
IF( ABS( D( J )*D( J-1 ) )*ULP**2+SAFEMN.GT.TMP1 ) THEN
ISPLIT( NSPLIT ) = J - 1
NSPLIT = NSPLIT + 1
WORK( J-1 ) = ZERO
ELSE
WORK( J-1 ) = TMP1
PIVMIN = MAX( PIVMIN, TMP1 )
END IF
10 CONTINUE
ISPLIT( NSPLIT ) = N
PIVMIN = PIVMIN*SAFEMN
*
* Compute Interval and ATOLI
*
IF( IRANGE.EQ.3 ) THEN
*
* RANGE='I': Compute the interval containing eigenvalues
* IL through IU.
*
* Compute Gershgorin interval for entire (split) matrix
* and use it as the initial interval
*
GU = D( 1 )
GL = D( 1 )
TMP1 = ZERO
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -