SUBROUTINE DSYEV( JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, INFO ) ! ! -- LAPACK driver routine (version 3.1) -- ! Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. ! November 2006 ! ! .. Scalar Arguments .. CHARACTER JOBZ, UPLO INTEGER INFO, LDA, LWORK, N ! .. ! .. Array Arguments .. DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ) ! .. ! ! Purpose ! ======= ! ! DSYEV computes all eigenvalues and, optionally, eigenvectors of a ! real symmetric matrix A. ! ! Arguments ! ========= ! ! JOBZ (input) CHARACTER*1 ! = 'N': Compute eigenvalues only; ! = 'V': Compute eigenvalues and eigenvectors. ! ! UPLO (input) CHARACTER*1 ! = 'U': Upper triangle of A is stored; ! = 'L': Lower triangle of A is stored. ! ! N (input) INTEGER ! The order of the matrix A. N >= 0. ! ! A (input/output) DOUBLE PRECISION array, dimension (LDA, N) ! On entry, the symmetric matrix A. If UPLO = 'U', the ! leading N-by-N upper triangular part of A contains the ! upper triangular part of the matrix A. If UPLO = 'L', ! the leading N-by-N lower triangular part of A contains ! the lower triangular part of the matrix A. ! On exit, if JOBZ = 'V', then if INFO = 0, A contains the ! orthonormal eigenvectors of the matrix A. ! If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') ! or the upper triangle (if UPLO='U') of A, including the ! diagonal, is destroyed. ! ! LDA (input) INTEGER ! The leading dimension of the array A. LDA >= max(1,N). ! ! W (output) DOUBLE PRECISION array, dimension (N) ! If INFO = 0, the eigenvalues in ascending order. ! ! WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) ! On exit, if INFO = 0, WORK(1) returns the optimal LWORK. ! ! LWORK (input) INTEGER ! The length of the array WORK. LWORK >= max(1,3*N-1). ! For optimal efficiency, LWORK >= (NB+2)*N, ! where NB is the blocksize for DSYTRD returned by ILAENV. ! ! 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. ! ! INFO (output) INTEGER ! = 0: successful exit ! < 0: if INFO = -i, the i-th argument had an illegal value ! > 0: if INFO = i, the algorithm failed to converge; i ! off-diagonal elements of an intermediate tridiagonal ! form did not converge to zero. ! ! ===================================================================== ! ! .. Parameters .. DOUBLE PRECISION ZERO, ONE PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 ) ! .. ! .. Local Scalars .. LOGICAL LOWER, LQUERY, WANTZ INTEGER IINFO, IMAX, INDE, INDTAU, INDWRK, ISCALE, & LLWORK, LWKOPT, NB DOUBLE PRECISION ANRM, BIGNUM, EPS, RMAX, RMIN, SAFMIN, SIGMA, & SMLNUM ! .. ! .. External Functions .. ! LOGICAL LSAME ! INTEGER ILAENV ! DOUBLE PRECISION DLAMCH, DLANSY ! EXTERNAL LSAME ! EXTERNAL ILAENV, DLAMCH, DLANSY ! .. ! .. External Subroutines .. ! EXTERNAL DLASCL, DORGTR, DSCAL, DSTEQR, DSTERF, DSYTRD, & ! XERBLA ! .. ! .. Intrinsic Functions .. INTRINSIC MAX, SQRT ! .. ! .. Executable Statements .. ! ! Test the input parameters. ! WANTZ = LSAME( JOBZ, 'V' ) LOWER = LSAME( UPLO, 'L' ) LQUERY = ( LWORK.EQ.-1 ) ! INFO = 0 IF( .NOT.( WANTZ .OR. LSAME( JOBZ, 'N' ) ) ) THEN INFO = -1 ELSE IF( .NOT.( LOWER .OR. LSAME( UPLO, 'U' ) ) ) THEN INFO = -2 ELSE IF( N.LT.0 ) THEN INFO = -3 ELSE IF( LDA.LT.MAX( 1, N ) ) THEN INFO = -5 END IF ! IF( INFO.EQ.0 ) THEN NB = ILAENV( 1, 'DSYTRD', UPLO, N, -1, -1, -1 ) LWKOPT = MAX( 1, ( NB+2 )*N ) WORK( 1 ) = LWKOPT ! IF( LWORK.LT.MAX( 1, 3*N-1 ) .AND. .NOT.LQUERY ) & INFO = -8 END IF ! IF( INFO.NE.0 ) THEN CALL XERBLA( 'DSYEV ', -INFO ) RETURN ELSE IF( LQUERY ) THEN RETURN END IF ! ! Quick return if possible ! IF( N.EQ.0 ) THEN RETURN END IF ! IF( N.EQ.1 ) THEN W( 1 ) = A( 1, 1 ) WORK( 1 ) = 2 IF( WANTZ ) & A( 1, 1 ) = ONE RETURN END IF ! ! Get machine constants. ! SAFMIN = DLAMCH( 'Safe minimum' ) EPS = DLAMCH( 'Precision' ) SMLNUM = SAFMIN / EPS BIGNUM = ONE / SMLNUM RMIN = SQRT( SMLNUM ) RMAX = SQRT( BIGNUM ) ! ! Scale matrix to allowable range, if necessary. ! ANRM = DLANSY( 'M', UPLO, N, A, LDA, WORK ) ISCALE = 0 IF( ANRM.GT.ZERO .AND. ANRM.LT.RMIN ) THEN ISCALE = 1 SIGMA = RMIN / ANRM ELSE IF( ANRM.GT.RMAX ) THEN ISCALE = 1 SIGMA = RMAX / ANRM END IF IF( ISCALE.EQ.1 ) & CALL DLASCL( UPLO, 0, 0, ONE, SIGMA, N, N, A, LDA, INFO ) ! ! Call DSYTRD to reduce symmetric matrix to tridiagonal form. ! INDE = 1 INDTAU = INDE + N INDWRK = INDTAU + N LLWORK = LWORK - INDWRK + 1 CALL DSYTRD( UPLO, N, A, LDA, W, WORK( INDE ), WORK( INDTAU ), & WORK( INDWRK ), LLWORK, IINFO ) ! ! For eigenvalues only, call DSTERF. For eigenvectors, first call ! DORGTR to generate the orthogonal matrix, then call DSTEQR. ! IF( .NOT.WANTZ ) THEN CALL DSTERF( N, W, WORK( INDE ), INFO ) ELSE CALL DORGTR( UPLO, N, A, LDA, WORK( INDTAU ), WORK( INDWRK ), & LLWORK, IINFO ) CALL DSTEQR( JOBZ, N, W, WORK( INDE ), A, LDA, WORK( INDTAU ), & INFO ) END IF ! ! If matrix was scaled, then rescale eigenvalues appropriately. ! IF( ISCALE.EQ.1 ) THEN IF( INFO.EQ.0 ) THEN IMAX = N ELSE IMAX = INFO - 1 END IF CALL DSCAL( IMAX, ONE / SIGMA, W, 1 ) END IF ! ! Set WORK(1) to optimal workspace size. ! WORK( 1 ) = LWKOPT ! RETURN ! ! End of DSYEV ! END SUBROUTINE DSYEV