! ! -- LAPACK95 interface driver routine (version 3.0) -- ! UNI-C, Denmark; Univ. of Tennessee, USA; NAG Ltd., UK ! September, 2000 ! !---------------------------------------------------------------------- ! ! Purpose ! ======= ! ! LA_STEVX computes selected eigenvalues and, optionally, the ! corresponding eigenvectors of a real symmetric tridiagonal matrix A. ! Eigenvalues and eigenvectors can be selected by specifying either a ! range of values or a range of indices for the desired eigenvalues. ! ! ========= ! ! SUBROUTINE LA_STEVX( D, E, W, Z=z, VL=vl, VU=vu, & ! IL=il, IU=iu, M=m, IFAIL=ifail, & ! ABSTOL=abstol, INFO=info ) ! REAL(), INTENT(INOUT) :: D(:), E(:) ! REAL(), INTENT(OUT) :: W(:) ! REAL(), INTENT(OUT), OPTIONAL :: Z(:,:) ! REAL(), INTENT(IN), OPTIONAL :: VL, VU ! INTEGER, INTENT(IN), OPTIONAL :: IL, IU ! INTEGER, INTENT(OUT), OPTIONAL :: M ! INTEGER, INTENT(OUT), OPTIONAL :: IFAIL(:) ! REAL(), INTENT(IN), OPTIONAL :: ABSTOL ! INTEGER, INTENT(OUT), OPTIONAL :: INFO ! where ! ::= KIND(1.0) | KIND(1.0D0) ! ! Arguments ! ========= ! ! D (input/output) REAL array, shape (:) with size(D) = n, where n ! is the order of A. ! On entry, the diagonal elements of the matrix A. ! On exit, the original contents of D possibly multiplied by a ! constant factor to avoid over/underflow in computing the ! eigenvalues. ! E (input/output) REAL array, shape (:) with size(E) = n. ! On entry, the n-1 subdiagonal elements of A in E(1) to E(n-1). ! E(n) need not be set. ! On exit, the original contents of E possibly multiplied by a ! constant factor to avoid over/underflow in computing the ! eigenvalues. ! W (output) REAL array with size(W) = n. ! The first M elements contain the selected eigenvalues in ! ascending order. ! Z Optional (output) REAL or COMPLEX array, shape (:,:) with ! size(Z,1) = n and size(Z,2) = M. ! The first M columns of Z contain the orthonormal eigenvectors ! of A corresponding to the selected eigenvalues, with the i-th ! column of Z containing the eigenvector associated with the ! eigenvalue in W(i) . If an eigenvector fails to converge, then ! that column of Z contains the latest approximation to the ! eigenvector, and the index of the eigenvector is returned in ! IFAIL. ! Note: The user must ensure that at least M columns are ! supplied in the array Z. When the exact value of M is not ! known in advance, an upper bound must be used. In all cases ! M <= n. ! VL,VU Optional (input) REAL. ! The lower and upper bounds of the interval to be searched for ! eigenvalues. VL < VU. ! Default values: VL = -HUGE() and VU = HUGE(), where ! ::= KIND(1.0) | KIND(1.0D0). ! Note: Neither VL nor VU may be present if IL and/or IU is ! present. ! IL,IU Optional (input) INTEGER. ! The indices of the smallest and largest eigenvalues to be ! returned. The IL-th through IU-th eigenvalues will be found. ! 1 <= IL <= IU <= n. ! Default values: IL = 1 and IU = n. ! Note: Neither IL nor IU may be present if VL and/or VU is ! present. ! Note: All eigenvalues are calculated if none of the arguments ! VL, VU, IL and IU are present. ! M Optional (output) INTEGER. ! The total number of eigenvalues found. 0 <= M <= n. ! Note: If IL and IU are present then M = IU - IL + 1. ! IFAIL Optional (output) INTEGER array, shape (:) with ! size(IFAIL) = n. ! If INFO = 0, the first M elements of IFAIL are zero. ! If INFO > 0, then IFAIL contains the indices of the ! eigenvectors that failed to converge. ! Note: If Z is present then IFAIL should also be present. ! ABSTOL Optional (input) REAL. ! The absolute error tolerance for the eigenvalues. An ! approximate eigenvalue is accepted as converged when it is ! determined to lie in an interval [a,b] of width less than or ! equal to ABSTOL + EPSILON(1.0_) * max(|a|,|b|), ! where is the working precision. If ABSTOL <= 0, then ! EPSILON(1.0_) * ||A||1 will be used in its place. ! Eigenvalues will be computed most accurately when ABSTOL is ! set to twice the underflow threshold ! 2 * LA_LAMCH(1.0_, 'Safe minimum'), not zero. ! Default value: 0.0_. ! Note: If this routine returns with INFO > 0, then some ! eigenvectors did not converge. Try setting ABSTOL to ! 2 * LA_LAMCH(1.0_, 'Safe minimum'). ! INFO Optional (output) INTEGER ! = 0: successful exit. ! < 0: if INFO = -i, the i-th argument had an illegal value. ! > 0: if INFO = i, then i eigenvectors failed to converge. ! Their indices are stored in array IFAIL. ! If INFO is not present and an error occurs, then the program ! is terminated with an error message. !---------------------------------------------------------------------- SUBROUTINE SSTEVX_F95( D, E, W, Z, VL, VU, IL, IU, M, & IFAIL, ABSTOL, INFO ) ! .. USE STATEMENTS .. USE LA_PRECISION, ONLY: WP => SP USE LA_AUXMOD, ONLY: ERINFO USE F77_LAPACK, ONLY: STEVX_F77 => LA_STEVX, LAMCH_F77 => SLAMCH ! .. IMPLICIT STATEMENT .. IMPLICIT NONE ! .. SCALAR ARGUMENTS .. INTEGER, INTENT(IN), OPTIONAL :: IL, IU INTEGER, INTENT(OUT), OPTIONAL :: INFO, M REAL(WP), INTENT(IN), OPTIONAL :: ABSTOL, VL, VU ! .. ARRAY ARGUMENTS .. INTEGER, INTENT(OUT), OPTIONAL, TARGET :: IFAIL(:) REAL(WP), INTENT(OUT), OPTIONAL, TARGET :: Z(:,:) REAL(WP), INTENT(INOUT) :: D(:), E(:) REAL(WP), INTENT(OUT) :: W(:) ! .. LOCAL PARAMETERS .. CHARACTER(LEN=8), PARAMETER :: SRNAME = 'LA_STEVX' ! .. LOCAL SCALARS .. CHARACTER(LEN=1) :: LJOBZ, LRANGE INTEGER :: N, LD, LIL, LIU, LM, SIFAIL, S1Z, S2Z INTEGER :: LINFO, ISTAT INTEGER, TARGET :: ISTAT1(1) REAL(WP), TARGET :: LLZ(1,1) REAL(WP) :: LABSTOL, LVL, LVU ! .. LOCAL ARRAYS .. INTEGER, POINTER :: IWORK(:), LIFAIL(:) REAL(WP), POINTER :: WORK(:) ! .. INTRINSIC FUNCTIONS .. INTRINSIC HUGE, PRESENT, SIZE ! .. EXECUTABLE STATEMENTS .. LINFO = 0; ISTAT = 0; N = SIZE(D); LD = MAX(1,N) IF( PRESENT(M)) M = 0 IF( PRESENT(IFAIL) )THEN; SIFAIL = SIZE(IFAIL); ELSE; SIFAIL = N; END IF IF( PRESENT(VL) )THEN; LVL = VL; ELSE; LVL = -HUGE(LVL); ENDIF IF( PRESENT(VU) )THEN; LVU = VU; ELSE; LVU = HUGE(LVU); ENDIF IF( PRESENT(IL) )THEN; LIL = IL; ELSE; LIL = 1; ENDIF IF( PRESENT(IU) )THEN; LIU = IU; ELSE; LIU = N; ENDIF IF( PRESENT(Z) )THEN; S1Z = SIZE(Z,1); S2Z = SIZE(Z,2) ELSE; S1Z = 1; S2Z = 1; ENDIF ! .. TEST THE ARGUMENTS IF( N < 0 ) THEN; LINFO = -1 ELSE IF( SIZE( E ) /= N .AND. N > 0 )THEN; LINFO = -2 ELSE IF( SIZE( W ) /= N )THEN; LINFO = -3 ELSE IF( PRESENT(Z) .AND. ( S1Z /= LD .OR. S2Z /= N ) )THEN; LINFO = -4 ELSE IF( LVU < LVL )THEN; LINFO = -5 ELSE IF( (PRESENT(VL) .OR. PRESENT(VU)) .AND. & & (PRESENT(IL) .OR. PRESENT(IU)) )THEN; LINFO = -6 ELSE IF(( LIU < LIL .OR. LIL < 1) .AND. N>0 )THEN; LINFO = -7 ELSE IF( N < LIU )THEN; LINFO = -8 ELSE IF( SIFAIL /= N .OR. PRESENT(IFAIL).AND..NOT.PRESENT(Z) )THEN; LINFO = -10 ELSE IF( N > 0 )THEN IF( PRESENT(VL) .OR. PRESENT(VU) )THEN; LRANGE = 'V'; LM = N ELSE IF( PRESENT(IL) .OR. PRESENT(IU) )THEN; LRANGE = 'I'; LM = LIU-LIL+1 ELSE; LRANGE = 'A'; LM = N; END IF IF( PRESENT(Z) ) THEN; LJOBZ = 'V' IF( PRESENT(IFAIL) )THEN; LIFAIL => IFAIL ELSE; ALLOCATE( LIFAIL(N), STAT=ISTAT ); END IF ELSE; LJOBZ = 'N' LIFAIL => ISTAT1; ENDIF ! .. DETERMINE THE WORKSPACE IF( ISTAT == 0 ) THEN ALLOCATE(IWORK(5*N), WORK(5*N), STAT=ISTAT) IF( ISTAT == 0 )THEN IF( PRESENT(ABSTOL) )THEN; LABSTOL = ABSTOL ELSE; LABSTOL = 2*LAMCH_F77('Safe minimum'); ENDIF IF (PRESENT(Z)) THEN CALL STEVX_F77( LJOBZ, LRANGE, N, D, E, LVL, LVU, LIL, LIU, & LABSTOL, LM, W, Z, S1Z, WORK, IWORK, LIFAIL, LINFO ) ELSE CALL STEVX_F77( LJOBZ, LRANGE, N, D, E, LVL, LVU, LIL, LIU, & LABSTOL, LM, W, LLZ, S1Z, WORK, IWORK, LIFAIL, LINFO ) ENDIF IF( PRESENT(M) ) M = LM W(LM+1:N) = 0.0_WP ELSE; LINFO = -100; END IF END IF IF( PRESENT(Z) .AND. .NOT.PRESENT(IFAIL) ) DEALLOCATE( LIFAIL, STAT=ISTAT1(1) ) DEALLOCATE(IWORK, WORK, STAT=ISTAT1(1)) END IF CALL ERINFO(LINFO,SRNAME,INFO,ISTAT) END SUBROUTINE SSTEVX_F95