10107 lines
294 KiB
FortranFixed
10107 lines
294 KiB
FortranFixed
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, 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 daxpy(n,da,dx,incx,dy,incy)
|
|
c
|
|
c constant times a vector plus a vector.
|
|
c uses unrolled loops for increments equal to one.
|
|
c jack dongarra, linpack, 3/11/78.
|
|
c modified 12/3/93, array(1) declarations changed to array(*)
|
|
c
|
|
double precision dx(*),dy(*),da
|
|
integer i,incx,incy,ix,iy,m,mp1,n
|
|
c
|
|
if(n.le.0)return
|
|
if (da .eq. 0.0d0) return
|
|
if(incx.eq.1.and.incy.eq.1)go to 20
|
|
c
|
|
c code for unequal increments or equal increments
|
|
c not equal to 1
|
|
c
|
|
ix = 1
|
|
iy = 1
|
|
if(incx.lt.0)ix = (-n+1)*incx + 1
|
|
if(incy.lt.0)iy = (-n+1)*incy + 1
|
|
do 10 i = 1,n
|
|
dy(iy) = dy(iy) + da*dx(ix)
|
|
ix = ix + incx
|
|
iy = iy + incy
|
|
10 continue
|
|
return
|
|
c
|
|
c code for both increments equal to 1
|
|
c
|
|
c
|
|
c clean-up loop
|
|
c
|
|
20 m = mod(n,4)
|
|
if( m .eq. 0 ) go to 40
|
|
do 30 i = 1,m
|
|
dy(i) = dy(i) + da*dx(i)
|
|
30 continue
|
|
if( n .lt. 4 ) return
|
|
40 mp1 = m + 1
|
|
do 50 i = mp1,n,4
|
|
dy(i) = dy(i) + da*dx(i)
|
|
dy(i + 1) = dy(i + 1) + da*dx(i + 1)
|
|
dy(i + 2) = dy(i + 2) + da*dx(i + 2)
|
|
dy(i + 3) = dy(i + 3) + da*dx(i + 3)
|
|
50 continue
|
|
return
|
|
end
|
|
subroutine dcopy(n,dx,incx,dy,incy)
|
|
c
|
|
c copies a vector, x, to a vector, y.
|
|
c uses unrolled loops for increments equal to one.
|
|
c jack dongarra, linpack, 3/11/78.
|
|
c modified 12/3/93, array(1) declarations changed to array(*)
|
|
c
|
|
double precision dx(*),dy(*)
|
|
integer i,incx,incy,ix,iy,m,mp1,n
|
|
c
|
|
if(n.le.0)return
|
|
if(incx.eq.1.and.incy.eq.1)go to 20
|
|
c
|
|
c code for unequal increments or equal increments
|
|
c not equal to 1
|
|
c
|
|
ix = 1
|
|
iy = 1
|
|
if(incx.lt.0)ix = (-n+1)*incx + 1
|
|
if(incy.lt.0)iy = (-n+1)*incy + 1
|
|
do 10 i = 1,n
|
|
dy(iy) = dx(ix)
|
|
ix = ix + incx
|
|
iy = iy + incy
|
|
10 continue
|
|
return
|
|
c
|
|
c code for both increments equal to 1
|
|
c
|
|
c
|
|
c clean-up loop
|
|
c
|
|
20 m = mod(n,7)
|
|
if( m .eq. 0 ) go to 40
|
|
do 30 i = 1,m
|
|
dy(i) = dx(i)
|
|
30 continue
|
|
if( n .lt. 7 ) return
|
|
40 mp1 = m + 1
|
|
do 50 i = mp1,n,7
|
|
dy(i) = dx(i)
|
|
dy(i + 1) = dx(i + 1)
|
|
dy(i + 2) = dx(i + 2)
|
|
dy(i + 3) = dx(i + 3)
|
|
dy(i + 4) = dx(i + 4)
|
|
dy(i + 5) = dx(i + 5)
|
|
dy(i + 6) = dx(i + 6)
|
|
50 continue
|
|
return
|
|
end
|
|
double precision function ddot(n,dx,incx,dy,incy)
|
|
c
|
|
c forms the dot product of two vectors.
|
|
c uses unrolled loops for increments equal to one.
|
|
c jack dongarra, linpack, 3/11/78.
|
|
c modified 12/3/93, array(1) declarations changed to array(*)
|
|
c
|
|
double precision dx(*),dy(*),dtemp
|
|
integer i,incx,incy,ix,iy,m,mp1,n
|
|
c
|
|
ddot = 0.0d0
|
|
dtemp = 0.0d0
|
|
if(n.le.0)return
|
|
if(incx.eq.1.and.incy.eq.1)go to 20
|
|
c
|
|
c code for unequal increments or equal increments
|
|
c not equal to 1
|
|
c
|
|
ix = 1
|
|
iy = 1
|
|
if(incx.lt.0)ix = (-n+1)*incx + 1
|
|
if(incy.lt.0)iy = (-n+1)*incy + 1
|
|
do 10 i = 1,n
|
|
dtemp = dtemp + dx(ix)*dy(iy)
|
|
ix = ix + incx
|
|
iy = iy + incy
|
|
10 continue
|
|
ddot = dtemp
|
|
return
|
|
c
|
|
c code for both increments equal to 1
|
|
c
|
|
c
|
|
c clean-up loop
|
|
c
|
|
20 m = mod(n,5)
|
|
if( m .eq. 0 ) go to 40
|
|
do 30 i = 1,m
|
|
dtemp = dtemp + dx(i)*dy(i)
|
|
30 continue
|
|
if( n .lt. 5 ) go to 60
|
|
40 mp1 = m + 1
|
|
do 50 i = mp1,n,5
|
|
dtemp = dtemp + dx(i)*dy(i) + dx(i + 1)*dy(i + 1) +
|
|
* dx(i + 2)*dy(i + 2) + dx(i + 3)*dy(i + 3) + dx(i + 4)*dy(i + 4)
|
|
50 continue
|
|
60 ddot = dtemp
|
|
return
|
|
end
|
|
SUBROUTINE DGEMM ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB,
|
|
$ BETA, C, LDC )
|
|
* .. Scalar Arguments ..
|
|
CHARACTER*1 TRANSA, TRANSB
|
|
INTEGER M, N, K, LDA, LDB, LDC
|
|
DOUBLE PRECISION ALPHA, BETA
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DGEMM performs one of the matrix-matrix operations
|
|
*
|
|
* C := alpha*op( A )*op( B ) + beta*C,
|
|
*
|
|
* where op( X ) is one of
|
|
*
|
|
* op( X ) = X or op( X ) = X',
|
|
*
|
|
* alpha and beta are scalars, and A, B and C are matrices, with op( A )
|
|
* an m by k matrix, op( B ) a k by n matrix and C an m by n matrix.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* TRANSA - CHARACTER*1.
|
|
* On entry, TRANSA specifies the form of op( A ) to be used in
|
|
* the matrix multiplication as follows:
|
|
*
|
|
* TRANSA = 'N' or 'n', op( A ) = A.
|
|
*
|
|
* TRANSA = 'T' or 't', op( A ) = A'.
|
|
*
|
|
* TRANSA = 'C' or 'c', op( A ) = A'.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* TRANSB - CHARACTER*1.
|
|
* On entry, TRANSB specifies the form of op( B ) to be used in
|
|
* the matrix multiplication as follows:
|
|
*
|
|
* TRANSB = 'N' or 'n', op( B ) = B.
|
|
*
|
|
* TRANSB = 'T' or 't', op( B ) = B'.
|
|
*
|
|
* TRANSB = 'C' or 'c', op( B ) = B'.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* M - INTEGER.
|
|
* On entry, M specifies the number of rows of the matrix
|
|
* op( A ) and of the matrix C. M must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the number of columns of the matrix
|
|
* op( B ) and the number of columns of the matrix C. N must be
|
|
* at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* K - INTEGER.
|
|
* On entry, K specifies the number of columns of the matrix
|
|
* op( A ) and the number of rows of the matrix op( B ). K must
|
|
* be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is
|
|
* k when TRANSA = 'N' or 'n', and is m otherwise.
|
|
* Before entry with TRANSA = 'N' or 'n', the leading m by k
|
|
* part of the array A must contain the matrix A, otherwise
|
|
* the leading k by m part of the array A must contain the
|
|
* matrix A.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. When TRANSA = 'N' or 'n' then
|
|
* LDA must be at least max( 1, m ), otherwise LDA must be at
|
|
* least max( 1, k ).
|
|
* Unchanged on exit.
|
|
*
|
|
* B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is
|
|
* n when TRANSB = 'N' or 'n', and is k otherwise.
|
|
* Before entry with TRANSB = 'N' or 'n', the leading k by n
|
|
* part of the array B must contain the matrix B, otherwise
|
|
* the leading n by k part of the array B must contain the
|
|
* matrix B.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDB - INTEGER.
|
|
* On entry, LDB specifies the first dimension of B as declared
|
|
* in the calling (sub) program. When TRANSB = 'N' or 'n' then
|
|
* LDB must be at least max( 1, k ), otherwise LDB must be at
|
|
* least max( 1, n ).
|
|
* Unchanged on exit.
|
|
*
|
|
* BETA - DOUBLE PRECISION.
|
|
* On entry, BETA specifies the scalar beta. When BETA is
|
|
* supplied as zero then C need not be set on input.
|
|
* Unchanged on exit.
|
|
*
|
|
* C - DOUBLE PRECISION array of DIMENSION ( LDC, n ).
|
|
* Before entry, the leading m by n part of the array C must
|
|
* contain the matrix C, except when beta is zero, in which
|
|
* case C need not be set on entry.
|
|
* On exit, the array C is overwritten by the m by n matrix
|
|
* ( alpha*op( A )*op( B ) + beta*C ).
|
|
*
|
|
* LDC - INTEGER.
|
|
* On entry, LDC specifies the first dimension of C as declared
|
|
* in the calling (sub) program. LDC must be at least
|
|
* max( 1, m ).
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 3 Blas routine.
|
|
*
|
|
* -- Written on 8-February-1989.
|
|
* Jack Dongarra, Argonne National Laboratory.
|
|
* Iain Duff, AERE Harwell.
|
|
* Jeremy Du Croz, Numerical Algorithms Group Ltd.
|
|
* Sven Hammarling, Numerical Algorithms Group Ltd.
|
|
*
|
|
*
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* .. Local Scalars ..
|
|
LOGICAL NOTA, NOTB
|
|
INTEGER I, INFO, J, L, NCOLA, NROWA, NROWB
|
|
DOUBLE PRECISION TEMP
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE , ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Set NOTA and NOTB as true if A and B respectively are not
|
|
* transposed and set NROWA, NCOLA and NROWB as the number of rows
|
|
* and columns of A and the number of rows of B respectively.
|
|
*
|
|
NOTA = LSAME( TRANSA, 'N' )
|
|
NOTB = LSAME( TRANSB, 'N' )
|
|
IF( NOTA )THEN
|
|
NROWA = M
|
|
NCOLA = K
|
|
ELSE
|
|
NROWA = K
|
|
NCOLA = M
|
|
END IF
|
|
IF( NOTB )THEN
|
|
NROWB = K
|
|
ELSE
|
|
NROWB = N
|
|
END IF
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
IF( ( .NOT.NOTA ).AND.
|
|
$ ( .NOT.LSAME( TRANSA, 'C' ) ).AND.
|
|
$ ( .NOT.LSAME( TRANSA, 'T' ) ) )THEN
|
|
INFO = 1
|
|
ELSE IF( ( .NOT.NOTB ).AND.
|
|
$ ( .NOT.LSAME( TRANSB, 'C' ) ).AND.
|
|
$ ( .NOT.LSAME( TRANSB, 'T' ) ) )THEN
|
|
INFO = 2
|
|
ELSE IF( M .LT.0 )THEN
|
|
INFO = 3
|
|
ELSE IF( N .LT.0 )THEN
|
|
INFO = 4
|
|
ELSE IF( K .LT.0 )THEN
|
|
INFO = 5
|
|
ELSE IF( LDA.LT.MAX( 1, NROWA ) )THEN
|
|
INFO = 8
|
|
ELSE IF( LDB.LT.MAX( 1, NROWB ) )THEN
|
|
INFO = 10
|
|
ELSE IF( LDC.LT.MAX( 1, M ) )THEN
|
|
INFO = 13
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DGEMM ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( ( M.EQ.0 ).OR.( N.EQ.0 ).OR.
|
|
$ ( ( ( ALPHA.EQ.ZERO ).OR.( K.EQ.0 ) ).AND.( BETA.EQ.ONE ) ) )
|
|
$ RETURN
|
|
*
|
|
* And if alpha.eq.zero.
|
|
*
|
|
IF( ALPHA.EQ.ZERO )THEN
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 20, J = 1, N
|
|
DO 10, I = 1, M
|
|
C( I, J ) = ZERO
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
ELSE
|
|
DO 40, J = 1, N
|
|
DO 30, I = 1, M
|
|
C( I, J ) = BETA*C( I, J )
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
END IF
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Start the operations.
|
|
*
|
|
IF( NOTB )THEN
|
|
IF( NOTA )THEN
|
|
*
|
|
* Form C := alpha*A*B + beta*C.
|
|
*
|
|
DO 90, J = 1, N
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 50, I = 1, M
|
|
C( I, J ) = ZERO
|
|
50 CONTINUE
|
|
ELSE IF( BETA.NE.ONE )THEN
|
|
DO 60, I = 1, M
|
|
C( I, J ) = BETA*C( I, J )
|
|
60 CONTINUE
|
|
END IF
|
|
DO 80, L = 1, K
|
|
IF( B( L, J ).NE.ZERO )THEN
|
|
TEMP = ALPHA*B( L, J )
|
|
DO 70, I = 1, M
|
|
C( I, J ) = C( I, J ) + TEMP*A( I, L )
|
|
70 CONTINUE
|
|
END IF
|
|
80 CONTINUE
|
|
90 CONTINUE
|
|
ELSE
|
|
*
|
|
* Form C := alpha*A'*B + beta*C
|
|
*
|
|
DO 120, J = 1, N
|
|
DO 110, I = 1, M
|
|
TEMP = ZERO
|
|
DO 100, L = 1, K
|
|
TEMP = TEMP + A( L, I )*B( L, J )
|
|
100 CONTINUE
|
|
IF( BETA.EQ.ZERO )THEN
|
|
C( I, J ) = ALPHA*TEMP
|
|
ELSE
|
|
C( I, J ) = ALPHA*TEMP + BETA*C( I, J )
|
|
END IF
|
|
110 CONTINUE
|
|
120 CONTINUE
|
|
END IF
|
|
ELSE
|
|
IF( NOTA )THEN
|
|
*
|
|
* Form C := alpha*A*B' + beta*C
|
|
*
|
|
DO 170, J = 1, N
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 130, I = 1, M
|
|
C( I, J ) = ZERO
|
|
130 CONTINUE
|
|
ELSE IF( BETA.NE.ONE )THEN
|
|
DO 140, I = 1, M
|
|
C( I, J ) = BETA*C( I, J )
|
|
140 CONTINUE
|
|
END IF
|
|
DO 160, L = 1, K
|
|
IF( B( J, L ).NE.ZERO )THEN
|
|
TEMP = ALPHA*B( J, L )
|
|
DO 150, I = 1, M
|
|
C( I, J ) = C( I, J ) + TEMP*A( I, L )
|
|
150 CONTINUE
|
|
END IF
|
|
160 CONTINUE
|
|
170 CONTINUE
|
|
ELSE
|
|
*
|
|
* Form C := alpha*A'*B' + beta*C
|
|
*
|
|
DO 200, J = 1, N
|
|
DO 190, I = 1, M
|
|
TEMP = ZERO
|
|
DO 180, L = 1, K
|
|
TEMP = TEMP + A( L, I )*B( J, L )
|
|
180 CONTINUE
|
|
IF( BETA.EQ.ZERO )THEN
|
|
C( I, J ) = ALPHA*TEMP
|
|
ELSE
|
|
C( I, J ) = ALPHA*TEMP + BETA*C( I, J )
|
|
END IF
|
|
190 CONTINUE
|
|
200 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DGEMM .
|
|
*
|
|
END
|
|
SUBROUTINE DGEMV ( TRANS, M, N, ALPHA, A, LDA, X, INCX,
|
|
$ BETA, Y, INCY )
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION ALPHA, BETA
|
|
INTEGER INCX, INCY, LDA, M, N
|
|
CHARACTER*1 TRANS
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), X( * ), Y( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DGEMV performs one of the matrix-vector operations
|
|
*
|
|
* y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y,
|
|
*
|
|
* where alpha and beta are scalars, x and y are vectors and A is an
|
|
* m by n matrix.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* TRANS - CHARACTER*1.
|
|
* On entry, TRANS specifies the operation to be performed as
|
|
* follows:
|
|
*
|
|
* TRANS = 'N' or 'n' y := alpha*A*x + beta*y.
|
|
*
|
|
* TRANS = 'T' or 't' y := alpha*A'*x + beta*y.
|
|
*
|
|
* TRANS = 'C' or 'c' y := alpha*A'*x + beta*y.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* M - INTEGER.
|
|
* On entry, M specifies the number of rows of the matrix A.
|
|
* M must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the number of columns of the matrix A.
|
|
* N must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
|
|
* Before entry, the leading m by n part of the array A must
|
|
* contain the matrix of coefficients.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. LDA must be at least
|
|
* max( 1, m ).
|
|
* Unchanged on exit.
|
|
*
|
|
* X - DOUBLE PRECISION array of DIMENSION at least
|
|
* ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n'
|
|
* and at least
|
|
* ( 1 + ( m - 1 )*abs( INCX ) ) otherwise.
|
|
* Before entry, the incremented array X must contain the
|
|
* vector x.
|
|
* Unchanged on exit.
|
|
*
|
|
* INCX - INTEGER.
|
|
* On entry, INCX specifies the increment for the elements of
|
|
* X. INCX must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* BETA - DOUBLE PRECISION.
|
|
* On entry, BETA specifies the scalar beta. When BETA is
|
|
* supplied as zero then Y need not be set on input.
|
|
* Unchanged on exit.
|
|
*
|
|
* Y - DOUBLE PRECISION array of DIMENSION at least
|
|
* ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'
|
|
* and at least
|
|
* ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.
|
|
* Before entry with BETA non-zero, the incremented array Y
|
|
* must contain the vector y. On exit, Y is overwritten by the
|
|
* updated vector y.
|
|
*
|
|
* INCY - INTEGER.
|
|
* On entry, INCY specifies the increment for the elements of
|
|
* Y. INCY must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 2 Blas routine.
|
|
*
|
|
* -- Written on 22-October-1986.
|
|
* Jack Dongarra, Argonne National Lab.
|
|
* Jeremy Du Croz, Nag Central Office.
|
|
* Sven Hammarling, Nag Central Office.
|
|
* Richard Hanson, Sandia National Labs.
|
|
*
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE , ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION TEMP
|
|
INTEGER I, INFO, IX, IY, J, JX, JY, KX, KY, LENX, LENY
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
IF ( .NOT.LSAME( TRANS, 'N' ).AND.
|
|
$ .NOT.LSAME( TRANS, 'T' ).AND.
|
|
$ .NOT.LSAME( TRANS, 'C' ) )THEN
|
|
INFO = 1
|
|
ELSE IF( M.LT.0 )THEN
|
|
INFO = 2
|
|
ELSE IF( N.LT.0 )THEN
|
|
INFO = 3
|
|
ELSE IF( LDA.LT.MAX( 1, M ) )THEN
|
|
INFO = 6
|
|
ELSE IF( INCX.EQ.0 )THEN
|
|
INFO = 8
|
|
ELSE IF( INCY.EQ.0 )THEN
|
|
INFO = 11
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DGEMV ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( ( M.EQ.0 ).OR.( N.EQ.0 ).OR.
|
|
$ ( ( ALPHA.EQ.ZERO ).AND.( BETA.EQ.ONE ) ) )
|
|
$ RETURN
|
|
*
|
|
* Set LENX and LENY, the lengths of the vectors x and y, and set
|
|
* up the start points in X and Y.
|
|
*
|
|
IF( LSAME( TRANS, 'N' ) )THEN
|
|
LENX = N
|
|
LENY = M
|
|
ELSE
|
|
LENX = M
|
|
LENY = N
|
|
END IF
|
|
IF( INCX.GT.0 )THEN
|
|
KX = 1
|
|
ELSE
|
|
KX = 1 - ( LENX - 1 )*INCX
|
|
END IF
|
|
IF( INCY.GT.0 )THEN
|
|
KY = 1
|
|
ELSE
|
|
KY = 1 - ( LENY - 1 )*INCY
|
|
END IF
|
|
*
|
|
* Start the operations. In this version the elements of A are
|
|
* accessed sequentially with one pass through A.
|
|
*
|
|
* First form y := beta*y.
|
|
*
|
|
IF( BETA.NE.ONE )THEN
|
|
IF( INCY.EQ.1 )THEN
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 10, I = 1, LENY
|
|
Y( I ) = ZERO
|
|
10 CONTINUE
|
|
ELSE
|
|
DO 20, I = 1, LENY
|
|
Y( I ) = BETA*Y( I )
|
|
20 CONTINUE
|
|
END IF
|
|
ELSE
|
|
IY = KY
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 30, I = 1, LENY
|
|
Y( IY ) = ZERO
|
|
IY = IY + INCY
|
|
30 CONTINUE
|
|
ELSE
|
|
DO 40, I = 1, LENY
|
|
Y( IY ) = BETA*Y( IY )
|
|
IY = IY + INCY
|
|
40 CONTINUE
|
|
END IF
|
|
END IF
|
|
END IF
|
|
IF( ALPHA.EQ.ZERO )
|
|
$ RETURN
|
|
IF( LSAME( TRANS, 'N' ) )THEN
|
|
*
|
|
* Form y := alpha*A*x + y.
|
|
*
|
|
JX = KX
|
|
IF( INCY.EQ.1 )THEN
|
|
DO 60, J = 1, N
|
|
IF( X( JX ).NE.ZERO )THEN
|
|
TEMP = ALPHA*X( JX )
|
|
DO 50, I = 1, M
|
|
Y( I ) = Y( I ) + TEMP*A( I, J )
|
|
50 CONTINUE
|
|
END IF
|
|
JX = JX + INCX
|
|
60 CONTINUE
|
|
ELSE
|
|
DO 80, J = 1, N
|
|
IF( X( JX ).NE.ZERO )THEN
|
|
TEMP = ALPHA*X( JX )
|
|
IY = KY
|
|
DO 70, I = 1, M
|
|
Y( IY ) = Y( IY ) + TEMP*A( I, J )
|
|
IY = IY + INCY
|
|
70 CONTINUE
|
|
END IF
|
|
JX = JX + INCX
|
|
80 CONTINUE
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form y := alpha*A'*x + y.
|
|
*
|
|
JY = KY
|
|
IF( INCX.EQ.1 )THEN
|
|
DO 100, J = 1, N
|
|
TEMP = ZERO
|
|
DO 90, I = 1, M
|
|
TEMP = TEMP + A( I, J )*X( I )
|
|
90 CONTINUE
|
|
Y( JY ) = Y( JY ) + ALPHA*TEMP
|
|
JY = JY + INCY
|
|
100 CONTINUE
|
|
ELSE
|
|
DO 120, J = 1, N
|
|
TEMP = ZERO
|
|
IX = KX
|
|
DO 110, I = 1, M
|
|
TEMP = TEMP + A( I, J )*X( IX )
|
|
IX = IX + INCX
|
|
110 CONTINUE
|
|
Y( JY ) = Y( JY ) + ALPHA*TEMP
|
|
JY = JY + INCY
|
|
120 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DGEMV .
|
|
*
|
|
END
|
|
SUBROUTINE DGER ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA )
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION ALPHA
|
|
INTEGER INCX, INCY, LDA, M, N
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), X( * ), Y( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DGER performs the rank 1 operation
|
|
*
|
|
* A := alpha*x*y' + A,
|
|
*
|
|
* where alpha is a scalar, x is an m element vector, y is an n element
|
|
* vector and A is an m by n matrix.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* M - INTEGER.
|
|
* On entry, M specifies the number of rows of the matrix A.
|
|
* M must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the number of columns of the matrix A.
|
|
* N must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha.
|
|
* Unchanged on exit.
|
|
*
|
|
* X - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( m - 1 )*abs( INCX ) ).
|
|
* Before entry, the incremented array X must contain the m
|
|
* element vector x.
|
|
* Unchanged on exit.
|
|
*
|
|
* INCX - INTEGER.
|
|
* On entry, INCX specifies the increment for the elements of
|
|
* X. INCX must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* Y - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( n - 1 )*abs( INCY ) ).
|
|
* Before entry, the incremented array Y must contain the n
|
|
* element vector y.
|
|
* Unchanged on exit.
|
|
*
|
|
* INCY - INTEGER.
|
|
* On entry, INCY specifies the increment for the elements of
|
|
* Y. INCY must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
|
|
* Before entry, the leading m by n part of the array A must
|
|
* contain the matrix of coefficients. On exit, A is
|
|
* overwritten by the updated matrix.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. LDA must be at least
|
|
* max( 1, m ).
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 2 Blas routine.
|
|
*
|
|
* -- Written on 22-October-1986.
|
|
* Jack Dongarra, Argonne National Lab.
|
|
* Jeremy Du Croz, Nag Central Office.
|
|
* Sven Hammarling, Nag Central Office.
|
|
* Richard Hanson, Sandia National Labs.
|
|
*
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D+0 )
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION TEMP
|
|
INTEGER I, INFO, IX, J, JY, KX
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
IF ( M.LT.0 )THEN
|
|
INFO = 1
|
|
ELSE IF( N.LT.0 )THEN
|
|
INFO = 2
|
|
ELSE IF( INCX.EQ.0 )THEN
|
|
INFO = 5
|
|
ELSE IF( INCY.EQ.0 )THEN
|
|
INFO = 7
|
|
ELSE IF( LDA.LT.MAX( 1, M ) )THEN
|
|
INFO = 9
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DGER ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( ( M.EQ.0 ).OR.( N.EQ.0 ).OR.( ALPHA.EQ.ZERO ) )
|
|
$ RETURN
|
|
*
|
|
* Start the operations. In this version the elements of A are
|
|
* accessed sequentially with one pass through A.
|
|
*
|
|
IF( INCY.GT.0 )THEN
|
|
JY = 1
|
|
ELSE
|
|
JY = 1 - ( N - 1 )*INCY
|
|
END IF
|
|
IF( INCX.EQ.1 )THEN
|
|
DO 20, J = 1, N
|
|
IF( Y( JY ).NE.ZERO )THEN
|
|
TEMP = ALPHA*Y( JY )
|
|
DO 10, I = 1, M
|
|
A( I, J ) = A( I, J ) + X( I )*TEMP
|
|
10 CONTINUE
|
|
END IF
|
|
JY = JY + INCY
|
|
20 CONTINUE
|
|
ELSE
|
|
IF( INCX.GT.0 )THEN
|
|
KX = 1
|
|
ELSE
|
|
KX = 1 - ( M - 1 )*INCX
|
|
END IF
|
|
DO 40, J = 1, N
|
|
IF( Y( JY ).NE.ZERO )THEN
|
|
TEMP = ALPHA*Y( JY )
|
|
IX = KX
|
|
DO 30, I = 1, M
|
|
A( I, J ) = A( I, J ) + X( IX )*TEMP
|
|
IX = IX + INCX
|
|
30 CONTINUE
|
|
END IF
|
|
JY = JY + INCY
|
|
40 CONTINUE
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DGER .
|
|
*
|
|
END
|
|
DOUBLE PRECISION FUNCTION DLAMCH( CMACH )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 1.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* October 31, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER CMACH
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAMCH determines double precision machine parameters.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* CMACH (input) CHARACTER*1
|
|
* Specifies the value to be returned by DLAMCH:
|
|
* = 'E' or 'e', DLAMCH := eps
|
|
* = 'S' or 's , DLAMCH := sfmin
|
|
* = 'B' or 'b', DLAMCH := base
|
|
* = 'P' or 'p', DLAMCH := eps*base
|
|
* = 'N' or 'n', DLAMCH := t
|
|
* = 'R' or 'r', DLAMCH := rnd
|
|
* = 'M' or 'm', DLAMCH := emin
|
|
* = 'U' or 'u', DLAMCH := rmin
|
|
* = 'L' or 'l', DLAMCH := emax
|
|
* = 'O' or 'o', DLAMCH := rmax
|
|
*
|
|
* where
|
|
*
|
|
* eps = relative machine precision
|
|
* sfmin = safe minimum, such that 1/sfmin does not overflow
|
|
* base = base of the machine
|
|
* prec = eps*base
|
|
* t = number of (base) digits in the mantissa
|
|
* rnd = 1.0 when rounding occurs in addition, 0.0 otherwise
|
|
* emin = minimum exponent before (gradual) underflow
|
|
* rmin = underflow threshold - base**(emin-1)
|
|
* emax = largest exponent before overflow
|
|
* rmax = overflow threshold - (base**emax)*(1-eps)
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL FIRST, LRND
|
|
INTEGER BETA, IMAX, IMIN, IT
|
|
DOUBLE PRECISION BASE, EMAX, EMIN, EPS, PREC, RMACH, RMAX, RMIN,
|
|
$ RND, SFMIN, SMALL, T
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLAMC2
|
|
* ..
|
|
* .. Save statement ..
|
|
SAVE FIRST, EPS, SFMIN, BASE, T, RND, EMIN, RMIN,
|
|
$ EMAX, RMAX, PREC
|
|
* ..
|
|
* .. Data statements ..
|
|
DATA FIRST / .TRUE. /
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( FIRST ) THEN
|
|
FIRST = .FALSE.
|
|
CALL DLAMC2( BETA, IT, LRND, EPS, IMIN, RMIN, IMAX, RMAX )
|
|
BASE = BETA
|
|
T = IT
|
|
IF( LRND ) THEN
|
|
RND = ONE
|
|
EPS = ( BASE**( 1-IT ) ) / 2
|
|
ELSE
|
|
RND = ZERO
|
|
EPS = BASE**( 1-IT )
|
|
END IF
|
|
PREC = EPS*BASE
|
|
EMIN = IMIN
|
|
EMAX = IMAX
|
|
SFMIN = RMIN
|
|
SMALL = ONE / RMAX
|
|
IF( SMALL.GE.SFMIN ) THEN
|
|
*
|
|
* Use SMALL plus a bit, to avoid the possibility of rounding
|
|
* causing overflow when computing 1/sfmin.
|
|
*
|
|
SFMIN = SMALL*( ONE+EPS )
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( LSAME( CMACH, 'E' ) ) THEN
|
|
RMACH = EPS
|
|
ELSE IF( LSAME( CMACH, 'S' ) ) THEN
|
|
RMACH = SFMIN
|
|
ELSE IF( LSAME( CMACH, 'B' ) ) THEN
|
|
RMACH = BASE
|
|
ELSE IF( LSAME( CMACH, 'P' ) ) THEN
|
|
RMACH = PREC
|
|
ELSE IF( LSAME( CMACH, 'N' ) ) THEN
|
|
RMACH = T
|
|
ELSE IF( LSAME( CMACH, 'R' ) ) THEN
|
|
RMACH = RND
|
|
ELSE IF( LSAME( CMACH, 'M' ) ) THEN
|
|
RMACH = EMIN
|
|
ELSE IF( LSAME( CMACH, 'U' ) ) THEN
|
|
RMACH = RMIN
|
|
ELSE IF( LSAME( CMACH, 'L' ) ) THEN
|
|
RMACH = EMAX
|
|
ELSE IF( LSAME( CMACH, 'O' ) ) THEN
|
|
RMACH = RMAX
|
|
END IF
|
|
*
|
|
DLAMCH = RMACH
|
|
RETURN
|
|
*
|
|
* End of DLAMCH
|
|
*
|
|
END
|
|
*
|
|
************************************************************************
|
|
*
|
|
SUBROUTINE DLAMC1( BETA, T, RND, IEEE1 )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 1.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* October 31, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
LOGICAL IEEE1, RND
|
|
INTEGER BETA, T
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAMC1 determines the machine parameters given by BETA, T, RND, and
|
|
* IEEE1.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* BETA (output) INTEGER
|
|
* The base of the machine.
|
|
*
|
|
* T (output) INTEGER
|
|
* The number of ( BETA ) digits in the mantissa.
|
|
*
|
|
* RND (output) LOGICAL
|
|
* Specifies whether proper rounding ( RND = .TRUE. ) or
|
|
* chopping ( RND = .FALSE. ) occurs in addition. This may not
|
|
* be a reliable guide to the way in which the machine performs
|
|
* its arithmetic.
|
|
*
|
|
* IEEE1 (output) LOGICAL
|
|
* Specifies whether rounding appears to be done in the IEEE
|
|
* 'round to nearest' style.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* The routine is based on the routine ENVRON by Malcolm and
|
|
* incorporates suggestions by Gentleman and Marovich. See
|
|
*
|
|
* Malcolm M. A. (1972) Algorithms to reveal properties of
|
|
* floating-point arithmetic. Comms. of the ACM, 15, 949-951.
|
|
*
|
|
* Gentleman W. M. and Marovich S. B. (1974) More on algorithms
|
|
* that reveal properties of floating point arithmetic units.
|
|
* Comms. of the ACM, 17, 276-277.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Local Scalars ..
|
|
LOGICAL FIRST, LIEEE1, LRND
|
|
INTEGER LBETA, LT
|
|
DOUBLE PRECISION A, B, C, F, ONE, QTR, SAVEC, T1, T2
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMC3
|
|
EXTERNAL DLAMC3
|
|
* ..
|
|
* .. Save statement ..
|
|
SAVE FIRST, LIEEE1, LBETA, LRND, LT
|
|
* ..
|
|
* .. Data statements ..
|
|
DATA FIRST / .TRUE. /
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( FIRST ) THEN
|
|
FIRST = .FALSE.
|
|
ONE = 1
|
|
*
|
|
* LBETA, LIEEE1, LT and LRND are the local values of BETA,
|
|
* IEEE1, T and RND.
|
|
*
|
|
* Throughout this routine we use the function DLAMC3 to ensure
|
|
* that relevant values are stored and not held in registers, or
|
|
* are not affected by optimizers.
|
|
*
|
|
* Compute a = 2.0**m with the smallest positive integer m such
|
|
* that
|
|
*
|
|
* fl( a + 1.0 ) = a.
|
|
*
|
|
A = 1
|
|
C = 1
|
|
*
|
|
*+ WHILE( C.EQ.ONE )LOOP
|
|
10 CONTINUE
|
|
IF( C.EQ.ONE ) THEN
|
|
A = 2*A
|
|
C = DLAMC3( A, ONE )
|
|
C = DLAMC3( C, -A )
|
|
GO TO 10
|
|
END IF
|
|
*+ END WHILE
|
|
*
|
|
* Now compute b = 2.0**m with the smallest positive integer m
|
|
* such that
|
|
*
|
|
* fl( a + b ) .gt. a.
|
|
*
|
|
B = 1
|
|
C = DLAMC3( A, B )
|
|
*
|
|
*+ WHILE( C.EQ.A )LOOP
|
|
20 CONTINUE
|
|
IF( C.EQ.A ) THEN
|
|
B = 2*B
|
|
C = DLAMC3( A, B )
|
|
GO TO 20
|
|
END IF
|
|
*+ END WHILE
|
|
*
|
|
* Now compute the base. a and c are neighbouring floating point
|
|
* numbers in the interval ( beta**t, beta**( t + 1 ) ) and so
|
|
* their difference is beta. Adding 0.25 to c is to ensure that it
|
|
* is truncated to beta and not ( beta - 1 ).
|
|
*
|
|
QTR = ONE / 4
|
|
SAVEC = C
|
|
C = DLAMC3( C, -A )
|
|
LBETA = C + QTR
|
|
*
|
|
* Now determine whether rounding or chopping occurs, by adding a
|
|
* bit less than beta/2 and a bit more than beta/2 to a.
|
|
*
|
|
B = LBETA
|
|
F = DLAMC3( B / 2, -B / 100 )
|
|
C = DLAMC3( F, A )
|
|
IF( C.EQ.A ) THEN
|
|
LRND = .TRUE.
|
|
ELSE
|
|
LRND = .FALSE.
|
|
END IF
|
|
F = DLAMC3( B / 2, B / 100 )
|
|
C = DLAMC3( F, A )
|
|
IF( ( LRND ) .AND. ( C.EQ.A ) )
|
|
$ LRND = .FALSE.
|
|
*
|
|
* Try and decide whether rounding is done in the IEEE 'round to
|
|
* nearest' style. B/2 is half a unit in the last place of the two
|
|
* numbers A and SAVEC. Furthermore, A is even, i.e. has last bit
|
|
* zero, and SAVEC is odd. Thus adding B/2 to A should not change
|
|
* A, but adding B/2 to SAVEC should change SAVEC.
|
|
*
|
|
T1 = DLAMC3( B / 2, A )
|
|
T2 = DLAMC3( B / 2, SAVEC )
|
|
LIEEE1 = ( T1.EQ.A ) .AND. ( T2.GT.SAVEC ) .AND. LRND
|
|
*
|
|
* Now find the mantissa, t. It should be the integer part of
|
|
* log to the base beta of a, however it is safer to determine t
|
|
* by powering. So we find t as the smallest positive integer for
|
|
* which
|
|
*
|
|
* fl( beta**t + 1.0 ) = 1.0.
|
|
*
|
|
LT = 0
|
|
A = 1
|
|
C = 1
|
|
*
|
|
*+ WHILE( C.EQ.ONE )LOOP
|
|
30 CONTINUE
|
|
IF( C.EQ.ONE ) THEN
|
|
LT = LT + 1
|
|
A = A*LBETA
|
|
C = DLAMC3( A, ONE )
|
|
C = DLAMC3( C, -A )
|
|
GO TO 30
|
|
END IF
|
|
*+ END WHILE
|
|
*
|
|
END IF
|
|
*
|
|
BETA = LBETA
|
|
T = LT
|
|
RND = LRND
|
|
IEEE1 = LIEEE1
|
|
RETURN
|
|
*
|
|
* End of DLAMC1
|
|
*
|
|
END
|
|
*
|
|
************************************************************************
|
|
*
|
|
SUBROUTINE DLAMC2( BETA, T, RND, EPS, EMIN, RMIN, EMAX, RMAX )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 1.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* October 31, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
LOGICAL RND
|
|
INTEGER BETA, EMAX, EMIN, T
|
|
DOUBLE PRECISION EPS, RMAX, RMIN
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAMC2 determines the machine parameters specified in its argument
|
|
* list.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* BETA (output) INTEGER
|
|
* The base of the machine.
|
|
*
|
|
* T (output) INTEGER
|
|
* The number of ( BETA ) digits in the mantissa.
|
|
*
|
|
* RND (output) LOGICAL
|
|
* Specifies whether proper rounding ( RND = .TRUE. ) or
|
|
* chopping ( RND = .FALSE. ) occurs in addition. This may not
|
|
* be a reliable guide to the way in which the machine performs
|
|
* its arithmetic.
|
|
*
|
|
* EPS (output) DOUBLE PRECISION
|
|
* The smallest positive number such that
|
|
*
|
|
* fl( 1.0 - EPS ) .LT. 1.0,
|
|
*
|
|
* where fl denotes the computed value.
|
|
*
|
|
* EMIN (output) INTEGER
|
|
* The minimum exponent before (gradual) underflow occurs.
|
|
*
|
|
* RMIN (output) DOUBLE PRECISION
|
|
* The smallest normalized number for the machine, given by
|
|
* BASE**( EMIN - 1 ), where BASE is the floating point value
|
|
* of BETA.
|
|
*
|
|
* EMAX (output) INTEGER
|
|
* The maximum exponent before overflow occurs.
|
|
*
|
|
* RMAX (output) DOUBLE PRECISION
|
|
* The largest positive number for the machine, given by
|
|
* BASE**EMAX * ( 1 - EPS ), where BASE is the floating point
|
|
* value of BETA.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* The computation of EPS is based on a routine PARANOIA by
|
|
* W. Kahan of the University of California at Berkeley.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Local Scalars ..
|
|
LOGICAL FIRST, IEEE, IWARN, LIEEE1, LRND
|
|
INTEGER GNMIN, GPMIN, I, LBETA, LEMAX, LEMIN, LT,
|
|
$ NGNMIN, NGPMIN
|
|
DOUBLE PRECISION A, B, C, HALF, LEPS, LRMAX, LRMIN, ONE, RBASE,
|
|
$ SIXTH, SMALL, THIRD, TWO, ZERO
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMC3
|
|
EXTERNAL DLAMC3
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLAMC1, DLAMC4, DLAMC5
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, MAX, MIN
|
|
* ..
|
|
* .. Save statement ..
|
|
SAVE FIRST, IWARN, LBETA, LEMAX, LEMIN, LEPS, LRMAX,
|
|
$ LRMIN, LT
|
|
* ..
|
|
* .. Data statements ..
|
|
DATA FIRST / .TRUE. / , IWARN / .FALSE. /
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( FIRST ) THEN
|
|
FIRST = .FALSE.
|
|
ZERO = 0
|
|
ONE = 1
|
|
TWO = 2
|
|
*
|
|
* LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of
|
|
* BETA, T, RND, EPS, EMIN and RMIN.
|
|
*
|
|
* Throughout this routine we use the function DLAMC3 to ensure
|
|
* that relevant values are stored and not held in registers, or
|
|
* are not affected by optimizers.
|
|
*
|
|
* DLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1.
|
|
*
|
|
CALL DLAMC1( LBETA, LT, LRND, LIEEE1 )
|
|
*
|
|
* Start to find EPS.
|
|
*
|
|
B = LBETA
|
|
A = B**( -LT )
|
|
LEPS = A
|
|
*
|
|
* Try some tricks to see whether or not this is the correct EPS.
|
|
*
|
|
B = TWO / 3
|
|
HALF = ONE / 2
|
|
SIXTH = DLAMC3( B, -HALF )
|
|
THIRD = DLAMC3( SIXTH, SIXTH )
|
|
B = DLAMC3( THIRD, -HALF )
|
|
B = DLAMC3( B, SIXTH )
|
|
B = ABS( B )
|
|
IF( B.LT.LEPS )
|
|
$ B = LEPS
|
|
*
|
|
LEPS = 1
|
|
*
|
|
*+ WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP
|
|
10 CONTINUE
|
|
IF( ( LEPS.GT.B ) .AND. ( B.GT.ZERO ) ) THEN
|
|
LEPS = B
|
|
C = DLAMC3( HALF*LEPS, ( TWO**5 )*( LEPS**2 ) )
|
|
C = DLAMC3( HALF, -C )
|
|
B = DLAMC3( HALF, C )
|
|
C = DLAMC3( HALF, -B )
|
|
B = DLAMC3( HALF, C )
|
|
GO TO 10
|
|
END IF
|
|
*+ END WHILE
|
|
*
|
|
IF( A.LT.LEPS )
|
|
$ LEPS = A
|
|
*
|
|
* Computation of EPS complete.
|
|
*
|
|
* Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3)).
|
|
* Keep dividing A by BETA until (gradual) underflow occurs. This
|
|
* is detected when we cannot recover the previous A.
|
|
*
|
|
RBASE = ONE / LBETA
|
|
SMALL = ONE
|
|
DO 20 I = 1, 3
|
|
SMALL = DLAMC3( SMALL*RBASE, ZERO )
|
|
20 CONTINUE
|
|
A = DLAMC3( ONE, SMALL )
|
|
CALL DLAMC4( NGPMIN, ONE, LBETA )
|
|
CALL DLAMC4( NGNMIN, -ONE, LBETA )
|
|
CALL DLAMC4( GPMIN, A, LBETA )
|
|
CALL DLAMC4( GNMIN, -A, LBETA )
|
|
IEEE = .FALSE.
|
|
*
|
|
IF( ( NGPMIN.EQ.NGNMIN ) .AND. ( GPMIN.EQ.GNMIN ) ) THEN
|
|
IF( NGPMIN.EQ.GPMIN ) THEN
|
|
LEMIN = NGPMIN
|
|
* ( Non twos-complement machines, no gradual underflow;
|
|
* e.g., VAX )
|
|
ELSE IF( ( GPMIN-NGPMIN ).EQ.3 ) THEN
|
|
LEMIN = NGPMIN - 1 + LT
|
|
IEEE = .TRUE.
|
|
* ( Non twos-complement machines, with gradual underflow;
|
|
* e.g., IEEE standard followers )
|
|
ELSE
|
|
LEMIN = MIN( NGPMIN, GPMIN )
|
|
* ( A guess; no known machine )
|
|
IWARN = .TRUE.
|
|
END IF
|
|
*
|
|
ELSE IF( ( NGPMIN.EQ.GPMIN ) .AND. ( NGNMIN.EQ.GNMIN ) ) THEN
|
|
IF( ABS( NGPMIN-NGNMIN ).EQ.1 ) THEN
|
|
LEMIN = MAX( NGPMIN, NGNMIN )
|
|
* ( Twos-complement machines, no gradual underflow;
|
|
* e.g., CYBER 205 )
|
|
ELSE
|
|
LEMIN = MIN( NGPMIN, NGNMIN )
|
|
* ( A guess; no known machine )
|
|
IWARN = .TRUE.
|
|
END IF
|
|
*
|
|
ELSE IF( ( ABS( NGPMIN-NGNMIN ).EQ.1 ) .AND.
|
|
$ ( GPMIN.EQ.GNMIN ) ) THEN
|
|
IF( ( GPMIN-MIN( NGPMIN, NGNMIN ) ).EQ.3 ) THEN
|
|
LEMIN = MAX( NGPMIN, NGNMIN ) - 1 + LT
|
|
* ( Twos-complement machines with gradual underflow;
|
|
* no known machine )
|
|
ELSE
|
|
LEMIN = MIN( NGPMIN, NGNMIN )
|
|
* ( A guess; no known machine )
|
|
IWARN = .TRUE.
|
|
END IF
|
|
*
|
|
ELSE
|
|
LEMIN = MIN( NGPMIN, NGNMIN, GPMIN, GNMIN )
|
|
* ( A guess; no known machine )
|
|
IWARN = .TRUE.
|
|
END IF
|
|
***
|
|
* Comment out this if block if EMIN is ok
|
|
IF( IWARN ) THEN
|
|
FIRST = .TRUE.
|
|
WRITE( 6, FMT = 9999 )LEMIN
|
|
END IF
|
|
***
|
|
*
|
|
* Assume IEEE arithmetic if we found denormalised numbers above,
|
|
* or if arithmetic seems to round in the IEEE style, determined
|
|
* in routine DLAMC1. A true IEEE machine should have both things
|
|
* true; however, faulty machines may have one or the other.
|
|
*
|
|
IEEE = IEEE .OR. LIEEE1
|
|
*
|
|
* Compute RMIN by successive division by BETA. We could compute
|
|
* RMIN as BASE**( EMIN - 1 ), but some machines underflow during
|
|
* this computation.
|
|
*
|
|
LRMIN = 1
|
|
DO 30 I = 1, 1 - LEMIN
|
|
LRMIN = DLAMC3( LRMIN*RBASE, ZERO )
|
|
30 CONTINUE
|
|
*
|
|
* Finally, call DLAMC5 to compute EMAX and RMAX.
|
|
*
|
|
CALL DLAMC5( LBETA, LT, LEMIN, IEEE, LEMAX, LRMAX )
|
|
END IF
|
|
*
|
|
BETA = LBETA
|
|
T = LT
|
|
RND = LRND
|
|
EPS = LEPS
|
|
EMIN = LEMIN
|
|
RMIN = LRMIN
|
|
EMAX = LEMAX
|
|
RMAX = LRMAX
|
|
*
|
|
RETURN
|
|
*
|
|
9999 FORMAT( / / ' WARNING. The value EMIN may be incorrect:-',
|
|
$ ' EMIN = ', I8, /
|
|
$ ' If, after inspection, the value EMIN looks',
|
|
$ ' acceptable please comment out ',
|
|
$ / ' the IF block as marked within the code of routine',
|
|
$ ' DLAMC2,', / ' otherwise supply EMIN explicitly.', / )
|
|
*
|
|
* End of DLAMC2
|
|
*
|
|
END
|
|
*
|
|
************************************************************************
|
|
*
|
|
DOUBLE PRECISION FUNCTION DLAMC3( A, B )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 1.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* October 31, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION A, B
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAMC3 is intended to force A and B to be stored prior to doing
|
|
* the addition of A and B , for use in situations where optimizers
|
|
* might hold one of these in a register.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* A, B (input) DOUBLE PRECISION
|
|
* The values A and B.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Executable Statements ..
|
|
*
|
|
DLAMC3 = A + B
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLAMC3
|
|
*
|
|
END
|
|
*
|
|
************************************************************************
|
|
*
|
|
SUBROUTINE DLAMC4( EMIN, START, BASE )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 1.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* October 31, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER BASE, EMIN
|
|
DOUBLE PRECISION START
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAMC4 is a service routine for DLAMC2.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* EMIN (output) EMIN
|
|
* The minimum exponent before (gradual) underflow, computed by
|
|
* setting A = START and dividing by BASE until the previous A
|
|
* can not be recovered.
|
|
*
|
|
* START (input) DOUBLE PRECISION
|
|
* The starting point for determining EMIN.
|
|
*
|
|
* BASE (input) INTEGER
|
|
* The base of the machine.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Local Scalars ..
|
|
INTEGER I
|
|
DOUBLE PRECISION A, B1, B2, C1, C2, D1, D2, ONE, RBASE, ZERO
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMC3
|
|
EXTERNAL DLAMC3
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
A = START
|
|
ONE = 1
|
|
RBASE = ONE / BASE
|
|
ZERO = 0
|
|
EMIN = 1
|
|
B1 = DLAMC3( A*RBASE, ZERO )
|
|
C1 = A
|
|
C2 = A
|
|
D1 = A
|
|
D2 = A
|
|
*+ WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND.
|
|
* $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP
|
|
10 CONTINUE
|
|
IF( ( C1.EQ.A ) .AND. ( C2.EQ.A ) .AND. ( D1.EQ.A ) .AND.
|
|
$ ( D2.EQ.A ) ) THEN
|
|
EMIN = EMIN - 1
|
|
A = B1
|
|
B1 = DLAMC3( A / BASE, ZERO )
|
|
C1 = DLAMC3( B1*BASE, ZERO )
|
|
D1 = ZERO
|
|
DO 20 I = 1, BASE
|
|
D1 = D1 + B1
|
|
20 CONTINUE
|
|
B2 = DLAMC3( A*RBASE, ZERO )
|
|
C2 = DLAMC3( B2 / RBASE, ZERO )
|
|
D2 = ZERO
|
|
DO 30 I = 1, BASE
|
|
D2 = D2 + B2
|
|
30 CONTINUE
|
|
GO TO 10
|
|
END IF
|
|
*+ END WHILE
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLAMC4
|
|
*
|
|
END
|
|
*
|
|
************************************************************************
|
|
*
|
|
SUBROUTINE DLAMC5( BETA, P, EMIN, IEEE, EMAX, RMAX )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 1.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* October 31, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
LOGICAL IEEE
|
|
INTEGER BETA, EMAX, EMIN, P
|
|
DOUBLE PRECISION RMAX
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAMC5 attempts to compute RMAX, the largest machine floating-point
|
|
* number, without overflow. It assumes that EMAX + abs(EMIN) sum
|
|
* approximately to a power of 2. It will fail on machines where this
|
|
* assumption does not hold, for example, the Cyber 205 (EMIN = -28625,
|
|
* EMAX = 28718). It will also fail if the value supplied for EMIN is
|
|
* too large (i.e. too close to zero), probably with overflow.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* BETA (input) INTEGER
|
|
* The base of floating-point arithmetic.
|
|
*
|
|
* P (input) INTEGER
|
|
* The number of base BETA digits in the mantissa of a
|
|
* floating-point value.
|
|
*
|
|
* EMIN (input) INTEGER
|
|
* The minimum exponent before (gradual) underflow.
|
|
*
|
|
* IEEE (input) LOGICAL
|
|
* A logical flag specifying whether or not the arithmetic
|
|
* system is thought to comply with the IEEE standard.
|
|
*
|
|
* EMAX (output) INTEGER
|
|
* The largest exponent before overflow
|
|
*
|
|
* RMAX (output) DOUBLE PRECISION
|
|
* The largest machine floating-point number.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, ONE
|
|
PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER EXBITS, EXPSUM, I, LEXP, NBITS, TRY, UEXP
|
|
DOUBLE PRECISION OLDY, RECBAS, Y, Z
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMC3
|
|
EXTERNAL DLAMC3
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MOD
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* First compute LEXP and UEXP, two powers of 2 that bound
|
|
* abs(EMIN). We then assume that EMAX + abs(EMIN) will sum
|
|
* approximately to the bound that is closest to abs(EMIN).
|
|
* (EMAX is the exponent of the required number RMAX).
|
|
*
|
|
LEXP = 1
|
|
EXBITS = 1
|
|
10 CONTINUE
|
|
TRY = LEXP*2
|
|
IF( TRY.LE.( -EMIN ) ) THEN
|
|
LEXP = TRY
|
|
EXBITS = EXBITS + 1
|
|
GO TO 10
|
|
END IF
|
|
IF( LEXP.EQ.-EMIN ) THEN
|
|
UEXP = LEXP
|
|
ELSE
|
|
UEXP = TRY
|
|
EXBITS = EXBITS + 1
|
|
END IF
|
|
*
|
|
* Now -LEXP is less than or equal to EMIN, and -UEXP is greater
|
|
* than or equal to EMIN. EXBITS is the number of bits needed to
|
|
* store the exponent.
|
|
*
|
|
IF( ( UEXP+EMIN ).GT.( -LEXP-EMIN ) ) THEN
|
|
EXPSUM = 2*LEXP
|
|
ELSE
|
|
EXPSUM = 2*UEXP
|
|
END IF
|
|
*
|
|
* EXPSUM is the exponent range, approximately equal to
|
|
* EMAX - EMIN + 1 .
|
|
*
|
|
EMAX = EXPSUM + EMIN - 1
|
|
NBITS = 1 + EXBITS + P
|
|
*
|
|
* NBITS is the total number of bits needed to store a
|
|
* floating-point number.
|
|
*
|
|
IF( ( MOD( NBITS, 2 ).EQ.1 ) .AND. ( BETA.EQ.2 ) ) THEN
|
|
*
|
|
* Either there are an odd number of bits used to store a
|
|
* floating-point number, which is unlikely, or some bits are
|
|
* not used in the representation of numbers, which is possible,
|
|
* (e.g. Cray machines) or the mantissa has an implicit bit,
|
|
* (e.g. IEEE machines, Dec Vax machines), which is perhaps the
|
|
* most likely. We have to assume the last alternative.
|
|
* If this is true, then we need to reduce EMAX by one because
|
|
* there must be some way of representing zero in an implicit-bit
|
|
* system. On machines like Cray, we are reducing EMAX by one
|
|
* unnecessarily.
|
|
*
|
|
EMAX = EMAX - 1
|
|
END IF
|
|
*
|
|
IF( IEEE ) THEN
|
|
*
|
|
* Assume we are on an IEEE machine which reserves one exponent
|
|
* for infinity and NaN.
|
|
*
|
|
EMAX = EMAX - 1
|
|
END IF
|
|
*
|
|
* Now create RMAX, the largest machine number, which should
|
|
* be equal to (1.0 - BETA**(-P)) * BETA**EMAX .
|
|
*
|
|
* First compute 1.0 - BETA**(-P), being careful that the
|
|
* result is less than 1.0 .
|
|
*
|
|
RECBAS = ONE / BETA
|
|
Z = BETA - ONE
|
|
Y = ZERO
|
|
DO 20 I = 1, P
|
|
Z = Z*RECBAS
|
|
IF( Y.LT.ONE )
|
|
$ OLDY = Y
|
|
Y = DLAMC3( Y, Z )
|
|
20 CONTINUE
|
|
IF( Y.GE.ONE )
|
|
$ Y = OLDY
|
|
*
|
|
* Now multiply by BETA**EMAX to get RMAX.
|
|
*
|
|
DO 30 I = 1, EMAX
|
|
Y = DLAMC3( Y*BETA, ZERO )
|
|
30 CONTINUE
|
|
*
|
|
RMAX = Y
|
|
RETURN
|
|
*
|
|
* End of DLAMC5
|
|
*
|
|
END
|
|
DOUBLE PRECISION FUNCTION DNRM2 ( N, X, INCX )
|
|
* .. Scalar Arguments ..
|
|
INTEGER INCX, N
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION X( * )
|
|
* ..
|
|
*
|
|
* DNRM2 returns the euclidean norm of a vector via the function
|
|
* name, so that
|
|
*
|
|
* DNRM2 := sqrt( x'*x )
|
|
*
|
|
*
|
|
*
|
|
* -- This version written on 25-October-1982.
|
|
* Modified on 14-October-1993 to inline the call to DLASSQ.
|
|
* Sven Hammarling, Nag Ltd.
|
|
*
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE , ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* .. Local Scalars ..
|
|
INTEGER IX
|
|
DOUBLE PRECISION ABSXI, NORM, SCALE, SSQ
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
IF( N.LT.1 .OR. INCX.LT.1 )THEN
|
|
NORM = ZERO
|
|
ELSE IF( N.EQ.1 )THEN
|
|
NORM = ABS( X( 1 ) )
|
|
ELSE
|
|
SCALE = ZERO
|
|
SSQ = ONE
|
|
* The following loop is equivalent to this call to the LAPACK
|
|
* auxiliary routine:
|
|
* CALL DLASSQ( N, X, INCX, SCALE, SSQ )
|
|
*
|
|
DO 10, IX = 1, 1 + ( N - 1 )*INCX, INCX
|
|
IF( X( IX ).NE.ZERO )THEN
|
|
ABSXI = ABS( X( IX ) )
|
|
IF( SCALE.LT.ABSXI )THEN
|
|
SSQ = ONE + SSQ*( SCALE/ABSXI )**2
|
|
SCALE = ABSXI
|
|
ELSE
|
|
SSQ = SSQ + ( ABSXI/SCALE )**2
|
|
END IF
|
|
END IF
|
|
10 CONTINUE
|
|
NORM = SCALE * SQRT( SSQ )
|
|
END IF
|
|
*
|
|
DNRM2 = NORM
|
|
RETURN
|
|
*
|
|
* End of DNRM2.
|
|
*
|
|
END
|
|
subroutine dscal(n,da,dx,incx)
|
|
c
|
|
c scales a vector by a constant.
|
|
c uses unrolled loops for increment equal to one.
|
|
c jack dongarra, linpack, 3/11/78.
|
|
c modified 3/93 to return if incx .le. 0.
|
|
c modified 12/3/93, array(1) declarations changed to array(*)
|
|
c
|
|
double precision da,dx(*)
|
|
integer i,incx,m,mp1,n,nincx
|
|
c
|
|
if( n.le.0 .or. incx.le.0 )return
|
|
if(incx.eq.1)go to 20
|
|
c
|
|
c code for increment not equal to 1
|
|
c
|
|
nincx = n*incx
|
|
do 10 i = 1,nincx,incx
|
|
dx(i) = da*dx(i)
|
|
10 continue
|
|
return
|
|
c
|
|
c code for increment equal to 1
|
|
c
|
|
c
|
|
c clean-up loop
|
|
c
|
|
20 m = mod(n,5)
|
|
if( m .eq. 0 ) go to 40
|
|
do 30 i = 1,m
|
|
dx(i) = da*dx(i)
|
|
30 continue
|
|
if( n .lt. 5 ) return
|
|
40 mp1 = m + 1
|
|
do 50 i = mp1,n,5
|
|
dx(i) = da*dx(i)
|
|
dx(i + 1) = da*dx(i + 1)
|
|
dx(i + 2) = da*dx(i + 2)
|
|
dx(i + 3) = da*dx(i + 3)
|
|
dx(i + 4) = da*dx(i + 4)
|
|
50 continue
|
|
return
|
|
end
|
|
subroutine dswap (n,dx,incx,dy,incy)
|
|
c
|
|
c interchanges two vectors.
|
|
c uses unrolled loops for increments equal one.
|
|
c jack dongarra, linpack, 3/11/78.
|
|
c modified 12/3/93, array(1) declarations changed to array(*)
|
|
c
|
|
double precision dx(*),dy(*),dtemp
|
|
integer i,incx,incy,ix,iy,m,mp1,n
|
|
c
|
|
if(n.le.0)return
|
|
if(incx.eq.1.and.incy.eq.1)go to 20
|
|
c
|
|
c code for unequal increments or equal increments not equal
|
|
c to 1
|
|
c
|
|
ix = 1
|
|
iy = 1
|
|
if(incx.lt.0)ix = (-n+1)*incx + 1
|
|
if(incy.lt.0)iy = (-n+1)*incy + 1
|
|
do 10 i = 1,n
|
|
dtemp = dx(ix)
|
|
dx(ix) = dy(iy)
|
|
dy(iy) = dtemp
|
|
ix = ix + incx
|
|
iy = iy + incy
|
|
10 continue
|
|
return
|
|
c
|
|
c code for both increments equal to 1
|
|
c
|
|
c
|
|
c clean-up loop
|
|
c
|
|
20 m = mod(n,3)
|
|
if( m .eq. 0 ) go to 40
|
|
do 30 i = 1,m
|
|
dtemp = dx(i)
|
|
dx(i) = dy(i)
|
|
dy(i) = dtemp
|
|
30 continue
|
|
if( n .lt. 3 ) return
|
|
40 mp1 = m + 1
|
|
do 50 i = mp1,n,3
|
|
dtemp = dx(i)
|
|
dx(i) = dy(i)
|
|
dy(i) = dtemp
|
|
dtemp = dx(i + 1)
|
|
dx(i + 1) = dy(i + 1)
|
|
dy(i + 1) = dtemp
|
|
dtemp = dx(i + 2)
|
|
dx(i + 2) = dy(i + 2)
|
|
dy(i + 2) = dtemp
|
|
50 continue
|
|
return
|
|
end
|
|
SUBROUTINE DSYMV ( UPLO, N, ALPHA, A, LDA, X, INCX,
|
|
$ BETA, Y, INCY )
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION ALPHA, BETA
|
|
INTEGER INCX, INCY, LDA, N
|
|
CHARACTER*1 UPLO
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), X( * ), Y( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSYMV performs the matrix-vector operation
|
|
*
|
|
* y := alpha*A*x + beta*y,
|
|
*
|
|
* where alpha and beta are scalars, x and y are n element vectors and
|
|
* A is an n by n symmetric matrix.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* UPLO - CHARACTER*1.
|
|
* On entry, UPLO specifies whether the upper or lower
|
|
* triangular part of the array A is to be referenced as
|
|
* follows:
|
|
*
|
|
* UPLO = 'U' or 'u' Only the upper triangular part of A
|
|
* is to be referenced.
|
|
*
|
|
* UPLO = 'L' or 'l' Only the lower triangular part of A
|
|
* is to be referenced.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the order of the matrix A.
|
|
* N must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
|
|
* Before entry with UPLO = 'U' or 'u', the leading n by n
|
|
* upper triangular part of the array A must contain the upper
|
|
* triangular part of the symmetric matrix and the strictly
|
|
* lower triangular part of A is not referenced.
|
|
* Before entry with UPLO = 'L' or 'l', the leading n by n
|
|
* lower triangular part of the array A must contain the lower
|
|
* triangular part of the symmetric matrix and the strictly
|
|
* upper triangular part of A is not referenced.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. LDA must be at least
|
|
* max( 1, n ).
|
|
* Unchanged on exit.
|
|
*
|
|
* X - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( n - 1 )*abs( INCX ) ).
|
|
* Before entry, the incremented array X must contain the n
|
|
* element vector x.
|
|
* Unchanged on exit.
|
|
*
|
|
* INCX - INTEGER.
|
|
* On entry, INCX specifies the increment for the elements of
|
|
* X. INCX must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* BETA - DOUBLE PRECISION.
|
|
* On entry, BETA specifies the scalar beta. When BETA is
|
|
* supplied as zero then Y need not be set on input.
|
|
* Unchanged on exit.
|
|
*
|
|
* Y - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( n - 1 )*abs( INCY ) ).
|
|
* Before entry, the incremented array Y must contain the n
|
|
* element vector y. On exit, Y is overwritten by the updated
|
|
* vector y.
|
|
*
|
|
* INCY - INTEGER.
|
|
* On entry, INCY specifies the increment for the elements of
|
|
* Y. INCY must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 2 Blas routine.
|
|
*
|
|
* -- Written on 22-October-1986.
|
|
* Jack Dongarra, Argonne National Lab.
|
|
* Jeremy Du Croz, Nag Central Office.
|
|
* Sven Hammarling, Nag Central Office.
|
|
* Richard Hanson, Sandia National Labs.
|
|
*
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE , ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION TEMP1, TEMP2
|
|
INTEGER I, INFO, IX, IY, J, JX, JY, KX, KY
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
IF ( .NOT.LSAME( UPLO, 'U' ).AND.
|
|
$ .NOT.LSAME( UPLO, 'L' ) )THEN
|
|
INFO = 1
|
|
ELSE IF( N.LT.0 )THEN
|
|
INFO = 2
|
|
ELSE IF( LDA.LT.MAX( 1, N ) )THEN
|
|
INFO = 5
|
|
ELSE IF( INCX.EQ.0 )THEN
|
|
INFO = 7
|
|
ELSE IF( INCY.EQ.0 )THEN
|
|
INFO = 10
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DSYMV ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( ( N.EQ.0 ).OR.( ( ALPHA.EQ.ZERO ).AND.( BETA.EQ.ONE ) ) )
|
|
$ RETURN
|
|
*
|
|
* Set up the start points in X and Y.
|
|
*
|
|
IF( INCX.GT.0 )THEN
|
|
KX = 1
|
|
ELSE
|
|
KX = 1 - ( N - 1 )*INCX
|
|
END IF
|
|
IF( INCY.GT.0 )THEN
|
|
KY = 1
|
|
ELSE
|
|
KY = 1 - ( N - 1 )*INCY
|
|
END IF
|
|
*
|
|
* Start the operations. In this version the elements of A are
|
|
* accessed sequentially with one pass through the triangular part
|
|
* of A.
|
|
*
|
|
* First form y := beta*y.
|
|
*
|
|
IF( BETA.NE.ONE )THEN
|
|
IF( INCY.EQ.1 )THEN
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 10, I = 1, N
|
|
Y( I ) = ZERO
|
|
10 CONTINUE
|
|
ELSE
|
|
DO 20, I = 1, N
|
|
Y( I ) = BETA*Y( I )
|
|
20 CONTINUE
|
|
END IF
|
|
ELSE
|
|
IY = KY
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 30, I = 1, N
|
|
Y( IY ) = ZERO
|
|
IY = IY + INCY
|
|
30 CONTINUE
|
|
ELSE
|
|
DO 40, I = 1, N
|
|
Y( IY ) = BETA*Y( IY )
|
|
IY = IY + INCY
|
|
40 CONTINUE
|
|
END IF
|
|
END IF
|
|
END IF
|
|
IF( ALPHA.EQ.ZERO )
|
|
$ RETURN
|
|
IF( LSAME( UPLO, 'U' ) )THEN
|
|
*
|
|
* Form y when A is stored in upper triangle.
|
|
*
|
|
IF( ( INCX.EQ.1 ).AND.( INCY.EQ.1 ) )THEN
|
|
DO 60, J = 1, N
|
|
TEMP1 = ALPHA*X( J )
|
|
TEMP2 = ZERO
|
|
DO 50, I = 1, J - 1
|
|
Y( I ) = Y( I ) + TEMP1*A( I, J )
|
|
TEMP2 = TEMP2 + A( I, J )*X( I )
|
|
50 CONTINUE
|
|
Y( J ) = Y( J ) + TEMP1*A( J, J ) + ALPHA*TEMP2
|
|
60 CONTINUE
|
|
ELSE
|
|
JX = KX
|
|
JY = KY
|
|
DO 80, J = 1, N
|
|
TEMP1 = ALPHA*X( JX )
|
|
TEMP2 = ZERO
|
|
IX = KX
|
|
IY = KY
|
|
DO 70, I = 1, J - 1
|
|
Y( IY ) = Y( IY ) + TEMP1*A( I, J )
|
|
TEMP2 = TEMP2 + A( I, J )*X( IX )
|
|
IX = IX + INCX
|
|
IY = IY + INCY
|
|
70 CONTINUE
|
|
Y( JY ) = Y( JY ) + TEMP1*A( J, J ) + ALPHA*TEMP2
|
|
JX = JX + INCX
|
|
JY = JY + INCY
|
|
80 CONTINUE
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form y when A is stored in lower triangle.
|
|
*
|
|
IF( ( INCX.EQ.1 ).AND.( INCY.EQ.1 ) )THEN
|
|
DO 100, J = 1, N
|
|
TEMP1 = ALPHA*X( J )
|
|
TEMP2 = ZERO
|
|
Y( J ) = Y( J ) + TEMP1*A( J, J )
|
|
DO 90, I = J + 1, N
|
|
Y( I ) = Y( I ) + TEMP1*A( I, J )
|
|
TEMP2 = TEMP2 + A( I, J )*X( I )
|
|
90 CONTINUE
|
|
Y( J ) = Y( J ) + ALPHA*TEMP2
|
|
100 CONTINUE
|
|
ELSE
|
|
JX = KX
|
|
JY = KY
|
|
DO 120, J = 1, N
|
|
TEMP1 = ALPHA*X( JX )
|
|
TEMP2 = ZERO
|
|
Y( JY ) = Y( JY ) + TEMP1*A( J, J )
|
|
IX = JX
|
|
IY = JY
|
|
DO 110, I = J + 1, N
|
|
IX = IX + INCX
|
|
IY = IY + INCY
|
|
Y( IY ) = Y( IY ) + TEMP1*A( I, J )
|
|
TEMP2 = TEMP2 + A( I, J )*X( IX )
|
|
110 CONTINUE
|
|
Y( JY ) = Y( JY ) + ALPHA*TEMP2
|
|
JX = JX + INCX
|
|
JY = JY + INCY
|
|
120 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DSYMV .
|
|
*
|
|
END
|
|
SUBROUTINE DSYR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA )
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION ALPHA
|
|
INTEGER INCX, INCY, LDA, N
|
|
CHARACTER*1 UPLO
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), X( * ), Y( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSYR2 performs the symmetric rank 2 operation
|
|
*
|
|
* A := alpha*x*y' + alpha*y*x' + A,
|
|
*
|
|
* where alpha is a scalar, x and y are n element vectors and A is an n
|
|
* by n symmetric matrix.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* UPLO - CHARACTER*1.
|
|
* On entry, UPLO specifies whether the upper or lower
|
|
* triangular part of the array A is to be referenced as
|
|
* follows:
|
|
*
|
|
* UPLO = 'U' or 'u' Only the upper triangular part of A
|
|
* is to be referenced.
|
|
*
|
|
* UPLO = 'L' or 'l' Only the lower triangular part of A
|
|
* is to be referenced.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the order of the matrix A.
|
|
* N must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha.
|
|
* Unchanged on exit.
|
|
*
|
|
* X - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( n - 1 )*abs( INCX ) ).
|
|
* Before entry, the incremented array X must contain the n
|
|
* element vector x.
|
|
* Unchanged on exit.
|
|
*
|
|
* INCX - INTEGER.
|
|
* On entry, INCX specifies the increment for the elements of
|
|
* X. INCX must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* Y - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( n - 1 )*abs( INCY ) ).
|
|
* Before entry, the incremented array Y must contain the n
|
|
* element vector y.
|
|
* Unchanged on exit.
|
|
*
|
|
* INCY - INTEGER.
|
|
* On entry, INCY specifies the increment for the elements of
|
|
* Y. INCY must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
|
|
* Before entry with UPLO = 'U' or 'u', the leading n by n
|
|
* upper triangular part of the array A must contain the upper
|
|
* triangular part of the symmetric matrix and the strictly
|
|
* lower triangular part of A is not referenced. On exit, the
|
|
* upper triangular part of the array A is overwritten by the
|
|
* upper triangular part of the updated matrix.
|
|
* Before entry with UPLO = 'L' or 'l', the leading n by n
|
|
* lower triangular part of the array A must contain the lower
|
|
* triangular part of the symmetric matrix and the strictly
|
|
* upper triangular part of A is not referenced. On exit, the
|
|
* lower triangular part of the array A is overwritten by the
|
|
* lower triangular part of the updated matrix.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. LDA must be at least
|
|
* max( 1, n ).
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 2 Blas routine.
|
|
*
|
|
* -- Written on 22-October-1986.
|
|
* Jack Dongarra, Argonne National Lab.
|
|
* Jeremy Du Croz, Nag Central Office.
|
|
* Sven Hammarling, Nag Central Office.
|
|
* Richard Hanson, Sandia National Labs.
|
|
*
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D+0 )
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION TEMP1, TEMP2
|
|
INTEGER I, INFO, IX, IY, J, JX, JY, KX, KY
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
IF ( .NOT.LSAME( UPLO, 'U' ).AND.
|
|
$ .NOT.LSAME( UPLO, 'L' ) )THEN
|
|
INFO = 1
|
|
ELSE IF( N.LT.0 )THEN
|
|
INFO = 2
|
|
ELSE IF( INCX.EQ.0 )THEN
|
|
INFO = 5
|
|
ELSE IF( INCY.EQ.0 )THEN
|
|
INFO = 7
|
|
ELSE IF( LDA.LT.MAX( 1, N ) )THEN
|
|
INFO = 9
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DSYR2 ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( ( N.EQ.0 ).OR.( ALPHA.EQ.ZERO ) )
|
|
$ RETURN
|
|
*
|
|
* Set up the start points in X and Y if the increments are not both
|
|
* unity.
|
|
*
|
|
IF( ( INCX.NE.1 ).OR.( INCY.NE.1 ) )THEN
|
|
IF( INCX.GT.0 )THEN
|
|
KX = 1
|
|
ELSE
|
|
KX = 1 - ( N - 1 )*INCX
|
|
END IF
|
|
IF( INCY.GT.0 )THEN
|
|
KY = 1
|
|
ELSE
|
|
KY = 1 - ( N - 1 )*INCY
|
|
END IF
|
|
JX = KX
|
|
JY = KY
|
|
END IF
|
|
*
|
|
* Start the operations. In this version the elements of A are
|
|
* accessed sequentially with one pass through the triangular part
|
|
* of A.
|
|
*
|
|
IF( LSAME( UPLO, 'U' ) )THEN
|
|
*
|
|
* Form A when A is stored in the upper triangle.
|
|
*
|
|
IF( ( INCX.EQ.1 ).AND.( INCY.EQ.1 ) )THEN
|
|
DO 20, J = 1, N
|
|
IF( ( X( J ).NE.ZERO ).OR.( Y( J ).NE.ZERO ) )THEN
|
|
TEMP1 = ALPHA*Y( J )
|
|
TEMP2 = ALPHA*X( J )
|
|
DO 10, I = 1, J
|
|
A( I, J ) = A( I, J ) + X( I )*TEMP1 + Y( I )*TEMP2
|
|
10 CONTINUE
|
|
END IF
|
|
20 CONTINUE
|
|
ELSE
|
|
DO 40, J = 1, N
|
|
IF( ( X( JX ).NE.ZERO ).OR.( Y( JY ).NE.ZERO ) )THEN
|
|
TEMP1 = ALPHA*Y( JY )
|
|
TEMP2 = ALPHA*X( JX )
|
|
IX = KX
|
|
IY = KY
|
|
DO 30, I = 1, J
|
|
A( I, J ) = A( I, J ) + X( IX )*TEMP1
|
|
$ + Y( IY )*TEMP2
|
|
IX = IX + INCX
|
|
IY = IY + INCY
|
|
30 CONTINUE
|
|
END IF
|
|
JX = JX + INCX
|
|
JY = JY + INCY
|
|
40 CONTINUE
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form A when A is stored in the lower triangle.
|
|
*
|
|
IF( ( INCX.EQ.1 ).AND.( INCY.EQ.1 ) )THEN
|
|
DO 60, J = 1, N
|
|
IF( ( X( J ).NE.ZERO ).OR.( Y( J ).NE.ZERO ) )THEN
|
|
TEMP1 = ALPHA*Y( J )
|
|
TEMP2 = ALPHA*X( J )
|
|
DO 50, I = J, N
|
|
A( I, J ) = A( I, J ) + X( I )*TEMP1 + Y( I )*TEMP2
|
|
50 CONTINUE
|
|
END IF
|
|
60 CONTINUE
|
|
ELSE
|
|
DO 80, J = 1, N
|
|
IF( ( X( JX ).NE.ZERO ).OR.( Y( JY ).NE.ZERO ) )THEN
|
|
TEMP1 = ALPHA*Y( JY )
|
|
TEMP2 = ALPHA*X( JX )
|
|
IX = JX
|
|
IY = JY
|
|
DO 70, I = J, N
|
|
A( I, J ) = A( I, J ) + X( IX )*TEMP1
|
|
$ + Y( IY )*TEMP2
|
|
IX = IX + INCX
|
|
IY = IY + INCY
|
|
70 CONTINUE
|
|
END IF
|
|
JX = JX + INCX
|
|
JY = JY + INCY
|
|
80 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DSYR2 .
|
|
*
|
|
END
|
|
SUBROUTINE DSYR2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB,
|
|
$ BETA, C, LDC )
|
|
* .. Scalar Arguments ..
|
|
CHARACTER*1 UPLO, TRANS
|
|
INTEGER N, K, LDA, LDB, LDC
|
|
DOUBLE PRECISION ALPHA, BETA
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSYR2K performs one of the symmetric rank 2k operations
|
|
*
|
|
* C := alpha*A*B' + alpha*B*A' + beta*C,
|
|
*
|
|
* or
|
|
*
|
|
* C := alpha*A'*B + alpha*B'*A + beta*C,
|
|
*
|
|
* where alpha and beta are scalars, C is an n by n symmetric matrix
|
|
* and A and B are n by k matrices in the first case and k by n
|
|
* matrices in the second case.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* UPLO - CHARACTER*1.
|
|
* On entry, UPLO specifies whether the upper or lower
|
|
* triangular part of the array C is to be referenced as
|
|
* follows:
|
|
*
|
|
* UPLO = 'U' or 'u' Only the upper triangular part of C
|
|
* is to be referenced.
|
|
*
|
|
* UPLO = 'L' or 'l' Only the lower triangular part of C
|
|
* is to be referenced.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* TRANS - CHARACTER*1.
|
|
* On entry, TRANS specifies the operation to be performed as
|
|
* follows:
|
|
*
|
|
* TRANS = 'N' or 'n' C := alpha*A*B' + alpha*B*A' +
|
|
* beta*C.
|
|
*
|
|
* TRANS = 'T' or 't' C := alpha*A'*B + alpha*B'*A +
|
|
* beta*C.
|
|
*
|
|
* TRANS = 'C' or 'c' C := alpha*A'*B + alpha*B'*A +
|
|
* beta*C.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the order of the matrix C. N must be
|
|
* at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* K - INTEGER.
|
|
* On entry with TRANS = 'N' or 'n', K specifies the number
|
|
* of columns of the matrices A and B, and on entry with
|
|
* TRANS = 'T' or 't' or 'C' or 'c', K specifies the number
|
|
* of rows of the matrices A and B. K must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is
|
|
* k when TRANS = 'N' or 'n', and is n otherwise.
|
|
* Before entry with TRANS = 'N' or 'n', the leading n by k
|
|
* part of the array A must contain the matrix A, otherwise
|
|
* the leading k by n part of the array A must contain the
|
|
* matrix A.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. When TRANS = 'N' or 'n'
|
|
* then LDA must be at least max( 1, n ), otherwise LDA must
|
|
* be at least max( 1, k ).
|
|
* Unchanged on exit.
|
|
*
|
|
* B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is
|
|
* k when TRANS = 'N' or 'n', and is n otherwise.
|
|
* Before entry with TRANS = 'N' or 'n', the leading n by k
|
|
* part of the array B must contain the matrix B, otherwise
|
|
* the leading k by n part of the array B must contain the
|
|
* matrix B.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDB - INTEGER.
|
|
* On entry, LDB specifies the first dimension of B as declared
|
|
* in the calling (sub) program. When TRANS = 'N' or 'n'
|
|
* then LDB must be at least max( 1, n ), otherwise LDB must
|
|
* be at least max( 1, k ).
|
|
* Unchanged on exit.
|
|
*
|
|
* BETA - DOUBLE PRECISION.
|
|
* On entry, BETA specifies the scalar beta.
|
|
* Unchanged on exit.
|
|
*
|
|
* C - DOUBLE PRECISION array of DIMENSION ( LDC, n ).
|
|
* Before entry with UPLO = 'U' or 'u', the leading n by n
|
|
* upper triangular part of the array C must contain the upper
|
|
* triangular part of the symmetric matrix and the strictly
|
|
* lower triangular part of C is not referenced. On exit, the
|
|
* upper triangular part of the array C is overwritten by the
|
|
* upper triangular part of the updated matrix.
|
|
* Before entry with UPLO = 'L' or 'l', the leading n by n
|
|
* lower triangular part of the array C must contain the lower
|
|
* triangular part of the symmetric matrix and the strictly
|
|
* upper triangular part of C is not referenced. On exit, the
|
|
* lower triangular part of the array C is overwritten by the
|
|
* lower triangular part of the updated matrix.
|
|
*
|
|
* LDC - INTEGER.
|
|
* On entry, LDC specifies the first dimension of C as declared
|
|
* in the calling (sub) program. LDC must be at least
|
|
* max( 1, n ).
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 3 Blas routine.
|
|
*
|
|
*
|
|
* -- Written on 8-February-1989.
|
|
* Jack Dongarra, Argonne National Laboratory.
|
|
* Iain Duff, AERE Harwell.
|
|
* Jeremy Du Croz, Numerical Algorithms Group Ltd.
|
|
* Sven Hammarling, Numerical Algorithms Group Ltd.
|
|
*
|
|
*
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* .. Local Scalars ..
|
|
LOGICAL UPPER
|
|
INTEGER I, INFO, J, L, NROWA
|
|
DOUBLE PRECISION TEMP1, TEMP2
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE , ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
IF( LSAME( TRANS, 'N' ) )THEN
|
|
NROWA = N
|
|
ELSE
|
|
NROWA = K
|
|
END IF
|
|
UPPER = LSAME( UPLO, 'U' )
|
|
*
|
|
INFO = 0
|
|
IF( ( .NOT.UPPER ).AND.
|
|
$ ( .NOT.LSAME( UPLO , 'L' ) ) )THEN
|
|
INFO = 1
|
|
ELSE IF( ( .NOT.LSAME( TRANS, 'N' ) ).AND.
|
|
$ ( .NOT.LSAME( TRANS, 'T' ) ).AND.
|
|
$ ( .NOT.LSAME( TRANS, 'C' ) ) )THEN
|
|
INFO = 2
|
|
ELSE IF( N .LT.0 )THEN
|
|
INFO = 3
|
|
ELSE IF( K .LT.0 )THEN
|
|
INFO = 4
|
|
ELSE IF( LDA.LT.MAX( 1, NROWA ) )THEN
|
|
INFO = 7
|
|
ELSE IF( LDB.LT.MAX( 1, NROWA ) )THEN
|
|
INFO = 9
|
|
ELSE IF( LDC.LT.MAX( 1, N ) )THEN
|
|
INFO = 12
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DSYR2K', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( ( N.EQ.0 ).OR.
|
|
$ ( ( ( ALPHA.EQ.ZERO ).OR.( K.EQ.0 ) ).AND.( BETA.EQ.ONE ) ) )
|
|
$ RETURN
|
|
*
|
|
* And when alpha.eq.zero.
|
|
*
|
|
IF( ALPHA.EQ.ZERO )THEN
|
|
IF( UPPER )THEN
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 20, J = 1, N
|
|
DO 10, I = 1, J
|
|
C( I, J ) = ZERO
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
ELSE
|
|
DO 40, J = 1, N
|
|
DO 30, I = 1, J
|
|
C( I, J ) = BETA*C( I, J )
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
END IF
|
|
ELSE
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 60, J = 1, N
|
|
DO 50, I = J, N
|
|
C( I, J ) = ZERO
|
|
50 CONTINUE
|
|
60 CONTINUE
|
|
ELSE
|
|
DO 80, J = 1, N
|
|
DO 70, I = J, N
|
|
C( I, J ) = BETA*C( I, J )
|
|
70 CONTINUE
|
|
80 CONTINUE
|
|
END IF
|
|
END IF
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Start the operations.
|
|
*
|
|
IF( LSAME( TRANS, 'N' ) )THEN
|
|
*
|
|
* Form C := alpha*A*B' + alpha*B*A' + C.
|
|
*
|
|
IF( UPPER )THEN
|
|
DO 130, J = 1, N
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 90, I = 1, J
|
|
C( I, J ) = ZERO
|
|
90 CONTINUE
|
|
ELSE IF( BETA.NE.ONE )THEN
|
|
DO 100, I = 1, J
|
|
C( I, J ) = BETA*C( I, J )
|
|
100 CONTINUE
|
|
END IF
|
|
DO 120, L = 1, K
|
|
IF( ( A( J, L ).NE.ZERO ).OR.
|
|
$ ( B( J, L ).NE.ZERO ) )THEN
|
|
TEMP1 = ALPHA*B( J, L )
|
|
TEMP2 = ALPHA*A( J, L )
|
|
DO 110, I = 1, J
|
|
C( I, J ) = C( I, J ) +
|
|
$ A( I, L )*TEMP1 + B( I, L )*TEMP2
|
|
110 CONTINUE
|
|
END IF
|
|
120 CONTINUE
|
|
130 CONTINUE
|
|
ELSE
|
|
DO 180, J = 1, N
|
|
IF( BETA.EQ.ZERO )THEN
|
|
DO 140, I = J, N
|
|
C( I, J ) = ZERO
|
|
140 CONTINUE
|
|
ELSE IF( BETA.NE.ONE )THEN
|
|
DO 150, I = J, N
|
|
C( I, J ) = BETA*C( I, J )
|
|
150 CONTINUE
|
|
END IF
|
|
DO 170, L = 1, K
|
|
IF( ( A( J, L ).NE.ZERO ).OR.
|
|
$ ( B( J, L ).NE.ZERO ) )THEN
|
|
TEMP1 = ALPHA*B( J, L )
|
|
TEMP2 = ALPHA*A( J, L )
|
|
DO 160, I = J, N
|
|
C( I, J ) = C( I, J ) +
|
|
$ A( I, L )*TEMP1 + B( I, L )*TEMP2
|
|
160 CONTINUE
|
|
END IF
|
|
170 CONTINUE
|
|
180 CONTINUE
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form C := alpha*A'*B + alpha*B'*A + C.
|
|
*
|
|
IF( UPPER )THEN
|
|
DO 210, J = 1, N
|
|
DO 200, I = 1, J
|
|
TEMP1 = ZERO
|
|
TEMP2 = ZERO
|
|
DO 190, L = 1, K
|
|
TEMP1 = TEMP1 + A( L, I )*B( L, J )
|
|
TEMP2 = TEMP2 + B( L, I )*A( L, J )
|
|
190 CONTINUE
|
|
IF( BETA.EQ.ZERO )THEN
|
|
C( I, J ) = ALPHA*TEMP1 + ALPHA*TEMP2
|
|
ELSE
|
|
C( I, J ) = BETA *C( I, J ) +
|
|
$ ALPHA*TEMP1 + ALPHA*TEMP2
|
|
END IF
|
|
200 CONTINUE
|
|
210 CONTINUE
|
|
ELSE
|
|
DO 240, J = 1, N
|
|
DO 230, I = J, N
|
|
TEMP1 = ZERO
|
|
TEMP2 = ZERO
|
|
DO 220, L = 1, K
|
|
TEMP1 = TEMP1 + A( L, I )*B( L, J )
|
|
TEMP2 = TEMP2 + B( L, I )*A( L, J )
|
|
220 CONTINUE
|
|
IF( BETA.EQ.ZERO )THEN
|
|
C( I, J ) = ALPHA*TEMP1 + ALPHA*TEMP2
|
|
ELSE
|
|
C( I, J ) = BETA *C( I, J ) +
|
|
$ ALPHA*TEMP1 + ALPHA*TEMP2
|
|
END IF
|
|
230 CONTINUE
|
|
240 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DSYR2K.
|
|
*
|
|
END
|
|
SUBROUTINE DTRMM ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA,
|
|
$ B, LDB )
|
|
* .. Scalar Arguments ..
|
|
CHARACTER*1 SIDE, UPLO, TRANSA, DIAG
|
|
INTEGER M, N, LDA, LDB
|
|
DOUBLE PRECISION ALPHA
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), B( LDB, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DTRMM performs one of the matrix-matrix operations
|
|
*
|
|
* B := alpha*op( A )*B, or B := alpha*B*op( A ),
|
|
*
|
|
* where alpha is a scalar, B is an m by n matrix, A is a unit, or
|
|
* non-unit, upper or lower triangular matrix and op( A ) is one of
|
|
*
|
|
* op( A ) = A or op( A ) = A'.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* SIDE - CHARACTER*1.
|
|
* On entry, SIDE specifies whether op( A ) multiplies B from
|
|
* the left or right as follows:
|
|
*
|
|
* SIDE = 'L' or 'l' B := alpha*op( A )*B.
|
|
*
|
|
* SIDE = 'R' or 'r' B := alpha*B*op( A ).
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* UPLO - CHARACTER*1.
|
|
* On entry, UPLO specifies whether the matrix A is an upper or
|
|
* lower triangular matrix as follows:
|
|
*
|
|
* UPLO = 'U' or 'u' A is an upper triangular matrix.
|
|
*
|
|
* UPLO = 'L' or 'l' A is a lower triangular matrix.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* TRANSA - CHARACTER*1.
|
|
* On entry, TRANSA specifies the form of op( A ) to be used in
|
|
* the matrix multiplication as follows:
|
|
*
|
|
* TRANSA = 'N' or 'n' op( A ) = A.
|
|
*
|
|
* TRANSA = 'T' or 't' op( A ) = A'.
|
|
*
|
|
* TRANSA = 'C' or 'c' op( A ) = A'.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* DIAG - CHARACTER*1.
|
|
* On entry, DIAG specifies whether or not A is unit triangular
|
|
* as follows:
|
|
*
|
|
* DIAG = 'U' or 'u' A is assumed to be unit triangular.
|
|
*
|
|
* DIAG = 'N' or 'n' A is not assumed to be unit
|
|
* triangular.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* M - INTEGER.
|
|
* On entry, M specifies the number of rows of B. M must be at
|
|
* least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the number of columns of B. N must be
|
|
* at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* ALPHA - DOUBLE PRECISION.
|
|
* On entry, ALPHA specifies the scalar alpha. When alpha is
|
|
* zero then A is not referenced and B need not be set before
|
|
* entry.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m
|
|
* when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'.
|
|
* Before entry with UPLO = 'U' or 'u', the leading k by k
|
|
* upper triangular part of the array A must contain the upper
|
|
* triangular matrix and the strictly lower triangular part of
|
|
* A is not referenced.
|
|
* Before entry with UPLO = 'L' or 'l', the leading k by k
|
|
* lower triangular part of the array A must contain the lower
|
|
* triangular matrix and the strictly upper triangular part of
|
|
* A is not referenced.
|
|
* Note that when DIAG = 'U' or 'u', the diagonal elements of
|
|
* A are not referenced either, but are assumed to be unity.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. When SIDE = 'L' or 'l' then
|
|
* LDA must be at least max( 1, m ), when SIDE = 'R' or 'r'
|
|
* then LDA must be at least max( 1, n ).
|
|
* Unchanged on exit.
|
|
*
|
|
* B - DOUBLE PRECISION array of DIMENSION ( LDB, n ).
|
|
* Before entry, the leading m by n part of the array B must
|
|
* contain the matrix B, and on exit is overwritten by the
|
|
* transformed matrix.
|
|
*
|
|
* LDB - INTEGER.
|
|
* On entry, LDB specifies the first dimension of B as declared
|
|
* in the calling (sub) program. LDB must be at least
|
|
* max( 1, m ).
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 3 Blas routine.
|
|
*
|
|
* -- Written on 8-February-1989.
|
|
* Jack Dongarra, Argonne National Laboratory.
|
|
* Iain Duff, AERE Harwell.
|
|
* Jeremy Du Croz, Numerical Algorithms Group Ltd.
|
|
* Sven Hammarling, Numerical Algorithms Group Ltd.
|
|
*
|
|
*
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* .. Local Scalars ..
|
|
LOGICAL LSIDE, NOUNIT, UPPER
|
|
INTEGER I, INFO, J, K, NROWA
|
|
DOUBLE PRECISION TEMP
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE , ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
LSIDE = LSAME( SIDE , 'L' )
|
|
IF( LSIDE )THEN
|
|
NROWA = M
|
|
ELSE
|
|
NROWA = N
|
|
END IF
|
|
NOUNIT = LSAME( DIAG , 'N' )
|
|
UPPER = LSAME( UPLO , 'U' )
|
|
*
|
|
INFO = 0
|
|
IF( ( .NOT.LSIDE ).AND.
|
|
$ ( .NOT.LSAME( SIDE , 'R' ) ) )THEN
|
|
INFO = 1
|
|
ELSE IF( ( .NOT.UPPER ).AND.
|
|
$ ( .NOT.LSAME( UPLO , 'L' ) ) )THEN
|
|
INFO = 2
|
|
ELSE IF( ( .NOT.LSAME( TRANSA, 'N' ) ).AND.
|
|
$ ( .NOT.LSAME( TRANSA, 'T' ) ).AND.
|
|
$ ( .NOT.LSAME( TRANSA, 'C' ) ) )THEN
|
|
INFO = 3
|
|
ELSE IF( ( .NOT.LSAME( DIAG , 'U' ) ).AND.
|
|
$ ( .NOT.LSAME( DIAG , 'N' ) ) )THEN
|
|
INFO = 4
|
|
ELSE IF( M .LT.0 )THEN
|
|
INFO = 5
|
|
ELSE IF( N .LT.0 )THEN
|
|
INFO = 6
|
|
ELSE IF( LDA.LT.MAX( 1, NROWA ) )THEN
|
|
INFO = 9
|
|
ELSE IF( LDB.LT.MAX( 1, M ) )THEN
|
|
INFO = 11
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DTRMM ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( N.EQ.0 )
|
|
$ RETURN
|
|
*
|
|
* And when alpha.eq.zero.
|
|
*
|
|
IF( ALPHA.EQ.ZERO )THEN
|
|
DO 20, J = 1, N
|
|
DO 10, I = 1, M
|
|
B( I, J ) = ZERO
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Start the operations.
|
|
*
|
|
IF( LSIDE )THEN
|
|
IF( LSAME( TRANSA, 'N' ) )THEN
|
|
*
|
|
* Form B := alpha*A*B.
|
|
*
|
|
IF( UPPER )THEN
|
|
DO 50, J = 1, N
|
|
DO 40, K = 1, M
|
|
IF( B( K, J ).NE.ZERO )THEN
|
|
TEMP = ALPHA*B( K, J )
|
|
DO 30, I = 1, K - 1
|
|
B( I, J ) = B( I, J ) + TEMP*A( I, K )
|
|
30 CONTINUE
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( K, K )
|
|
B( K, J ) = TEMP
|
|
END IF
|
|
40 CONTINUE
|
|
50 CONTINUE
|
|
ELSE
|
|
DO 80, J = 1, N
|
|
DO 70 K = M, 1, -1
|
|
IF( B( K, J ).NE.ZERO )THEN
|
|
TEMP = ALPHA*B( K, J )
|
|
B( K, J ) = TEMP
|
|
IF( NOUNIT )
|
|
$ B( K, J ) = B( K, J )*A( K, K )
|
|
DO 60, I = K + 1, M
|
|
B( I, J ) = B( I, J ) + TEMP*A( I, K )
|
|
60 CONTINUE
|
|
END IF
|
|
70 CONTINUE
|
|
80 CONTINUE
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form B := alpha*A'*B.
|
|
*
|
|
IF( UPPER )THEN
|
|
DO 110, J = 1, N
|
|
DO 100, I = M, 1, -1
|
|
TEMP = B( I, J )
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( I, I )
|
|
DO 90, K = 1, I - 1
|
|
TEMP = TEMP + A( K, I )*B( K, J )
|
|
90 CONTINUE
|
|
B( I, J ) = ALPHA*TEMP
|
|
100 CONTINUE
|
|
110 CONTINUE
|
|
ELSE
|
|
DO 140, J = 1, N
|
|
DO 130, I = 1, M
|
|
TEMP = B( I, J )
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( I, I )
|
|
DO 120, K = I + 1, M
|
|
TEMP = TEMP + A( K, I )*B( K, J )
|
|
120 CONTINUE
|
|
B( I, J ) = ALPHA*TEMP
|
|
130 CONTINUE
|
|
140 CONTINUE
|
|
END IF
|
|
END IF
|
|
ELSE
|
|
IF( LSAME( TRANSA, 'N' ) )THEN
|
|
*
|
|
* Form B := alpha*B*A.
|
|
*
|
|
IF( UPPER )THEN
|
|
DO 180, J = N, 1, -1
|
|
TEMP = ALPHA
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( J, J )
|
|
DO 150, I = 1, M
|
|
B( I, J ) = TEMP*B( I, J )
|
|
150 CONTINUE
|
|
DO 170, K = 1, J - 1
|
|
IF( A( K, J ).NE.ZERO )THEN
|
|
TEMP = ALPHA*A( K, J )
|
|
DO 160, I = 1, M
|
|
B( I, J ) = B( I, J ) + TEMP*B( I, K )
|
|
160 CONTINUE
|
|
END IF
|
|
170 CONTINUE
|
|
180 CONTINUE
|
|
ELSE
|
|
DO 220, J = 1, N
|
|
TEMP = ALPHA
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( J, J )
|
|
DO 190, I = 1, M
|
|
B( I, J ) = TEMP*B( I, J )
|
|
190 CONTINUE
|
|
DO 210, K = J + 1, N
|
|
IF( A( K, J ).NE.ZERO )THEN
|
|
TEMP = ALPHA*A( K, J )
|
|
DO 200, I = 1, M
|
|
B( I, J ) = B( I, J ) + TEMP*B( I, K )
|
|
200 CONTINUE
|
|
END IF
|
|
210 CONTINUE
|
|
220 CONTINUE
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form B := alpha*B*A'.
|
|
*
|
|
IF( UPPER )THEN
|
|
DO 260, K = 1, N
|
|
DO 240, J = 1, K - 1
|
|
IF( A( J, K ).NE.ZERO )THEN
|
|
TEMP = ALPHA*A( J, K )
|
|
DO 230, I = 1, M
|
|
B( I, J ) = B( I, J ) + TEMP*B( I, K )
|
|
230 CONTINUE
|
|
END IF
|
|
240 CONTINUE
|
|
TEMP = ALPHA
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( K, K )
|
|
IF( TEMP.NE.ONE )THEN
|
|
DO 250, I = 1, M
|
|
B( I, K ) = TEMP*B( I, K )
|
|
250 CONTINUE
|
|
END IF
|
|
260 CONTINUE
|
|
ELSE
|
|
DO 300, K = N, 1, -1
|
|
DO 280, J = K + 1, N
|
|
IF( A( J, K ).NE.ZERO )THEN
|
|
TEMP = ALPHA*A( J, K )
|
|
DO 270, I = 1, M
|
|
B( I, J ) = B( I, J ) + TEMP*B( I, K )
|
|
270 CONTINUE
|
|
END IF
|
|
280 CONTINUE
|
|
TEMP = ALPHA
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( K, K )
|
|
IF( TEMP.NE.ONE )THEN
|
|
DO 290, I = 1, M
|
|
B( I, K ) = TEMP*B( I, K )
|
|
290 CONTINUE
|
|
END IF
|
|
300 CONTINUE
|
|
END IF
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DTRMM .
|
|
*
|
|
END
|
|
SUBROUTINE DTRMV ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX )
|
|
* .. Scalar Arguments ..
|
|
INTEGER INCX, LDA, N
|
|
CHARACTER*1 DIAG, TRANS, UPLO
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), X( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DTRMV performs one of the matrix-vector operations
|
|
*
|
|
* x := A*x, or x := A'*x,
|
|
*
|
|
* where x is an n element vector and A is an n by n unit, or non-unit,
|
|
* upper or lower triangular matrix.
|
|
*
|
|
* Parameters
|
|
* ==========
|
|
*
|
|
* UPLO - CHARACTER*1.
|
|
* On entry, UPLO specifies whether the matrix is an upper or
|
|
* lower triangular matrix as follows:
|
|
*
|
|
* UPLO = 'U' or 'u' A is an upper triangular matrix.
|
|
*
|
|
* UPLO = 'L' or 'l' A is a lower triangular matrix.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* TRANS - CHARACTER*1.
|
|
* On entry, TRANS specifies the operation to be performed as
|
|
* follows:
|
|
*
|
|
* TRANS = 'N' or 'n' x := A*x.
|
|
*
|
|
* TRANS = 'T' or 't' x := A'*x.
|
|
*
|
|
* TRANS = 'C' or 'c' x := A'*x.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* DIAG - CHARACTER*1.
|
|
* On entry, DIAG specifies whether or not A is unit
|
|
* triangular as follows:
|
|
*
|
|
* DIAG = 'U' or 'u' A is assumed to be unit triangular.
|
|
*
|
|
* DIAG = 'N' or 'n' A is not assumed to be unit
|
|
* triangular.
|
|
*
|
|
* Unchanged on exit.
|
|
*
|
|
* N - INTEGER.
|
|
* On entry, N specifies the order of the matrix A.
|
|
* N must be at least zero.
|
|
* Unchanged on exit.
|
|
*
|
|
* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
|
|
* Before entry with UPLO = 'U' or 'u', the leading n by n
|
|
* upper triangular part of the array A must contain the upper
|
|
* triangular matrix and the strictly lower triangular part of
|
|
* A is not referenced.
|
|
* Before entry with UPLO = 'L' or 'l', the leading n by n
|
|
* lower triangular part of the array A must contain the lower
|
|
* triangular matrix and the strictly upper triangular part of
|
|
* A is not referenced.
|
|
* Note that when DIAG = 'U' or 'u', the diagonal elements of
|
|
* A are not referenced either, but are assumed to be unity.
|
|
* Unchanged on exit.
|
|
*
|
|
* LDA - INTEGER.
|
|
* On entry, LDA specifies the first dimension of A as declared
|
|
* in the calling (sub) program. LDA must be at least
|
|
* max( 1, n ).
|
|
* Unchanged on exit.
|
|
*
|
|
* X - DOUBLE PRECISION array of dimension at least
|
|
* ( 1 + ( n - 1 )*abs( INCX ) ).
|
|
* Before entry, the incremented array X must contain the n
|
|
* element vector x. On exit, X is overwritten with the
|
|
* tranformed vector x.
|
|
*
|
|
* INCX - INTEGER.
|
|
* On entry, INCX specifies the increment for the elements of
|
|
* X. INCX must not be zero.
|
|
* Unchanged on exit.
|
|
*
|
|
*
|
|
* Level 2 Blas routine.
|
|
*
|
|
* -- Written on 22-October-1986.
|
|
* Jack Dongarra, Argonne National Lab.
|
|
* Jeremy Du Croz, Nag Central Office.
|
|
* Sven Hammarling, Nag Central Office.
|
|
* Richard Hanson, Sandia National Labs.
|
|
*
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D+0 )
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION TEMP
|
|
INTEGER I, INFO, IX, J, JX, KX
|
|
LOGICAL NOUNIT
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
IF ( .NOT.LSAME( UPLO , 'U' ).AND.
|
|
$ .NOT.LSAME( UPLO , 'L' ) )THEN
|
|
INFO = 1
|
|
ELSE IF( .NOT.LSAME( TRANS, 'N' ).AND.
|
|
$ .NOT.LSAME( TRANS, 'T' ).AND.
|
|
$ .NOT.LSAME( TRANS, 'C' ) )THEN
|
|
INFO = 2
|
|
ELSE IF( .NOT.LSAME( DIAG , 'U' ).AND.
|
|
$ .NOT.LSAME( DIAG , 'N' ) )THEN
|
|
INFO = 3
|
|
ELSE IF( N.LT.0 )THEN
|
|
INFO = 4
|
|
ELSE IF( LDA.LT.MAX( 1, N ) )THEN
|
|
INFO = 6
|
|
ELSE IF( INCX.EQ.0 )THEN
|
|
INFO = 8
|
|
END IF
|
|
IF( INFO.NE.0 )THEN
|
|
CALL XERBLA( 'DTRMV ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible.
|
|
*
|
|
IF( N.EQ.0 )
|
|
$ RETURN
|
|
*
|
|
NOUNIT = LSAME( DIAG, 'N' )
|
|
*
|
|
* Set up the start point in X if the increment is not unity. This
|
|
* will be ( N - 1 )*INCX too small for descending loops.
|
|
*
|
|
IF( INCX.LE.0 )THEN
|
|
KX = 1 - ( N - 1 )*INCX
|
|
ELSE IF( INCX.NE.1 )THEN
|
|
KX = 1
|
|
END IF
|
|
*
|
|
* Start the operations. In this version the elements of A are
|
|
* accessed sequentially with one pass through A.
|
|
*
|
|
IF( LSAME( TRANS, 'N' ) )THEN
|
|
*
|
|
* Form x := A*x.
|
|
*
|
|
IF( LSAME( UPLO, 'U' ) )THEN
|
|
IF( INCX.EQ.1 )THEN
|
|
DO 20, J = 1, N
|
|
IF( X( J ).NE.ZERO )THEN
|
|
TEMP = X( J )
|
|
DO 10, I = 1, J - 1
|
|
X( I ) = X( I ) + TEMP*A( I, J )
|
|
10 CONTINUE
|
|
IF( NOUNIT )
|
|
$ X( J ) = X( J )*A( J, J )
|
|
END IF
|
|
20 CONTINUE
|
|
ELSE
|
|
JX = KX
|
|
DO 40, J = 1, N
|
|
IF( X( JX ).NE.ZERO )THEN
|
|
TEMP = X( JX )
|
|
IX = KX
|
|
DO 30, I = 1, J - 1
|
|
X( IX ) = X( IX ) + TEMP*A( I, J )
|
|
IX = IX + INCX
|
|
30 CONTINUE
|
|
IF( NOUNIT )
|
|
$ X( JX ) = X( JX )*A( J, J )
|
|
END IF
|
|
JX = JX + INCX
|
|
40 CONTINUE
|
|
END IF
|
|
ELSE
|
|
IF( INCX.EQ.1 )THEN
|
|
DO 60, J = N, 1, -1
|
|
IF( X( J ).NE.ZERO )THEN
|
|
TEMP = X( J )
|
|
DO 50, I = N, J + 1, -1
|
|
X( I ) = X( I ) + TEMP*A( I, J )
|
|
50 CONTINUE
|
|
IF( NOUNIT )
|
|
$ X( J ) = X( J )*A( J, J )
|
|
END IF
|
|
60 CONTINUE
|
|
ELSE
|
|
KX = KX + ( N - 1 )*INCX
|
|
JX = KX
|
|
DO 80, J = N, 1, -1
|
|
IF( X( JX ).NE.ZERO )THEN
|
|
TEMP = X( JX )
|
|
IX = KX
|
|
DO 70, I = N, J + 1, -1
|
|
X( IX ) = X( IX ) + TEMP*A( I, J )
|
|
IX = IX - INCX
|
|
70 CONTINUE
|
|
IF( NOUNIT )
|
|
$ X( JX ) = X( JX )*A( J, J )
|
|
END IF
|
|
JX = JX - INCX
|
|
80 CONTINUE
|
|
END IF
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form x := A'*x.
|
|
*
|
|
IF( LSAME( UPLO, 'U' ) )THEN
|
|
IF( INCX.EQ.1 )THEN
|
|
DO 100, J = N, 1, -1
|
|
TEMP = X( J )
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( J, J )
|
|
DO 90, I = J - 1, 1, -1
|
|
TEMP = TEMP + A( I, J )*X( I )
|
|
90 CONTINUE
|
|
X( J ) = TEMP
|
|
100 CONTINUE
|
|
ELSE
|
|
JX = KX + ( N - 1 )*INCX
|
|
DO 120, J = N, 1, -1
|
|
TEMP = X( JX )
|
|
IX = JX
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( J, J )
|
|
DO 110, I = J - 1, 1, -1
|
|
IX = IX - INCX
|
|
TEMP = TEMP + A( I, J )*X( IX )
|
|
110 CONTINUE
|
|
X( JX ) = TEMP
|
|
JX = JX - INCX
|
|
120 CONTINUE
|
|
END IF
|
|
ELSE
|
|
IF( INCX.EQ.1 )THEN
|
|
DO 140, J = 1, N
|
|
TEMP = X( J )
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( J, J )
|
|
DO 130, I = J + 1, N
|
|
TEMP = TEMP + A( I, J )*X( I )
|
|
130 CONTINUE
|
|
X( J ) = TEMP
|
|
140 CONTINUE
|
|
ELSE
|
|
JX = KX
|
|
DO 160, J = 1, N
|
|
TEMP = X( JX )
|
|
IX = JX
|
|
IF( NOUNIT )
|
|
$ TEMP = TEMP*A( J, J )
|
|
DO 150, I = J + 1, N
|
|
IX = IX + INCX
|
|
TEMP = TEMP + A( I, J )*X( IX )
|
|
150 CONTINUE
|
|
X( JX ) = TEMP
|
|
JX = JX + INCX
|
|
160 CONTINUE
|
|
END IF
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DTRMV .
|
|
*
|
|
END
|
|
LOGICAL FUNCTION LSAME( CA, CB )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 2.0) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* January 31, 1994
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER CA, CB
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* LSAME returns .TRUE. if CA is the same letter as CB regardless of
|
|
* case.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* CA (input) CHARACTER*1
|
|
* CB (input) CHARACTER*1
|
|
* CA and CB specify the single characters to be compared.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ICHAR
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER INTA, INTB, ZCODE
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test if the characters are equal
|
|
*
|
|
LSAME = CA.EQ.CB
|
|
IF( LSAME )
|
|
$ RETURN
|
|
*
|
|
* Now test for equivalence if both characters are alphabetic.
|
|
*
|
|
ZCODE = ICHAR( 'Z' )
|
|
*
|
|
* Use 'Z' rather than 'A' so that ASCII can be detected on Prime
|
|
* machines, on which ICHAR returns a value with bit 8 set.
|
|
* ICHAR('A') on Prime machines returns 193 which is the same as
|
|
* ICHAR('A') on an EBCDIC machine.
|
|
*
|
|
INTA = ICHAR( CA )
|
|
INTB = ICHAR( CB )
|
|
*
|
|
IF( ZCODE.EQ.90 .OR. ZCODE.EQ.122 ) THEN
|
|
*
|
|
* ASCII is assumed - ZCODE is the ASCII code of either lower or
|
|
* upper case 'Z'.
|
|
*
|
|
IF( INTA.GE.97 .AND. INTA.LE.122 ) INTA = INTA - 32
|
|
IF( INTB.GE.97 .AND. INTB.LE.122 ) INTB = INTB - 32
|
|
*
|
|
ELSE IF( ZCODE.EQ.233 .OR. ZCODE.EQ.169 ) THEN
|
|
*
|
|
* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or
|
|
* upper case 'Z'.
|
|
*
|
|
IF( INTA.GE.129 .AND. INTA.LE.137 .OR.
|
|
$ INTA.GE.145 .AND. INTA.LE.153 .OR.
|
|
$ INTA.GE.162 .AND. INTA.LE.169 ) INTA = INTA + 64
|
|
IF( INTB.GE.129 .AND. INTB.LE.137 .OR.
|
|
$ INTB.GE.145 .AND. INTB.LE.153 .OR.
|
|
$ INTB.GE.162 .AND. INTB.LE.169 ) INTB = INTB + 64
|
|
*
|
|
ELSE IF( ZCODE.EQ.218 .OR. ZCODE.EQ.250 ) THEN
|
|
*
|
|
* ASCII is assumed, on Prime machines - ZCODE is the ASCII code
|
|
* plus 128 of either lower or upper case 'Z'.
|
|
*
|
|
IF( INTA.GE.225 .AND. INTA.LE.250 ) INTA = INTA - 32
|
|
IF( INTB.GE.225 .AND. INTB.LE.250 ) INTB = INTB - 32
|
|
END IF
|
|
LSAME = INTA.EQ.INTB
|
|
*
|
|
* RETURN
|
|
*
|
|
* End of LSAME
|
|
*
|
|
END
|
|
SUBROUTINE XERBLA( SRNAME, INFO )
|
|
*
|
|
* -- LAPACK auxiliary routine (preliminary version) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
|
|
* Courant Institute, Argonne National Lab, and Rice University
|
|
* February 29, 1992
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER*6 SRNAME
|
|
INTEGER INFO
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* XERBLA is an error handler for the LAPACK routines.
|
|
* It is called by an LAPACK routine if an input parameter has an
|
|
* invalid value. A message is printed and execution stops.
|
|
*
|
|
* Installers may consider modifying the STOP statement in order to
|
|
* call system-specific exception-handling facilities.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* SRNAME (input) CHARACTER*6
|
|
* The name of the routine which called XERBLA.
|
|
*
|
|
* INFO (input) INTEGER
|
|
* The position of the invalid parameter in the parameter list
|
|
* of the calling routine.
|
|
*
|
|
*
|
|
WRITE( *, FMT = 9999 )SRNAME, INFO
|
|
*
|
|
STOP
|
|
*
|
|
9999 FORMAT( ' ** On entry to ', A6, ' parameter number ', I2, ' had ',
|
|
$ 'an illegal value' )
|
|
*
|
|
* End of XERBLA
|
|
*
|
|
END
|
|
SUBROUTINE DLAE2( A, B, C, RT1, RT2 )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION A, B, C, RT1, RT2
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix
|
|
* [ A B ]
|
|
* [ B C ].
|
|
* On return, RT1 is the eigenvalue of larger absolute value, and RT2
|
|
* is the eigenvalue of smaller absolute value.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* A (input) DOUBLE PRECISION
|
|
* The (1,1) element of the 2-by-2 matrix.
|
|
*
|
|
* B (input) DOUBLE PRECISION
|
|
* The (1,2) and (2,1) elements of the 2-by-2 matrix.
|
|
*
|
|
* C (input) DOUBLE PRECISION
|
|
* The (2,2) element of the 2-by-2 matrix.
|
|
*
|
|
* RT1 (output) DOUBLE PRECISION
|
|
* The eigenvalue of larger absolute value.
|
|
*
|
|
* RT2 (output) DOUBLE PRECISION
|
|
* The eigenvalue of smaller absolute value.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* RT1 is accurate to a few ulps barring over/underflow.
|
|
*
|
|
* RT2 may be inaccurate if there is massive cancellation in the
|
|
* determinant A*C-B*B; higher precision or correctly rounded or
|
|
* correctly truncated arithmetic would be needed to compute RT2
|
|
* accurately in all cases.
|
|
*
|
|
* Overflow is possible only if RT1 is within a factor of 5 of overflow.
|
|
* Underflow is harmless if the input data is 0 or exceeds
|
|
* underflow_threshold / macheps.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE
|
|
PARAMETER ( ONE = 1.0D0 )
|
|
DOUBLE PRECISION TWO
|
|
PARAMETER ( TWO = 2.0D0 )
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D0 )
|
|
DOUBLE PRECISION HALF
|
|
PARAMETER ( HALF = 0.5D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION AB, ACMN, ACMX, ADF, DF, RT, SM, TB
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Compute the eigenvalues
|
|
*
|
|
SM = A + C
|
|
DF = A - C
|
|
ADF = ABS( DF )
|
|
TB = B + B
|
|
AB = ABS( TB )
|
|
IF( ABS( A ).GT.ABS( C ) ) THEN
|
|
ACMX = A
|
|
ACMN = C
|
|
ELSE
|
|
ACMX = C
|
|
ACMN = A
|
|
END IF
|
|
IF( ADF.GT.AB ) THEN
|
|
RT = ADF*SQRT( ONE+( AB / ADF )**2 )
|
|
ELSE IF( ADF.LT.AB ) THEN
|
|
RT = AB*SQRT( ONE+( ADF / AB )**2 )
|
|
ELSE
|
|
*
|
|
* Includes case AB=ADF=0
|
|
*
|
|
RT = AB*SQRT( TWO )
|
|
END IF
|
|
IF( SM.LT.ZERO ) THEN
|
|
RT1 = HALF*( SM-RT )
|
|
*
|
|
* Order of execution important.
|
|
* To get fully accurate smaller eigenvalue,
|
|
* next line needs to be executed in higher precision.
|
|
*
|
|
RT2 = ( ACMX / RT1 )*ACMN - ( B / RT1 )*B
|
|
ELSE IF( SM.GT.ZERO ) THEN
|
|
RT1 = HALF*( SM+RT )
|
|
*
|
|
* Order of execution important.
|
|
* To get fully accurate smaller eigenvalue,
|
|
* next line needs to be executed in higher precision.
|
|
*
|
|
RT2 = ( ACMX / RT1 )*ACMN - ( B / RT1 )*B
|
|
ELSE
|
|
*
|
|
* Includes case RT1 = RT2 = 0
|
|
*
|
|
RT1 = HALF*RT
|
|
RT2 = -HALF*RT
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLAE2
|
|
*
|
|
END
|
|
SUBROUTINE DLAEV2( A, B, C, RT1, RT2, CS1, SN1 )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION A, B, C, CS1, RT1, RT2, SN1
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix
|
|
* [ A B ]
|
|
* [ B C ].
|
|
* On return, RT1 is the eigenvalue of larger absolute value, RT2 is the
|
|
* eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right
|
|
* eigenvector for RT1, giving the decomposition
|
|
*
|
|
* [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ]
|
|
* [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ].
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* A (input) DOUBLE PRECISION
|
|
* The (1,1) element of the 2-by-2 matrix.
|
|
*
|
|
* B (input) DOUBLE PRECISION
|
|
* The (1,2) element and the conjugate of the (2,1) element of
|
|
* the 2-by-2 matrix.
|
|
*
|
|
* C (input) DOUBLE PRECISION
|
|
* The (2,2) element of the 2-by-2 matrix.
|
|
*
|
|
* RT1 (output) DOUBLE PRECISION
|
|
* The eigenvalue of larger absolute value.
|
|
*
|
|
* RT2 (output) DOUBLE PRECISION
|
|
* The eigenvalue of smaller absolute value.
|
|
*
|
|
* CS1 (output) DOUBLE PRECISION
|
|
* SN1 (output) DOUBLE PRECISION
|
|
* The vector (CS1, SN1) is a unit right eigenvector for RT1.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* RT1 is accurate to a few ulps barring over/underflow.
|
|
*
|
|
* RT2 may be inaccurate if there is massive cancellation in the
|
|
* determinant A*C-B*B; higher precision or correctly rounded or
|
|
* correctly truncated arithmetic would be needed to compute RT2
|
|
* accurately in all cases.
|
|
*
|
|
* CS1 and SN1 are accurate to a few ulps barring over/underflow.
|
|
*
|
|
* Overflow is possible only if RT1 is within a factor of 5 of overflow.
|
|
* Underflow is harmless if the input data is 0 or exceeds
|
|
* underflow_threshold / macheps.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE
|
|
PARAMETER ( ONE = 1.0D0 )
|
|
DOUBLE PRECISION TWO
|
|
PARAMETER ( TWO = 2.0D0 )
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D0 )
|
|
DOUBLE PRECISION HALF
|
|
PARAMETER ( HALF = 0.5D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER SGN1, SGN2
|
|
DOUBLE PRECISION AB, ACMN, ACMX, ACS, ADF, CS, CT, DF, RT, SM,
|
|
$ TB, TN
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Compute the eigenvalues
|
|
*
|
|
SM = A + C
|
|
DF = A - C
|
|
ADF = ABS( DF )
|
|
TB = B + B
|
|
AB = ABS( TB )
|
|
IF( ABS( A ).GT.ABS( C ) ) THEN
|
|
ACMX = A
|
|
ACMN = C
|
|
ELSE
|
|
ACMX = C
|
|
ACMN = A
|
|
END IF
|
|
IF( ADF.GT.AB ) THEN
|
|
RT = ADF*SQRT( ONE+( AB / ADF )**2 )
|
|
ELSE IF( ADF.LT.AB ) THEN
|
|
RT = AB*SQRT( ONE+( ADF / AB )**2 )
|
|
ELSE
|
|
*
|
|
* Includes case AB=ADF=0
|
|
*
|
|
RT = AB*SQRT( TWO )
|
|
END IF
|
|
IF( SM.LT.ZERO ) THEN
|
|
RT1 = HALF*( SM-RT )
|
|
SGN1 = -1
|
|
*
|
|
* Order of execution important.
|
|
* To get fully accurate smaller eigenvalue,
|
|
* next line needs to be executed in higher precision.
|
|
*
|
|
RT2 = ( ACMX / RT1 )*ACMN - ( B / RT1 )*B
|
|
ELSE IF( SM.GT.ZERO ) THEN
|
|
RT1 = HALF*( SM+RT )
|
|
SGN1 = 1
|
|
*
|
|
* Order of execution important.
|
|
* To get fully accurate smaller eigenvalue,
|
|
* next line needs to be executed in higher precision.
|
|
*
|
|
RT2 = ( ACMX / RT1 )*ACMN - ( B / RT1 )*B
|
|
ELSE
|
|
*
|
|
* Includes case RT1 = RT2 = 0
|
|
*
|
|
RT1 = HALF*RT
|
|
RT2 = -HALF*RT
|
|
SGN1 = 1
|
|
END IF
|
|
*
|
|
* Compute the eigenvector
|
|
*
|
|
IF( DF.GE.ZERO ) THEN
|
|
CS = DF + RT
|
|
SGN2 = 1
|
|
ELSE
|
|
CS = DF - RT
|
|
SGN2 = -1
|
|
END IF
|
|
ACS = ABS( CS )
|
|
IF( ACS.GT.AB ) THEN
|
|
CT = -TB / CS
|
|
SN1 = ONE / SQRT( ONE+CT*CT )
|
|
CS1 = CT*SN1
|
|
ELSE
|
|
IF( AB.EQ.ZERO ) THEN
|
|
CS1 = ONE
|
|
SN1 = ZERO
|
|
ELSE
|
|
TN = -CS / TB
|
|
CS1 = ONE / SQRT( ONE+TN*TN )
|
|
SN1 = TN*CS1
|
|
END IF
|
|
END IF
|
|
IF( SGN1.EQ.SGN2 ) THEN
|
|
TN = CS1
|
|
CS1 = -SN1
|
|
SN1 = TN
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLAEV2
|
|
*
|
|
END
|
|
DOUBLE PRECISION FUNCTION DLANST( NORM, N, D, E )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER NORM
|
|
INTEGER N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION D( * ), E( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLANST returns the value of the one norm, or the Frobenius norm, or
|
|
* the infinity norm, or the element of largest absolute value of a
|
|
* real symmetric tridiagonal matrix A.
|
|
*
|
|
* Description
|
|
* ===========
|
|
*
|
|
* DLANST returns the value
|
|
*
|
|
* DLANST = ( max(abs(A(i,j))), NORM = 'M' or 'm'
|
|
* (
|
|
* ( norm1(A), NORM = '1', 'O' or 'o'
|
|
* (
|
|
* ( normI(A), NORM = 'I' or 'i'
|
|
* (
|
|
* ( normF(A), NORM = 'F', 'f', 'E' or 'e'
|
|
*
|
|
* where norm1 denotes the one norm of a matrix (maximum column sum),
|
|
* normI denotes the infinity norm of a matrix (maximum row sum) and
|
|
* normF denotes the Frobenius norm of a matrix (square root of sum of
|
|
* squares). Note that max(abs(A(i,j))) is not a consistent matrix norm.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* NORM (input) CHARACTER*1
|
|
* Specifies the value to be returned in DLANST as described
|
|
* above.
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the matrix A. N >= 0. When N = 0, DLANST is
|
|
* set to zero.
|
|
*
|
|
* D (input) DOUBLE PRECISION array, dimension (N)
|
|
* The diagonal elements of A.
|
|
*
|
|
* E (input) DOUBLE PRECISION array, dimension (N-1)
|
|
* The (n-1) sub-diagonal or super-diagonal elements of A.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I
|
|
DOUBLE PRECISION ANORM, SCALE, SUM
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLASSQ
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, MAX, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( N.LE.0 ) THEN
|
|
ANORM = ZERO
|
|
ELSE IF( LSAME( NORM, 'M' ) ) THEN
|
|
*
|
|
* Find max(abs(A(i,j))).
|
|
*
|
|
ANORM = ABS( D( N ) )
|
|
DO 10 I = 1, N - 1
|
|
ANORM = MAX( ANORM, ABS( D( I ) ) )
|
|
ANORM = MAX( ANORM, ABS( E( I ) ) )
|
|
10 CONTINUE
|
|
ELSE IF( LSAME( NORM, 'O' ) .OR. NORM.EQ.'1' .OR.
|
|
$ LSAME( NORM, 'I' ) ) THEN
|
|
*
|
|
* Find norm1(A).
|
|
*
|
|
IF( N.EQ.1 ) THEN
|
|
ANORM = ABS( D( 1 ) )
|
|
ELSE
|
|
ANORM = MAX( ABS( D( 1 ) )+ABS( E( 1 ) ),
|
|
$ ABS( E( N-1 ) )+ABS( D( N ) ) )
|
|
DO 20 I = 2, N - 1
|
|
ANORM = MAX( ANORM, ABS( D( I ) )+ABS( E( I ) )+
|
|
$ ABS( E( I-1 ) ) )
|
|
20 CONTINUE
|
|
END IF
|
|
ELSE IF( ( LSAME( NORM, 'F' ) ) .OR. ( LSAME( NORM, 'E' ) ) ) THEN
|
|
*
|
|
* Find normF(A).
|
|
*
|
|
SCALE = ZERO
|
|
SUM = ONE
|
|
IF( N.GT.1 ) THEN
|
|
CALL DLASSQ( N-1, E, 1, SCALE, SUM )
|
|
SUM = 2*SUM
|
|
END IF
|
|
CALL DLASSQ( N, D, 1, SCALE, SUM )
|
|
ANORM = SCALE*SQRT( SUM )
|
|
END IF
|
|
*
|
|
DLANST = ANORM
|
|
RETURN
|
|
*
|
|
* End of DLANST
|
|
*
|
|
END
|
|
DOUBLE PRECISION FUNCTION DLANSY( NORM, UPLO, N, A, LDA, WORK )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER NORM, UPLO
|
|
INTEGER LDA, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLANSY returns the value of the one norm, or the Frobenius norm, or
|
|
* the infinity norm, or the element of largest absolute value of a
|
|
* real symmetric matrix A.
|
|
*
|
|
* Description
|
|
* ===========
|
|
*
|
|
* DLANSY returns the value
|
|
*
|
|
* DLANSY = ( max(abs(A(i,j))), NORM = 'M' or 'm'
|
|
* (
|
|
* ( norm1(A), NORM = '1', 'O' or 'o'
|
|
* (
|
|
* ( normI(A), NORM = 'I' or 'i'
|
|
* (
|
|
* ( normF(A), NORM = 'F', 'f', 'E' or 'e'
|
|
*
|
|
* where norm1 denotes the one norm of a matrix (maximum column sum),
|
|
* normI denotes the infinity norm of a matrix (maximum row sum) and
|
|
* normF denotes the Frobenius norm of a matrix (square root of sum of
|
|
* squares). Note that max(abs(A(i,j))) is not a consistent matrix norm.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* NORM (input) CHARACTER*1
|
|
* Specifies the value to be returned in DLANSY as described
|
|
* above.
|
|
*
|
|
* UPLO (input) CHARACTER*1
|
|
* Specifies whether the upper or lower triangular part of the
|
|
* symmetric matrix A is to be referenced.
|
|
* = 'U': Upper triangular part of A is referenced
|
|
* = 'L': Lower triangular part of A is referenced
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the matrix A. N >= 0. When N = 0, DLANSY is
|
|
* set to zero.
|
|
*
|
|
* A (input) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* 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, and the strictly lower triangular part of A
|
|
* is not referenced. If UPLO = 'L', the leading n by n lower
|
|
* triangular part of A contains the lower triangular part of
|
|
* the matrix A, and the strictly upper triangular part of A is
|
|
* not referenced.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(N,1).
|
|
*
|
|
* WORK (workspace) DOUBLE PRECISION array, dimension (MAX(1,LWORK)),
|
|
* where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise,
|
|
* WORK is not referenced.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, J
|
|
DOUBLE PRECISION ABSA, SCALE, SUM, VALUE
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLASSQ
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, MAX, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( N.EQ.0 ) THEN
|
|
VALUE = ZERO
|
|
ELSE IF( LSAME( NORM, 'M' ) ) THEN
|
|
*
|
|
* Find max(abs(A(i,j))).
|
|
*
|
|
VALUE = ZERO
|
|
IF( LSAME( UPLO, 'U' ) ) THEN
|
|
DO 20 J = 1, N
|
|
DO 10 I = 1, J
|
|
VALUE = MAX( VALUE, ABS( A( I, J ) ) )
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
ELSE
|
|
DO 40 J = 1, N
|
|
DO 30 I = J, N
|
|
VALUE = MAX( VALUE, ABS( A( I, J ) ) )
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
END IF
|
|
ELSE IF( ( LSAME( NORM, 'I' ) ) .OR. ( LSAME( NORM, 'O' ) ) .OR.
|
|
$ ( NORM.EQ.'1' ) ) THEN
|
|
*
|
|
* Find normI(A) ( = norm1(A), since A is symmetric).
|
|
*
|
|
VALUE = ZERO
|
|
IF( LSAME( UPLO, 'U' ) ) THEN
|
|
DO 60 J = 1, N
|
|
SUM = ZERO
|
|
DO 50 I = 1, J - 1
|
|
ABSA = ABS( A( I, J ) )
|
|
SUM = SUM + ABSA
|
|
WORK( I ) = WORK( I ) + ABSA
|
|
50 CONTINUE
|
|
WORK( J ) = SUM + ABS( A( J, J ) )
|
|
60 CONTINUE
|
|
DO 70 I = 1, N
|
|
VALUE = MAX( VALUE, WORK( I ) )
|
|
70 CONTINUE
|
|
ELSE
|
|
DO 80 I = 1, N
|
|
WORK( I ) = ZERO
|
|
80 CONTINUE
|
|
DO 100 J = 1, N
|
|
SUM = WORK( J ) + ABS( A( J, J ) )
|
|
DO 90 I = J + 1, N
|
|
ABSA = ABS( A( I, J ) )
|
|
SUM = SUM + ABSA
|
|
WORK( I ) = WORK( I ) + ABSA
|
|
90 CONTINUE
|
|
VALUE = MAX( VALUE, SUM )
|
|
100 CONTINUE
|
|
END IF
|
|
ELSE IF( ( LSAME( NORM, 'F' ) ) .OR. ( LSAME( NORM, 'E' ) ) ) THEN
|
|
*
|
|
* Find normF(A).
|
|
*
|
|
SCALE = ZERO
|
|
SUM = ONE
|
|
IF( LSAME( UPLO, 'U' ) ) THEN
|
|
DO 110 J = 2, N
|
|
CALL DLASSQ( J-1, A( 1, J ), 1, SCALE, SUM )
|
|
110 CONTINUE
|
|
ELSE
|
|
DO 120 J = 1, N - 1
|
|
CALL DLASSQ( N-J, A( J+1, J ), 1, SCALE, SUM )
|
|
120 CONTINUE
|
|
END IF
|
|
SUM = 2*SUM
|
|
CALL DLASSQ( N, A, LDA+1, SCALE, SUM )
|
|
VALUE = SCALE*SQRT( SUM )
|
|
END IF
|
|
*
|
|
DLANSY = VALUE
|
|
RETURN
|
|
*
|
|
* End of DLANSY
|
|
*
|
|
END
|
|
DOUBLE PRECISION FUNCTION DLAPY2( X, Y )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION X, Y
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLAPY2 returns sqrt(x**2+y**2), taking care not to cause unnecessary
|
|
* overflow.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* X (input) DOUBLE PRECISION
|
|
* Y (input) DOUBLE PRECISION
|
|
* X and Y specify the values x and y.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D0 )
|
|
DOUBLE PRECISION ONE
|
|
PARAMETER ( ONE = 1.0D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
DOUBLE PRECISION W, XABS, YABS, Z
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, MAX, MIN, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
XABS = ABS( X )
|
|
YABS = ABS( Y )
|
|
W = MAX( XABS, YABS )
|
|
Z = MIN( XABS, YABS )
|
|
IF( Z.EQ.ZERO ) THEN
|
|
DLAPY2 = W
|
|
ELSE
|
|
DLAPY2 = W*SQRT( ONE+( Z / W )**2 )
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLAPY2
|
|
*
|
|
END
|
|
SUBROUTINE DLARF( SIDE, M, N, V, INCV, TAU, C, LDC, WORK )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER SIDE
|
|
INTEGER INCV, LDC, M, N
|
|
DOUBLE PRECISION TAU
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION C( LDC, * ), V( * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLARF applies a real elementary reflector H to a real m by n matrix
|
|
* C, from either the left or the right. H is represented in the form
|
|
*
|
|
* H = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar and v is a real vector.
|
|
*
|
|
* If tau = 0, then H is taken to be the unit matrix.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* SIDE (input) CHARACTER*1
|
|
* = 'L': form H * C
|
|
* = 'R': form C * H
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix C.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix C.
|
|
*
|
|
* V (input) DOUBLE PRECISION array, dimension
|
|
* (1 + (M-1)*abs(INCV)) if SIDE = 'L'
|
|
* or (1 + (N-1)*abs(INCV)) if SIDE = 'R'
|
|
* The vector v in the representation of H. V is not used if
|
|
* TAU = 0.
|
|
*
|
|
* INCV (input) INTEGER
|
|
* The increment between elements of v. INCV <> 0.
|
|
*
|
|
* TAU (input) DOUBLE PRECISION
|
|
* The value tau in the representation of H.
|
|
*
|
|
* C (input/output) DOUBLE PRECISION array, dimension (LDC,N)
|
|
* On entry, the m by n matrix C.
|
|
* On exit, C is overwritten by the matrix H * C if SIDE = 'L',
|
|
* or C * H if SIDE = 'R'.
|
|
*
|
|
* LDC (input) INTEGER
|
|
* The leading dimension of the array C. LDC >= max(1,M).
|
|
*
|
|
* WORK (workspace) DOUBLE PRECISION array, dimension
|
|
* (N) if SIDE = 'L'
|
|
* or (M) if SIDE = 'R'
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DGEMV, DGER
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( LSAME( SIDE, 'L' ) ) THEN
|
|
*
|
|
* Form H * C
|
|
*
|
|
IF( TAU.NE.ZERO ) THEN
|
|
*
|
|
* w := C' * v
|
|
*
|
|
CALL DGEMV( 'Transpose', M, N, ONE, C, LDC, V, INCV, ZERO,
|
|
$ WORK, 1 )
|
|
*
|
|
* C := C - v * w'
|
|
*
|
|
CALL DGER( M, N, -TAU, V, INCV, WORK, 1, C, LDC )
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Form C * H
|
|
*
|
|
IF( TAU.NE.ZERO ) THEN
|
|
*
|
|
* w := C * v
|
|
*
|
|
CALL DGEMV( 'No transpose', M, N, ONE, C, LDC, V, INCV,
|
|
$ ZERO, WORK, 1 )
|
|
*
|
|
* C := C - w * v'
|
|
*
|
|
CALL DGER( M, N, -TAU, WORK, 1, V, INCV, C, LDC )
|
|
END IF
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLARF
|
|
*
|
|
END
|
|
SUBROUTINE DLARFB( SIDE, TRANS, DIRECT, STOREV, M, N, K, V, LDV,
|
|
$ T, LDT, C, LDC, WORK, LDWORK )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER DIRECT, SIDE, STOREV, TRANS
|
|
INTEGER K, LDC, LDT, LDV, LDWORK, M, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION C( LDC, * ), T( LDT, * ), V( LDV, * ),
|
|
$ WORK( LDWORK, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLARFB applies a real block reflector H or its transpose H' to a
|
|
* real m by n matrix C, from either the left or the right.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* SIDE (input) CHARACTER*1
|
|
* = 'L': apply H or H' from the Left
|
|
* = 'R': apply H or H' from the Right
|
|
*
|
|
* TRANS (input) CHARACTER*1
|
|
* = 'N': apply H (No transpose)
|
|
* = 'T': apply H' (Transpose)
|
|
*
|
|
* DIRECT (input) CHARACTER*1
|
|
* Indicates how H is formed from a product of elementary
|
|
* reflectors
|
|
* = 'F': H = H(1) H(2) . . . H(k) (Forward)
|
|
* = 'B': H = H(k) . . . H(2) H(1) (Backward)
|
|
*
|
|
* STOREV (input) CHARACTER*1
|
|
* Indicates how the vectors which define the elementary
|
|
* reflectors are stored:
|
|
* = 'C': Columnwise
|
|
* = 'R': Rowwise
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix C.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix C.
|
|
*
|
|
* K (input) INTEGER
|
|
* The order of the matrix T (= the number of elementary
|
|
* reflectors whose product defines the block reflector).
|
|
*
|
|
* V (input) DOUBLE PRECISION array, dimension
|
|
* (LDV,K) if STOREV = 'C'
|
|
* (LDV,M) if STOREV = 'R' and SIDE = 'L'
|
|
* (LDV,N) if STOREV = 'R' and SIDE = 'R'
|
|
* The matrix V. See further details.
|
|
*
|
|
* LDV (input) INTEGER
|
|
* The leading dimension of the array V.
|
|
* If STOREV = 'C' and SIDE = 'L', LDV >= max(1,M);
|
|
* if STOREV = 'C' and SIDE = 'R', LDV >= max(1,N);
|
|
* if STOREV = 'R', LDV >= K.
|
|
*
|
|
* T (input) DOUBLE PRECISION array, dimension (LDT,K)
|
|
* The triangular k by k matrix T in the representation of the
|
|
* block reflector.
|
|
*
|
|
* LDT (input) INTEGER
|
|
* The leading dimension of the array T. LDT >= K.
|
|
*
|
|
* C (input/output) DOUBLE PRECISION array, dimension (LDC,N)
|
|
* On entry, the m by n matrix C.
|
|
* On exit, C is overwritten by H*C or H'*C or C*H or C*H'.
|
|
*
|
|
* LDC (input) INTEGER
|
|
* The leading dimension of the array C. LDA >= max(1,M).
|
|
*
|
|
* WORK (workspace) DOUBLE PRECISION array, dimension (LDWORK,K)
|
|
*
|
|
* LDWORK (input) INTEGER
|
|
* The leading dimension of the array WORK.
|
|
* If SIDE = 'L', LDWORK >= max(1,N);
|
|
* if SIDE = 'R', LDWORK >= max(1,M).
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE
|
|
PARAMETER ( ONE = 1.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
CHARACTER TRANST
|
|
INTEGER I, J
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DCOPY, DGEMM, DTRMM
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( M.LE.0 .OR. N.LE.0 )
|
|
$ RETURN
|
|
*
|
|
IF( LSAME( TRANS, 'N' ) ) THEN
|
|
TRANST = 'T'
|
|
ELSE
|
|
TRANST = 'N'
|
|
END IF
|
|
*
|
|
IF( LSAME( STOREV, 'C' ) ) THEN
|
|
*
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
*
|
|
* Let V = ( V1 ) (first K rows)
|
|
* ( V2 )
|
|
* where V1 is unit lower triangular.
|
|
*
|
|
IF( LSAME( SIDE, 'L' ) ) THEN
|
|
*
|
|
* Form H * C or H' * C where C = ( C1 )
|
|
* ( C2 )
|
|
*
|
|
* W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK)
|
|
*
|
|
* W := C1'
|
|
*
|
|
DO 10 J = 1, K
|
|
CALL DCOPY( N, C( J, 1 ), LDC, WORK( 1, J ), 1 )
|
|
10 CONTINUE
|
|
*
|
|
* W := W * V1
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'No transpose', 'Unit', N,
|
|
$ K, ONE, V, LDV, WORK, LDWORK )
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* W := W + C2'*V2
|
|
*
|
|
CALL DGEMM( 'Transpose', 'No transpose', N, K, M-K,
|
|
$ ONE, C( K+1, 1 ), LDC, V( K+1, 1 ), LDV,
|
|
$ ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T' or W * T
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', TRANST, 'Non-unit', N, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - V * W'
|
|
*
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* C2 := C2 - V2 * W'
|
|
*
|
|
CALL DGEMM( 'No transpose', 'Transpose', M-K, N, K,
|
|
$ -ONE, V( K+1, 1 ), LDV, WORK, LDWORK, ONE,
|
|
$ C( K+1, 1 ), LDC )
|
|
END IF
|
|
*
|
|
* W := W * V1'
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'Transpose', 'Unit', N, K,
|
|
$ ONE, V, LDV, WORK, LDWORK )
|
|
*
|
|
* C1 := C1 - W'
|
|
*
|
|
DO 30 J = 1, K
|
|
DO 20 I = 1, N
|
|
C( J, I ) = C( J, I ) - WORK( I, J )
|
|
20 CONTINUE
|
|
30 CONTINUE
|
|
*
|
|
ELSE IF( LSAME( SIDE, 'R' ) ) THEN
|
|
*
|
|
* Form C * H or C * H' where C = ( C1 C2 )
|
|
*
|
|
* W := C * V = (C1*V1 + C2*V2) (stored in WORK)
|
|
*
|
|
* W := C1
|
|
*
|
|
DO 40 J = 1, K
|
|
CALL DCOPY( M, C( 1, J ), 1, WORK( 1, J ), 1 )
|
|
40 CONTINUE
|
|
*
|
|
* W := W * V1
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'No transpose', 'Unit', M,
|
|
$ K, ONE, V, LDV, WORK, LDWORK )
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* W := W + C2 * V2
|
|
*
|
|
CALL DGEMM( 'No transpose', 'No transpose', M, K, N-K,
|
|
$ ONE, C( 1, K+1 ), LDC, V( K+1, 1 ), LDV,
|
|
$ ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T or W * T'
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', TRANS, 'Non-unit', M, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - W * V'
|
|
*
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* C2 := C2 - W * V2'
|
|
*
|
|
CALL DGEMM( 'No transpose', 'Transpose', M, N-K, K,
|
|
$ -ONE, WORK, LDWORK, V( K+1, 1 ), LDV, ONE,
|
|
$ C( 1, K+1 ), LDC )
|
|
END IF
|
|
*
|
|
* W := W * V1'
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'Transpose', 'Unit', M, K,
|
|
$ ONE, V, LDV, WORK, LDWORK )
|
|
*
|
|
* C1 := C1 - W
|
|
*
|
|
DO 60 J = 1, K
|
|
DO 50 I = 1, M
|
|
C( I, J ) = C( I, J ) - WORK( I, J )
|
|
50 CONTINUE
|
|
60 CONTINUE
|
|
END IF
|
|
*
|
|
ELSE
|
|
*
|
|
* Let V = ( V1 )
|
|
* ( V2 ) (last K rows)
|
|
* where V2 is unit upper triangular.
|
|
*
|
|
IF( LSAME( SIDE, 'L' ) ) THEN
|
|
*
|
|
* Form H * C or H' * C where C = ( C1 )
|
|
* ( C2 )
|
|
*
|
|
* W := C' * V = (C1'*V1 + C2'*V2) (stored in WORK)
|
|
*
|
|
* W := C2'
|
|
*
|
|
DO 70 J = 1, K
|
|
CALL DCOPY( N, C( M-K+J, 1 ), LDC, WORK( 1, J ), 1 )
|
|
70 CONTINUE
|
|
*
|
|
* W := W * V2
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'No transpose', 'Unit', N,
|
|
$ K, ONE, V( M-K+1, 1 ), LDV, WORK, LDWORK )
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* W := W + C1'*V1
|
|
*
|
|
CALL DGEMM( 'Transpose', 'No transpose', N, K, M-K,
|
|
$ ONE, C, LDC, V, LDV, ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T' or W * T
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', TRANST, 'Non-unit', N, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - V * W'
|
|
*
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* C1 := C1 - V1 * W'
|
|
*
|
|
CALL DGEMM( 'No transpose', 'Transpose', M-K, N, K,
|
|
$ -ONE, V, LDV, WORK, LDWORK, ONE, C, LDC )
|
|
END IF
|
|
*
|
|
* W := W * V2'
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Unit', N, K,
|
|
$ ONE, V( M-K+1, 1 ), LDV, WORK, LDWORK )
|
|
*
|
|
* C2 := C2 - W'
|
|
*
|
|
DO 90 J = 1, K
|
|
DO 80 I = 1, N
|
|
C( M-K+J, I ) = C( M-K+J, I ) - WORK( I, J )
|
|
80 CONTINUE
|
|
90 CONTINUE
|
|
*
|
|
ELSE IF( LSAME( SIDE, 'R' ) ) THEN
|
|
*
|
|
* Form C * H or C * H' where C = ( C1 C2 )
|
|
*
|
|
* W := C * V = (C1*V1 + C2*V2) (stored in WORK)
|
|
*
|
|
* W := C2
|
|
*
|
|
DO 100 J = 1, K
|
|
CALL DCOPY( M, C( 1, N-K+J ), 1, WORK( 1, J ), 1 )
|
|
100 CONTINUE
|
|
*
|
|
* W := W * V2
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'No transpose', 'Unit', M,
|
|
$ K, ONE, V( N-K+1, 1 ), LDV, WORK, LDWORK )
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* W := W + C1 * V1
|
|
*
|
|
CALL DGEMM( 'No transpose', 'No transpose', M, K, N-K,
|
|
$ ONE, C, LDC, V, LDV, ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T or W * T'
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', TRANS, 'Non-unit', M, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - W * V'
|
|
*
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* C1 := C1 - W * V1'
|
|
*
|
|
CALL DGEMM( 'No transpose', 'Transpose', M, N-K, K,
|
|
$ -ONE, WORK, LDWORK, V, LDV, ONE, C, LDC )
|
|
END IF
|
|
*
|
|
* W := W * V2'
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Unit', M, K,
|
|
$ ONE, V( N-K+1, 1 ), LDV, WORK, LDWORK )
|
|
*
|
|
* C2 := C2 - W
|
|
*
|
|
DO 120 J = 1, K
|
|
DO 110 I = 1, M
|
|
C( I, N-K+J ) = C( I, N-K+J ) - WORK( I, J )
|
|
110 CONTINUE
|
|
120 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
ELSE IF( LSAME( STOREV, 'R' ) ) THEN
|
|
*
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
*
|
|
* Let V = ( V1 V2 ) (V1: first K columns)
|
|
* where V1 is unit upper triangular.
|
|
*
|
|
IF( LSAME( SIDE, 'L' ) ) THEN
|
|
*
|
|
* Form H * C or H' * C where C = ( C1 )
|
|
* ( C2 )
|
|
*
|
|
* W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK)
|
|
*
|
|
* W := C1'
|
|
*
|
|
DO 130 J = 1, K
|
|
CALL DCOPY( N, C( J, 1 ), LDC, WORK( 1, J ), 1 )
|
|
130 CONTINUE
|
|
*
|
|
* W := W * V1'
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Unit', N, K,
|
|
$ ONE, V, LDV, WORK, LDWORK )
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* W := W + C2'*V2'
|
|
*
|
|
CALL DGEMM( 'Transpose', 'Transpose', N, K, M-K, ONE,
|
|
$ C( K+1, 1 ), LDC, V( 1, K+1 ), LDV, ONE,
|
|
$ WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T' or W * T
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', TRANST, 'Non-unit', N, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - V' * W'
|
|
*
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* C2 := C2 - V2' * W'
|
|
*
|
|
CALL DGEMM( 'Transpose', 'Transpose', M-K, N, K, -ONE,
|
|
$ V( 1, K+1 ), LDV, WORK, LDWORK, ONE,
|
|
$ C( K+1, 1 ), LDC )
|
|
END IF
|
|
*
|
|
* W := W * V1
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'No transpose', 'Unit', N,
|
|
$ K, ONE, V, LDV, WORK, LDWORK )
|
|
*
|
|
* C1 := C1 - W'
|
|
*
|
|
DO 150 J = 1, K
|
|
DO 140 I = 1, N
|
|
C( J, I ) = C( J, I ) - WORK( I, J )
|
|
140 CONTINUE
|
|
150 CONTINUE
|
|
*
|
|
ELSE IF( LSAME( SIDE, 'R' ) ) THEN
|
|
*
|
|
* Form C * H or C * H' where C = ( C1 C2 )
|
|
*
|
|
* W := C * V' = (C1*V1' + C2*V2') (stored in WORK)
|
|
*
|
|
* W := C1
|
|
*
|
|
DO 160 J = 1, K
|
|
CALL DCOPY( M, C( 1, J ), 1, WORK( 1, J ), 1 )
|
|
160 CONTINUE
|
|
*
|
|
* W := W * V1'
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Unit', M, K,
|
|
$ ONE, V, LDV, WORK, LDWORK )
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* W := W + C2 * V2'
|
|
*
|
|
CALL DGEMM( 'No transpose', 'Transpose', M, K, N-K,
|
|
$ ONE, C( 1, K+1 ), LDC, V( 1, K+1 ), LDV,
|
|
$ ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T or W * T'
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', TRANS, 'Non-unit', M, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - W * V
|
|
*
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* C2 := C2 - W * V2
|
|
*
|
|
CALL DGEMM( 'No transpose', 'No transpose', M, N-K, K,
|
|
$ -ONE, WORK, LDWORK, V( 1, K+1 ), LDV, ONE,
|
|
$ C( 1, K+1 ), LDC )
|
|
END IF
|
|
*
|
|
* W := W * V1
|
|
*
|
|
CALL DTRMM( 'Right', 'Upper', 'No transpose', 'Unit', M,
|
|
$ K, ONE, V, LDV, WORK, LDWORK )
|
|
*
|
|
* C1 := C1 - W
|
|
*
|
|
DO 180 J = 1, K
|
|
DO 170 I = 1, M
|
|
C( I, J ) = C( I, J ) - WORK( I, J )
|
|
170 CONTINUE
|
|
180 CONTINUE
|
|
*
|
|
END IF
|
|
*
|
|
ELSE
|
|
*
|
|
* Let V = ( V1 V2 ) (V2: last K columns)
|
|
* where V2 is unit lower triangular.
|
|
*
|
|
IF( LSAME( SIDE, 'L' ) ) THEN
|
|
*
|
|
* Form H * C or H' * C where C = ( C1 )
|
|
* ( C2 )
|
|
*
|
|
* W := C' * V' = (C1'*V1' + C2'*V2') (stored in WORK)
|
|
*
|
|
* W := C2'
|
|
*
|
|
DO 190 J = 1, K
|
|
CALL DCOPY( N, C( M-K+J, 1 ), LDC, WORK( 1, J ), 1 )
|
|
190 CONTINUE
|
|
*
|
|
* W := W * V2'
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'Transpose', 'Unit', N, K,
|
|
$ ONE, V( 1, M-K+1 ), LDV, WORK, LDWORK )
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* W := W + C1'*V1'
|
|
*
|
|
CALL DGEMM( 'Transpose', 'Transpose', N, K, M-K, ONE,
|
|
$ C, LDC, V, LDV, ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T' or W * T
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', TRANST, 'Non-unit', N, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - V' * W'
|
|
*
|
|
IF( M.GT.K ) THEN
|
|
*
|
|
* C1 := C1 - V1' * W'
|
|
*
|
|
CALL DGEMM( 'Transpose', 'Transpose', M-K, N, K, -ONE,
|
|
$ V, LDV, WORK, LDWORK, ONE, C, LDC )
|
|
END IF
|
|
*
|
|
* W := W * V2
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'No transpose', 'Unit', N,
|
|
$ K, ONE, V( 1, M-K+1 ), LDV, WORK, LDWORK )
|
|
*
|
|
* C2 := C2 - W'
|
|
*
|
|
DO 210 J = 1, K
|
|
DO 200 I = 1, N
|
|
C( M-K+J, I ) = C( M-K+J, I ) - WORK( I, J )
|
|
200 CONTINUE
|
|
210 CONTINUE
|
|
*
|
|
ELSE IF( LSAME( SIDE, 'R' ) ) THEN
|
|
*
|
|
* Form C * H or C * H' where C = ( C1 C2 )
|
|
*
|
|
* W := C * V' = (C1*V1' + C2*V2') (stored in WORK)
|
|
*
|
|
* W := C2
|
|
*
|
|
DO 220 J = 1, K
|
|
CALL DCOPY( M, C( 1, N-K+J ), 1, WORK( 1, J ), 1 )
|
|
220 CONTINUE
|
|
*
|
|
* W := W * V2'
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'Transpose', 'Unit', M, K,
|
|
$ ONE, V( 1, N-K+1 ), LDV, WORK, LDWORK )
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* W := W + C1 * V1'
|
|
*
|
|
CALL DGEMM( 'No transpose', 'Transpose', M, K, N-K,
|
|
$ ONE, C, LDC, V, LDV, ONE, WORK, LDWORK )
|
|
END IF
|
|
*
|
|
* W := W * T or W * T'
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', TRANS, 'Non-unit', M, K,
|
|
$ ONE, T, LDT, WORK, LDWORK )
|
|
*
|
|
* C := C - W * V
|
|
*
|
|
IF( N.GT.K ) THEN
|
|
*
|
|
* C1 := C1 - W * V1
|
|
*
|
|
CALL DGEMM( 'No transpose', 'No transpose', M, N-K, K,
|
|
$ -ONE, WORK, LDWORK, V, LDV, ONE, C, LDC )
|
|
END IF
|
|
*
|
|
* W := W * V2
|
|
*
|
|
CALL DTRMM( 'Right', 'Lower', 'No transpose', 'Unit', M,
|
|
$ K, ONE, V( 1, N-K+1 ), LDV, WORK, LDWORK )
|
|
*
|
|
* C1 := C1 - W
|
|
*
|
|
DO 240 J = 1, K
|
|
DO 230 I = 1, M
|
|
C( I, N-K+J ) = C( I, N-K+J ) - WORK( I, J )
|
|
230 CONTINUE
|
|
240 CONTINUE
|
|
*
|
|
END IF
|
|
*
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLARFB
|
|
*
|
|
END
|
|
SUBROUTINE DLARFG( N, ALPHA, X, INCX, TAU )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INCX, N
|
|
DOUBLE PRECISION ALPHA, TAU
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION X( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLARFG generates a real elementary reflector H of order n, such
|
|
* that
|
|
*
|
|
* H * ( alpha ) = ( beta ), H' * H = I.
|
|
* ( x ) ( 0 )
|
|
*
|
|
* where alpha and beta are scalars, and x is an (n-1)-element real
|
|
* vector. H is represented in the form
|
|
*
|
|
* H = I - tau * ( 1 ) * ( 1 v' ) ,
|
|
* ( v )
|
|
*
|
|
* where tau is a real scalar and v is a real (n-1)-element
|
|
* vector.
|
|
*
|
|
* If the elements of x are all zero, then tau = 0 and H is taken to be
|
|
* the unit matrix.
|
|
*
|
|
* Otherwise 1 <= tau <= 2.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the elementary reflector.
|
|
*
|
|
* ALPHA (input/output) DOUBLE PRECISION
|
|
* On entry, the value alpha.
|
|
* On exit, it is overwritten with the value beta.
|
|
*
|
|
* X (input/output) DOUBLE PRECISION array, dimension
|
|
* (1+(N-2)*abs(INCX))
|
|
* On entry, the vector x.
|
|
* On exit, it is overwritten with the vector v.
|
|
*
|
|
* INCX (input) INTEGER
|
|
* The increment between elements of X. INCX > 0.
|
|
*
|
|
* TAU (output) DOUBLE PRECISION
|
|
* The value tau.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER J, KNT
|
|
DOUBLE PRECISION BETA, RSAFMN, SAFMIN, XNORM
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMCH, DLAPY2, DNRM2
|
|
EXTERNAL DLAMCH, DLAPY2, DNRM2
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, SIGN
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DSCAL
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( N.LE.1 ) THEN
|
|
TAU = ZERO
|
|
RETURN
|
|
END IF
|
|
*
|
|
XNORM = DNRM2( N-1, X, INCX )
|
|
*
|
|
IF( XNORM.EQ.ZERO ) THEN
|
|
*
|
|
* H = I
|
|
*
|
|
TAU = ZERO
|
|
ELSE
|
|
*
|
|
* general case
|
|
*
|
|
BETA = -SIGN( DLAPY2( ALPHA, XNORM ), ALPHA )
|
|
SAFMIN = DLAMCH( 'S' ) / DLAMCH( 'E' )
|
|
IF( ABS( BETA ).LT.SAFMIN ) THEN
|
|
*
|
|
* XNORM, BETA may be inaccurate; scale X and recompute them
|
|
*
|
|
RSAFMN = ONE / SAFMIN
|
|
KNT = 0
|
|
10 CONTINUE
|
|
KNT = KNT + 1
|
|
CALL DSCAL( N-1, RSAFMN, X, INCX )
|
|
BETA = BETA*RSAFMN
|
|
ALPHA = ALPHA*RSAFMN
|
|
IF( ABS( BETA ).LT.SAFMIN )
|
|
$ GO TO 10
|
|
*
|
|
* New BETA is at most 1, at least SAFMIN
|
|
*
|
|
XNORM = DNRM2( N-1, X, INCX )
|
|
BETA = -SIGN( DLAPY2( ALPHA, XNORM ), ALPHA )
|
|
TAU = ( BETA-ALPHA ) / BETA
|
|
CALL DSCAL( N-1, ONE / ( ALPHA-BETA ), X, INCX )
|
|
*
|
|
* If ALPHA is subnormal, it may lose relative accuracy
|
|
*
|
|
ALPHA = BETA
|
|
DO 20 J = 1, KNT
|
|
ALPHA = ALPHA*SAFMIN
|
|
20 CONTINUE
|
|
ELSE
|
|
TAU = ( BETA-ALPHA ) / BETA
|
|
CALL DSCAL( N-1, ONE / ( ALPHA-BETA ), X, INCX )
|
|
ALPHA = BETA
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLARFG
|
|
*
|
|
END
|
|
SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER DIRECT, STOREV
|
|
INTEGER K, LDT, LDV, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION T( LDT, * ), TAU( * ), V( LDV, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLARFT forms the triangular factor T of a real block reflector H
|
|
* of order n, which is defined as a product of k elementary reflectors.
|
|
*
|
|
* If DIRECT = 'F', H = H(1) H(2) . . . H(k) and T is upper triangular;
|
|
*
|
|
* If DIRECT = 'B', H = H(k) . . . H(2) H(1) and T is lower triangular.
|
|
*
|
|
* If STOREV = 'C', the vector which defines the elementary reflector
|
|
* H(i) is stored in the i-th column of the array V, and
|
|
*
|
|
* H = I - V * T * V'
|
|
*
|
|
* If STOREV = 'R', the vector which defines the elementary reflector
|
|
* H(i) is stored in the i-th row of the array V, and
|
|
*
|
|
* H = I - V' * T * V
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* DIRECT (input) CHARACTER*1
|
|
* Specifies the order in which the elementary reflectors are
|
|
* multiplied to form the block reflector:
|
|
* = 'F': H = H(1) H(2) . . . H(k) (Forward)
|
|
* = 'B': H = H(k) . . . H(2) H(1) (Backward)
|
|
*
|
|
* STOREV (input) CHARACTER*1
|
|
* Specifies how the vectors which define the elementary
|
|
* reflectors are stored (see also Further Details):
|
|
* = 'C': columnwise
|
|
* = 'R': rowwise
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the block reflector H. N >= 0.
|
|
*
|
|
* K (input) INTEGER
|
|
* The order of the triangular factor T (= the number of
|
|
* elementary reflectors). K >= 1.
|
|
*
|
|
* V (input/output) DOUBLE PRECISION array, dimension
|
|
* (LDV,K) if STOREV = 'C'
|
|
* (LDV,N) if STOREV = 'R'
|
|
* The matrix V. See further details.
|
|
*
|
|
* LDV (input) INTEGER
|
|
* The leading dimension of the array V.
|
|
* If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K.
|
|
*
|
|
* TAU (input) DOUBLE PRECISION array, dimension (K)
|
|
* TAU(i) must contain the scalar factor of the elementary
|
|
* reflector H(i).
|
|
*
|
|
* T (output) DOUBLE PRECISION array, dimension (LDT,K)
|
|
* The k by k triangular factor T of the block reflector.
|
|
* If DIRECT = 'F', T is upper triangular; if DIRECT = 'B', T is
|
|
* lower triangular. The rest of the array is not used.
|
|
*
|
|
* LDT (input) INTEGER
|
|
* The leading dimension of the array T. LDT >= K.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* The shape of the matrix V and the storage of the vectors which define
|
|
* the H(i) is best illustrated by the following example with n = 5 and
|
|
* k = 3. The elements equal to 1 are not stored; the corresponding
|
|
* array elements are modified but restored on exit. The rest of the
|
|
* array is not used.
|
|
*
|
|
* DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R':
|
|
*
|
|
* V = ( 1 ) V = ( 1 v1 v1 v1 v1 )
|
|
* ( v1 1 ) ( 1 v2 v2 v2 )
|
|
* ( v1 v2 1 ) ( 1 v3 v3 )
|
|
* ( v1 v2 v3 )
|
|
* ( v1 v2 v3 )
|
|
*
|
|
* DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R':
|
|
*
|
|
* V = ( v1 v2 v3 ) V = ( v1 v1 1 )
|
|
* ( v1 v2 v3 ) ( v2 v2 v2 1 )
|
|
* ( 1 v2 v3 ) ( v3 v3 v3 v3 1 )
|
|
* ( 1 v3 )
|
|
* ( 1 )
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, J
|
|
DOUBLE PRECISION VII
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DGEMV, DTRMV
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.EQ.0 )
|
|
$ RETURN
|
|
*
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 20 I = 1, K
|
|
IF( TAU( I ).EQ.ZERO ) THEN
|
|
*
|
|
* H(i) = I
|
|
*
|
|
DO 10 J = 1, I
|
|
T( J, I ) = ZERO
|
|
10 CONTINUE
|
|
ELSE
|
|
*
|
|
* general case
|
|
*
|
|
VII = V( I, I )
|
|
V( I, I ) = ONE
|
|
IF( LSAME( STOREV, 'C' ) ) THEN
|
|
*
|
|
* T(1:i-1,i) := - tau(i) * V(i:n,1:i-1)' * V(i:n,i)
|
|
*
|
|
CALL DGEMV( 'Transpose', N-I+1, I-1, -TAU( I ),
|
|
$ V( I, 1 ), LDV, V( I, I ), 1, ZERO,
|
|
$ T( 1, I ), 1 )
|
|
ELSE
|
|
*
|
|
* T(1:i-1,i) := - tau(i) * V(1:i-1,i:n) * V(i,i:n)'
|
|
*
|
|
CALL DGEMV( 'No transpose', I-1, N-I+1, -TAU( I ),
|
|
$ V( 1, I ), LDV, V( I, I ), LDV, ZERO,
|
|
$ T( 1, I ), 1 )
|
|
END IF
|
|
V( I, I ) = VII
|
|
*
|
|
* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i)
|
|
*
|
|
CALL DTRMV( 'Upper', 'No transpose', 'Non-unit', I-1, T,
|
|
$ LDT, T( 1, I ), 1 )
|
|
T( I, I ) = TAU( I )
|
|
END IF
|
|
20 CONTINUE
|
|
ELSE
|
|
DO 40 I = K, 1, -1
|
|
IF( TAU( I ).EQ.ZERO ) THEN
|
|
*
|
|
* H(i) = I
|
|
*
|
|
DO 30 J = I, K
|
|
T( J, I ) = ZERO
|
|
30 CONTINUE
|
|
ELSE
|
|
*
|
|
* general case
|
|
*
|
|
IF( I.LT.K ) THEN
|
|
IF( LSAME( STOREV, 'C' ) ) THEN
|
|
VII = V( N-K+I, I )
|
|
V( N-K+I, I ) = ONE
|
|
*
|
|
* T(i+1:k,i) :=
|
|
* - tau(i) * V(1:n-k+i,i+1:k)' * V(1:n-k+i,i)
|
|
*
|
|
CALL DGEMV( 'Transpose', N-K+I, K-I, -TAU( I ),
|
|
$ V( 1, I+1 ), LDV, V( 1, I ), 1, ZERO,
|
|
$ T( I+1, I ), 1 )
|
|
V( N-K+I, I ) = VII
|
|
ELSE
|
|
VII = V( I, N-K+I )
|
|
V( I, N-K+I ) = ONE
|
|
*
|
|
* T(i+1:k,i) :=
|
|
* - tau(i) * V(i+1:k,1:n-k+i) * V(i,1:n-k+i)'
|
|
*
|
|
CALL DGEMV( 'No transpose', K-I, N-K+I, -TAU( I ),
|
|
$ V( I+1, 1 ), LDV, V( I, 1 ), LDV, ZERO,
|
|
$ T( I+1, I ), 1 )
|
|
V( I, N-K+I ) = VII
|
|
END IF
|
|
*
|
|
* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i)
|
|
*
|
|
CALL DTRMV( 'Lower', 'No transpose', 'Non-unit', K-I,
|
|
$ T( I+1, I+1 ), LDT, T( I+1, I ), 1 )
|
|
END IF
|
|
T( I, I ) = TAU( I )
|
|
END IF
|
|
40 CONTINUE
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLARFT
|
|
*
|
|
END
|
|
SUBROUTINE DLARTG( F, G, CS, SN, R )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
DOUBLE PRECISION CS, F, G, R, SN
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLARTG generate a plane rotation so that
|
|
*
|
|
* [ CS SN ] . [ F ] = [ R ] where CS**2 + SN**2 = 1.
|
|
* [ -SN CS ] [ G ] [ 0 ]
|
|
*
|
|
* This is a slower, more accurate version of the BLAS1 routine DROTG,
|
|
* with the following other differences:
|
|
* F and G are unchanged on return.
|
|
* If G=0, then CS=1 and SN=0.
|
|
* If F=0 and (G .ne. 0), then CS=0 and SN=1 without doing any
|
|
* floating point operations (saves work in DBDSQR when
|
|
* there are zeros on the diagonal).
|
|
*
|
|
* If F exceeds G in magnitude, CS will be positive.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* F (input) DOUBLE PRECISION
|
|
* The first component of vector to be rotated.
|
|
*
|
|
* G (input) DOUBLE PRECISION
|
|
* The second component of vector to be rotated.
|
|
*
|
|
* CS (output) DOUBLE PRECISION
|
|
* The cosine of the rotation.
|
|
*
|
|
* SN (output) DOUBLE PRECISION
|
|
* The sine of the rotation.
|
|
*
|
|
* R (output) DOUBLE PRECISION
|
|
* The nonzero component of the rotated vector.
|
|
*
|
|
* This version has a few statements commented out for thread safety
|
|
* (machine parameters are computed on each entry). 10 feb 03, SJH.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D0 )
|
|
DOUBLE PRECISION ONE
|
|
PARAMETER ( ONE = 1.0D0 )
|
|
DOUBLE PRECISION TWO
|
|
PARAMETER ( TWO = 2.0D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
* LOGICAL FIRST
|
|
INTEGER COUNT, I
|
|
DOUBLE PRECISION EPS, F1, G1, SAFMIN, SAFMN2, SAFMX2, SCALE
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMCH
|
|
EXTERNAL DLAMCH
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, INT, LOG, MAX, SQRT
|
|
* ..
|
|
* .. Save statement ..
|
|
* SAVE FIRST, SAFMX2, SAFMIN, SAFMN2
|
|
* ..
|
|
* .. Data statements ..
|
|
* DATA FIRST / .TRUE. /
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* IF( FIRST ) THEN
|
|
SAFMIN = DLAMCH( 'S' )
|
|
EPS = DLAMCH( 'E' )
|
|
SAFMN2 = DLAMCH( 'B' )**INT( LOG( SAFMIN / EPS ) /
|
|
$ LOG( DLAMCH( 'B' ) ) / TWO )
|
|
SAFMX2 = ONE / SAFMN2
|
|
* FIRST = .FALSE.
|
|
* END IF
|
|
IF( G.EQ.ZERO ) THEN
|
|
CS = ONE
|
|
SN = ZERO
|
|
R = F
|
|
ELSE IF( F.EQ.ZERO ) THEN
|
|
CS = ZERO
|
|
SN = ONE
|
|
R = G
|
|
ELSE
|
|
F1 = F
|
|
G1 = G
|
|
SCALE = MAX( ABS( F1 ), ABS( G1 ) )
|
|
IF( SCALE.GE.SAFMX2 ) THEN
|
|
COUNT = 0
|
|
10 CONTINUE
|
|
COUNT = COUNT + 1
|
|
F1 = F1*SAFMN2
|
|
G1 = G1*SAFMN2
|
|
SCALE = MAX( ABS( F1 ), ABS( G1 ) )
|
|
IF( SCALE.GE.SAFMX2 )
|
|
$ GO TO 10
|
|
R = SQRT( F1**2+G1**2 )
|
|
CS = F1 / R
|
|
SN = G1 / R
|
|
DO 20 I = 1, COUNT
|
|
R = R*SAFMX2
|
|
20 CONTINUE
|
|
ELSE IF( SCALE.LE.SAFMN2 ) THEN
|
|
COUNT = 0
|
|
30 CONTINUE
|
|
COUNT = COUNT + 1
|
|
F1 = F1*SAFMX2
|
|
G1 = G1*SAFMX2
|
|
SCALE = MAX( ABS( F1 ), ABS( G1 ) )
|
|
IF( SCALE.LE.SAFMN2 )
|
|
$ GO TO 30
|
|
R = SQRT( F1**2+G1**2 )
|
|
CS = F1 / R
|
|
SN = G1 / R
|
|
DO 40 I = 1, COUNT
|
|
R = R*SAFMN2
|
|
40 CONTINUE
|
|
ELSE
|
|
R = SQRT( F1**2+G1**2 )
|
|
CS = F1 / R
|
|
SN = G1 / R
|
|
END IF
|
|
IF( ABS( F ).GT.ABS( G ) .AND. CS.LT.ZERO ) THEN
|
|
CS = -CS
|
|
SN = -SN
|
|
R = -R
|
|
END IF
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLARTG
|
|
*
|
|
END
|
|
SUBROUTINE DLASCL( TYPE, KL, KU, CFROM, CTO, M, N, A, LDA, INFO )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER TYPE
|
|
INTEGER INFO, KL, KU, LDA, M, N
|
|
DOUBLE PRECISION CFROM, CTO
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLASCL multiplies the M by N real matrix A by the real scalar
|
|
* CTO/CFROM. This is done without over/underflow as long as the final
|
|
* result CTO*A(I,J)/CFROM does not over/underflow. TYPE specifies that
|
|
* A may be full, upper triangular, lower triangular, upper Hessenberg,
|
|
* or banded.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* TYPE (input) CHARACTER*1
|
|
* TYPE indices the storage type of the input matrix.
|
|
* = 'G': A is a full matrix.
|
|
* = 'L': A is a lower triangular matrix.
|
|
* = 'U': A is an upper triangular matrix.
|
|
* = 'H': A is an upper Hessenberg matrix.
|
|
* = 'B': A is a symmetric band matrix with lower bandwidth KL
|
|
* and upper bandwidth KU and with the only the lower
|
|
* half stored.
|
|
* = 'Q': A is a symmetric band matrix with lower bandwidth KL
|
|
* and upper bandwidth KU and with the only the upper
|
|
* half stored.
|
|
* = 'Z': A is a band matrix with lower bandwidth KL and upper
|
|
* bandwidth KU.
|
|
*
|
|
* KL (input) INTEGER
|
|
* The lower bandwidth of A. Referenced only if TYPE = 'B',
|
|
* 'Q' or 'Z'.
|
|
*
|
|
* KU (input) INTEGER
|
|
* The upper bandwidth of A. Referenced only if TYPE = 'B',
|
|
* 'Q' or 'Z'.
|
|
*
|
|
* CFROM (input) DOUBLE PRECISION
|
|
* CTO (input) DOUBLE PRECISION
|
|
* The matrix A is multiplied by CTO/CFROM. A(I,J) is computed
|
|
* without over/underflow if the final result CTO*A(I,J)/CFROM
|
|
* can be represented without over/underflow. CFROM must be
|
|
* nonzero.
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix A. M >= 0.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix A. N >= 0.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* The matrix to be multiplied by CTO/CFROM. See TYPE for the
|
|
* storage type.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* INFO (output) INTEGER
|
|
* 0 - successful exit
|
|
* <0 - if INFO = -i, the i-th argument had an illegal value.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, ONE
|
|
PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL DONE
|
|
INTEGER I, ITYPE, J, K1, K2, K3, K4
|
|
DOUBLE PRECISION BIGNUM, CFROM1, CFROMC, CTO1, CTOC, MUL, SMLNUM
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
DOUBLE PRECISION DLAMCH
|
|
EXTERNAL LSAME, DLAMCH
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, MAX, MIN
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
*
|
|
IF( LSAME( TYPE, 'G' ) ) THEN
|
|
ITYPE = 0
|
|
ELSE IF( LSAME( TYPE, 'L' ) ) THEN
|
|
ITYPE = 1
|
|
ELSE IF( LSAME( TYPE, 'U' ) ) THEN
|
|
ITYPE = 2
|
|
ELSE IF( LSAME( TYPE, 'H' ) ) THEN
|
|
ITYPE = 3
|
|
ELSE IF( LSAME( TYPE, 'B' ) ) THEN
|
|
ITYPE = 4
|
|
ELSE IF( LSAME( TYPE, 'Q' ) ) THEN
|
|
ITYPE = 5
|
|
ELSE IF( LSAME( TYPE, 'Z' ) ) THEN
|
|
ITYPE = 6
|
|
ELSE
|
|
ITYPE = -1
|
|
END IF
|
|
*
|
|
IF( ITYPE.EQ.-1 ) THEN
|
|
INFO = -1
|
|
ELSE IF( CFROM.EQ.ZERO ) THEN
|
|
INFO = -4
|
|
ELSE IF( M.LT.0 ) THEN
|
|
INFO = -6
|
|
ELSE IF( N.LT.0 .OR. ( ITYPE.EQ.4 .AND. N.NE.M ) .OR.
|
|
$ ( ITYPE.EQ.5 .AND. N.NE.M ) ) THEN
|
|
INFO = -7
|
|
ELSE IF( ITYPE.LE.3 .AND. LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = -9
|
|
ELSE IF( ITYPE.GE.4 ) THEN
|
|
IF( KL.LT.0 .OR. KL.GT.MAX( M-1, 0 ) ) THEN
|
|
INFO = -2
|
|
ELSE IF( KU.LT.0 .OR. KU.GT.MAX( N-1, 0 ) .OR.
|
|
$ ( ( ITYPE.EQ.4 .OR. ITYPE.EQ.5 ) .AND. KL.NE.KU ) )
|
|
$ THEN
|
|
INFO = -3
|
|
ELSE IF( ( ITYPE.EQ.4 .AND. LDA.LT.KL+1 ) .OR.
|
|
$ ( ITYPE.EQ.5 .AND. LDA.LT.KU+1 ) .OR.
|
|
$ ( ITYPE.EQ.6 .AND. LDA.LT.2*KL+KU+1 ) ) THEN
|
|
INFO = -9
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DLASCL', -INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.EQ.0 .OR. M.EQ.0 )
|
|
$ RETURN
|
|
*
|
|
* Get machine parameters
|
|
*
|
|
SMLNUM = DLAMCH( 'S' )
|
|
BIGNUM = ONE / SMLNUM
|
|
*
|
|
CFROMC = CFROM
|
|
CTOC = CTO
|
|
*
|
|
10 CONTINUE
|
|
CFROM1 = CFROMC*SMLNUM
|
|
CTO1 = CTOC / BIGNUM
|
|
IF( ABS( CFROM1 ).GT.ABS( CTOC ) .AND. CTOC.NE.ZERO ) THEN
|
|
MUL = SMLNUM
|
|
DONE = .FALSE.
|
|
CFROMC = CFROM1
|
|
ELSE IF( ABS( CTO1 ).GT.ABS( CFROMC ) ) THEN
|
|
MUL = BIGNUM
|
|
DONE = .FALSE.
|
|
CTOC = CTO1
|
|
ELSE
|
|
MUL = CTOC / CFROMC
|
|
DONE = .TRUE.
|
|
END IF
|
|
*
|
|
IF( ITYPE.EQ.0 ) THEN
|
|
*
|
|
* Full matrix
|
|
*
|
|
DO 30 J = 1, N
|
|
DO 20 I = 1, M
|
|
A( I, J ) = A( I, J )*MUL
|
|
20 CONTINUE
|
|
30 CONTINUE
|
|
*
|
|
ELSE IF( ITYPE.EQ.1 ) THEN
|
|
*
|
|
* Lower triangular matrix
|
|
*
|
|
DO 50 J = 1, N
|
|
DO 40 I = J, M
|
|
A( I, J ) = A( I, J )*MUL
|
|
40 CONTINUE
|
|
50 CONTINUE
|
|
*
|
|
ELSE IF( ITYPE.EQ.2 ) THEN
|
|
*
|
|
* Upper triangular matrix
|
|
*
|
|
DO 70 J = 1, N
|
|
DO 60 I = 1, MIN( J, M )
|
|
A( I, J ) = A( I, J )*MUL
|
|
60 CONTINUE
|
|
70 CONTINUE
|
|
*
|
|
ELSE IF( ITYPE.EQ.3 ) THEN
|
|
*
|
|
* Upper Hessenberg matrix
|
|
*
|
|
DO 90 J = 1, N
|
|
DO 80 I = 1, MIN( J+1, M )
|
|
A( I, J ) = A( I, J )*MUL
|
|
80 CONTINUE
|
|
90 CONTINUE
|
|
*
|
|
ELSE IF( ITYPE.EQ.4 ) THEN
|
|
*
|
|
* Lower half of a symmetric band matrix
|
|
*
|
|
K3 = KL + 1
|
|
K4 = N + 1
|
|
DO 110 J = 1, N
|
|
DO 100 I = 1, MIN( K3, K4-J )
|
|
A( I, J ) = A( I, J )*MUL
|
|
100 CONTINUE
|
|
110 CONTINUE
|
|
*
|
|
ELSE IF( ITYPE.EQ.5 ) THEN
|
|
*
|
|
* Upper half of a symmetric band matrix
|
|
*
|
|
K1 = KU + 2
|
|
K3 = KU + 1
|
|
DO 130 J = 1, N
|
|
DO 120 I = MAX( K1-J, 1 ), K3
|
|
A( I, J ) = A( I, J )*MUL
|
|
120 CONTINUE
|
|
130 CONTINUE
|
|
*
|
|
ELSE IF( ITYPE.EQ.6 ) THEN
|
|
*
|
|
* Band matrix
|
|
*
|
|
K1 = KL + KU + 2
|
|
K2 = KL + 1
|
|
K3 = 2*KL + KU + 1
|
|
K4 = KL + KU + 1 + M
|
|
DO 150 J = 1, N
|
|
DO 140 I = MAX( K1-J, K2 ), MIN( K3, K4-J )
|
|
A( I, J ) = A( I, J )*MUL
|
|
140 CONTINUE
|
|
150 CONTINUE
|
|
*
|
|
END IF
|
|
*
|
|
IF( .NOT.DONE )
|
|
$ GO TO 10
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLASCL
|
|
*
|
|
END
|
|
SUBROUTINE DLASET( UPLO, M, N, ALPHA, BETA, A, LDA )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER UPLO
|
|
INTEGER LDA, M, N
|
|
DOUBLE PRECISION ALPHA, BETA
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLASET initializes an m-by-n matrix A to BETA on the diagonal and
|
|
* ALPHA on the offdiagonals.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* UPLO (input) CHARACTER*1
|
|
* Specifies the part of the matrix A to be set.
|
|
* = 'U': Upper triangular part is set; the strictly lower
|
|
* triangular part of A is not changed.
|
|
* = 'L': Lower triangular part is set; the strictly upper
|
|
* triangular part of A is not changed.
|
|
* Otherwise: All of the matrix A is set.
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix A. M >= 0.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix A. N >= 0.
|
|
*
|
|
* ALPHA (input) DOUBLE PRECISION
|
|
* The constant to which the offdiagonal elements are to be set.
|
|
*
|
|
* BETA (input) DOUBLE PRECISION
|
|
* The constant to which the diagonal elements are to be set.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* On exit, the leading m-by-n submatrix of A is set as follows:
|
|
*
|
|
* if UPLO = 'U', A(i,j) = ALPHA, 1<=i<=j-1, 1<=j<=n,
|
|
* if UPLO = 'L', A(i,j) = ALPHA, j+1<=i<=m, 1<=j<=n,
|
|
* otherwise, A(i,j) = ALPHA, 1<=i<=m, 1<=j<=n, i.ne.j,
|
|
*
|
|
* and, for all UPLO, A(i,i) = BETA, 1<=i<=min(m,n).
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Local Scalars ..
|
|
INTEGER I, J
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MIN
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( LSAME( UPLO, 'U' ) ) THEN
|
|
*
|
|
* Set the strictly upper triangular or trapezoidal part of the
|
|
* array to ALPHA.
|
|
*
|
|
DO 20 J = 2, N
|
|
DO 10 I = 1, MIN( J-1, M )
|
|
A( I, J ) = ALPHA
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
*
|
|
ELSE IF( LSAME( UPLO, 'L' ) ) THEN
|
|
*
|
|
* Set the strictly lower triangular or trapezoidal part of the
|
|
* array to ALPHA.
|
|
*
|
|
DO 40 J = 1, MIN( M, N )
|
|
DO 30 I = J + 1, M
|
|
A( I, J ) = ALPHA
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
*
|
|
ELSE
|
|
*
|
|
* Set the leading m-by-n submatrix to ALPHA.
|
|
*
|
|
DO 60 J = 1, N
|
|
DO 50 I = 1, M
|
|
A( I, J ) = ALPHA
|
|
50 CONTINUE
|
|
60 CONTINUE
|
|
END IF
|
|
*
|
|
* Set the first min(M,N) diagonal elements to BETA.
|
|
*
|
|
DO 70 I = 1, MIN( M, N )
|
|
A( I, I ) = BETA
|
|
70 CONTINUE
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLASET
|
|
*
|
|
END
|
|
SUBROUTINE DLASR( SIDE, PIVOT, DIRECT, M, N, C, S, A, LDA )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER DIRECT, PIVOT, SIDE
|
|
INTEGER LDA, M, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), C( * ), S( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLASR applies a sequence of plane rotations to a real matrix A,
|
|
* from either the left or the right.
|
|
*
|
|
* When SIDE = 'L', the transformation takes the form
|
|
*
|
|
* A := P*A
|
|
*
|
|
* and when SIDE = 'R', the transformation takes the form
|
|
*
|
|
* A := A*P**T
|
|
*
|
|
* where P is an orthogonal matrix consisting of a sequence of z plane
|
|
* rotations, with z = M when SIDE = 'L' and z = N when SIDE = 'R',
|
|
* and P**T is the transpose of P.
|
|
*
|
|
* When DIRECT = 'F' (Forward sequence), then
|
|
*
|
|
* P = P(z-1) * ... * P(2) * P(1)
|
|
*
|
|
* and when DIRECT = 'B' (Backward sequence), then
|
|
*
|
|
* P = P(1) * P(2) * ... * P(z-1)
|
|
*
|
|
* where P(k) is a plane rotation matrix defined by the 2-by-2 rotation
|
|
*
|
|
* R(k) = ( c(k) s(k) )
|
|
* = ( -s(k) c(k) ).
|
|
*
|
|
* When PIVOT = 'V' (Variable pivot), the rotation is performed
|
|
* for the plane (k,k+1), i.e., P(k) has the form
|
|
*
|
|
* P(k) = ( 1 )
|
|
* ( ... )
|
|
* ( 1 )
|
|
* ( c(k) s(k) )
|
|
* ( -s(k) c(k) )
|
|
* ( 1 )
|
|
* ( ... )
|
|
* ( 1 )
|
|
*
|
|
* where R(k) appears as a rank-2 modification to the identity matrix in
|
|
* rows and columns k and k+1.
|
|
*
|
|
* When PIVOT = 'T' (Top pivot), the rotation is performed for the
|
|
* plane (1,k+1), so P(k) has the form
|
|
*
|
|
* P(k) = ( c(k) s(k) )
|
|
* ( 1 )
|
|
* ( ... )
|
|
* ( 1 )
|
|
* ( -s(k) c(k) )
|
|
* ( 1 )
|
|
* ( ... )
|
|
* ( 1 )
|
|
*
|
|
* where R(k) appears in rows and columns 1 and k+1.
|
|
*
|
|
* Similarly, when PIVOT = 'B' (Bottom pivot), the rotation is
|
|
* performed for the plane (k,z), giving P(k) the form
|
|
*
|
|
* P(k) = ( 1 )
|
|
* ( ... )
|
|
* ( 1 )
|
|
* ( c(k) s(k) )
|
|
* ( 1 )
|
|
* ( ... )
|
|
* ( 1 )
|
|
* ( -s(k) c(k) )
|
|
*
|
|
* where R(k) appears in rows and columns k and z. The rotations are
|
|
* performed without ever forming P(k) explicitly.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* SIDE (input) CHARACTER*1
|
|
* Specifies whether the plane rotation matrix P is applied to
|
|
* A on the left or the right.
|
|
* = 'L': Left, compute A := P*A
|
|
* = 'R': Right, compute A:= A*P**T
|
|
*
|
|
* PIVOT (input) CHARACTER*1
|
|
* Specifies the plane for which P(k) is a plane rotation
|
|
* matrix.
|
|
* = 'V': Variable pivot, the plane (k,k+1)
|
|
* = 'T': Top pivot, the plane (1,k+1)
|
|
* = 'B': Bottom pivot, the plane (k,z)
|
|
*
|
|
* DIRECT (input) CHARACTER*1
|
|
* Specifies whether P is a forward or backward sequence of
|
|
* plane rotations.
|
|
* = 'F': Forward, P = P(z-1)*...*P(2)*P(1)
|
|
* = 'B': Backward, P = P(1)*P(2)*...*P(z-1)
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix A. If m <= 1, an immediate
|
|
* return is effected.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix A. If n <= 1, an
|
|
* immediate return is effected.
|
|
*
|
|
* C (input) DOUBLE PRECISION array, dimension
|
|
* (M-1) if SIDE = 'L'
|
|
* (N-1) if SIDE = 'R'
|
|
* The cosines c(k) of the plane rotations.
|
|
*
|
|
* S (input) DOUBLE PRECISION array, dimension
|
|
* (M-1) if SIDE = 'L'
|
|
* (N-1) if SIDE = 'R'
|
|
* The sines s(k) of the plane rotations. The 2-by-2 plane
|
|
* rotation part of the matrix P(k), R(k), has the form
|
|
* R(k) = ( c(k) s(k) )
|
|
* ( -s(k) c(k) ).
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* The M-by-N matrix A. On exit, A is overwritten by P*A if
|
|
* SIDE = 'R' or by A*P**T if SIDE = 'L'.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, INFO, J
|
|
DOUBLE PRECISION CTEMP, STEMP, TEMP
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters
|
|
*
|
|
INFO = 0
|
|
IF( .NOT.( LSAME( SIDE, 'L' ) .OR. LSAME( SIDE, 'R' ) ) ) THEN
|
|
INFO = 1
|
|
ELSE IF( .NOT.( LSAME( PIVOT, 'V' ) .OR. LSAME( PIVOT,
|
|
$ 'T' ) .OR. LSAME( PIVOT, 'B' ) ) ) THEN
|
|
INFO = 2
|
|
ELSE IF( .NOT.( LSAME( DIRECT, 'F' ) .OR. LSAME( DIRECT, 'B' ) ) )
|
|
$ THEN
|
|
INFO = 3
|
|
ELSE IF( M.LT.0 ) THEN
|
|
INFO = 4
|
|
ELSE IF( N.LT.0 ) THEN
|
|
INFO = 5
|
|
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = 9
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DLASR ', INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( ( M.EQ.0 ) .OR. ( N.EQ.0 ) )
|
|
$ RETURN
|
|
IF( LSAME( SIDE, 'L' ) ) THEN
|
|
*
|
|
* Form P * A
|
|
*
|
|
IF( LSAME( PIVOT, 'V' ) ) THEN
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 20 J = 1, M - 1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 10 I = 1, N
|
|
TEMP = A( J+1, I )
|
|
A( J+1, I ) = CTEMP*TEMP - STEMP*A( J, I )
|
|
A( J, I ) = STEMP*TEMP + CTEMP*A( J, I )
|
|
10 CONTINUE
|
|
END IF
|
|
20 CONTINUE
|
|
ELSE IF( LSAME( DIRECT, 'B' ) ) THEN
|
|
DO 40 J = M - 1, 1, -1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 30 I = 1, N
|
|
TEMP = A( J+1, I )
|
|
A( J+1, I ) = CTEMP*TEMP - STEMP*A( J, I )
|
|
A( J, I ) = STEMP*TEMP + CTEMP*A( J, I )
|
|
30 CONTINUE
|
|
END IF
|
|
40 CONTINUE
|
|
END IF
|
|
ELSE IF( LSAME( PIVOT, 'T' ) ) THEN
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 60 J = 2, M
|
|
CTEMP = C( J-1 )
|
|
STEMP = S( J-1 )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 50 I = 1, N
|
|
TEMP = A( J, I )
|
|
A( J, I ) = CTEMP*TEMP - STEMP*A( 1, I )
|
|
A( 1, I ) = STEMP*TEMP + CTEMP*A( 1, I )
|
|
50 CONTINUE
|
|
END IF
|
|
60 CONTINUE
|
|
ELSE IF( LSAME( DIRECT, 'B' ) ) THEN
|
|
DO 80 J = M, 2, -1
|
|
CTEMP = C( J-1 )
|
|
STEMP = S( J-1 )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 70 I = 1, N
|
|
TEMP = A( J, I )
|
|
A( J, I ) = CTEMP*TEMP - STEMP*A( 1, I )
|
|
A( 1, I ) = STEMP*TEMP + CTEMP*A( 1, I )
|
|
70 CONTINUE
|
|
END IF
|
|
80 CONTINUE
|
|
END IF
|
|
ELSE IF( LSAME( PIVOT, 'B' ) ) THEN
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 100 J = 1, M - 1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 90 I = 1, N
|
|
TEMP = A( J, I )
|
|
A( J, I ) = STEMP*A( M, I ) + CTEMP*TEMP
|
|
A( M, I ) = CTEMP*A( M, I ) - STEMP*TEMP
|
|
90 CONTINUE
|
|
END IF
|
|
100 CONTINUE
|
|
ELSE IF( LSAME( DIRECT, 'B' ) ) THEN
|
|
DO 120 J = M - 1, 1, -1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 110 I = 1, N
|
|
TEMP = A( J, I )
|
|
A( J, I ) = STEMP*A( M, I ) + CTEMP*TEMP
|
|
A( M, I ) = CTEMP*A( M, I ) - STEMP*TEMP
|
|
110 CONTINUE
|
|
END IF
|
|
120 CONTINUE
|
|
END IF
|
|
END IF
|
|
ELSE IF( LSAME( SIDE, 'R' ) ) THEN
|
|
*
|
|
* Form A * P'
|
|
*
|
|
IF( LSAME( PIVOT, 'V' ) ) THEN
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 140 J = 1, N - 1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 130 I = 1, M
|
|
TEMP = A( I, J+1 )
|
|
A( I, J+1 ) = CTEMP*TEMP - STEMP*A( I, J )
|
|
A( I, J ) = STEMP*TEMP + CTEMP*A( I, J )
|
|
130 CONTINUE
|
|
END IF
|
|
140 CONTINUE
|
|
ELSE IF( LSAME( DIRECT, 'B' ) ) THEN
|
|
DO 160 J = N - 1, 1, -1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 150 I = 1, M
|
|
TEMP = A( I, J+1 )
|
|
A( I, J+1 ) = CTEMP*TEMP - STEMP*A( I, J )
|
|
A( I, J ) = STEMP*TEMP + CTEMP*A( I, J )
|
|
150 CONTINUE
|
|
END IF
|
|
160 CONTINUE
|
|
END IF
|
|
ELSE IF( LSAME( PIVOT, 'T' ) ) THEN
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 180 J = 2, N
|
|
CTEMP = C( J-1 )
|
|
STEMP = S( J-1 )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 170 I = 1, M
|
|
TEMP = A( I, J )
|
|
A( I, J ) = CTEMP*TEMP - STEMP*A( I, 1 )
|
|
A( I, 1 ) = STEMP*TEMP + CTEMP*A( I, 1 )
|
|
170 CONTINUE
|
|
END IF
|
|
180 CONTINUE
|
|
ELSE IF( LSAME( DIRECT, 'B' ) ) THEN
|
|
DO 200 J = N, 2, -1
|
|
CTEMP = C( J-1 )
|
|
STEMP = S( J-1 )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 190 I = 1, M
|
|
TEMP = A( I, J )
|
|
A( I, J ) = CTEMP*TEMP - STEMP*A( I, 1 )
|
|
A( I, 1 ) = STEMP*TEMP + CTEMP*A( I, 1 )
|
|
190 CONTINUE
|
|
END IF
|
|
200 CONTINUE
|
|
END IF
|
|
ELSE IF( LSAME( PIVOT, 'B' ) ) THEN
|
|
IF( LSAME( DIRECT, 'F' ) ) THEN
|
|
DO 220 J = 1, N - 1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 210 I = 1, M
|
|
TEMP = A( I, J )
|
|
A( I, J ) = STEMP*A( I, N ) + CTEMP*TEMP
|
|
A( I, N ) = CTEMP*A( I, N ) - STEMP*TEMP
|
|
210 CONTINUE
|
|
END IF
|
|
220 CONTINUE
|
|
ELSE IF( LSAME( DIRECT, 'B' ) ) THEN
|
|
DO 240 J = N - 1, 1, -1
|
|
CTEMP = C( J )
|
|
STEMP = S( J )
|
|
IF( ( CTEMP.NE.ONE ) .OR. ( STEMP.NE.ZERO ) ) THEN
|
|
DO 230 I = 1, M
|
|
TEMP = A( I, J )
|
|
A( I, J ) = STEMP*A( I, N ) + CTEMP*TEMP
|
|
A( I, N ) = CTEMP*A( I, N ) - STEMP*TEMP
|
|
230 CONTINUE
|
|
END IF
|
|
240 CONTINUE
|
|
END IF
|
|
END IF
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLASR
|
|
*
|
|
END
|
|
SUBROUTINE DLASRT( ID, N, D, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER ID
|
|
INTEGER INFO, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION D( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* Sort the numbers in D in increasing order (if ID = 'I') or
|
|
* in decreasing order (if ID = 'D' ).
|
|
*
|
|
* Use Quick Sort, reverting to Insertion sort on arrays of
|
|
* size <= 20. Dimension of STACK limits N to about 2**32.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* ID (input) CHARACTER*1
|
|
* = 'I': sort D in increasing order;
|
|
* = 'D': sort D in decreasing order.
|
|
*
|
|
* N (input) INTEGER
|
|
* The length of the array D.
|
|
*
|
|
* D (input/output) DOUBLE PRECISION array, dimension (N)
|
|
* On entry, the array to be sorted.
|
|
* On exit, D has been sorted into increasing order
|
|
* (D(1) <= ... <= D(N) ) or into decreasing order
|
|
* (D(1) >= ... >= D(N) ), depending on ID.
|
|
*
|
|
* INFO (output) INTEGER
|
|
* = 0: successful exit
|
|
* < 0: if INFO = -i, the i-th argument had an illegal value
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
INTEGER SELECT
|
|
PARAMETER ( SELECT = 20 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER DIR, ENDD, I, J, START, STKPNT
|
|
DOUBLE PRECISION D1, D2, D3, DMNMX, TMP
|
|
* ..
|
|
* .. Local Arrays ..
|
|
INTEGER STACK( 2, 32 )
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
EXTERNAL LSAME
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL XERBLA
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input paramters.
|
|
*
|
|
INFO = 0
|
|
DIR = -1
|
|
IF( LSAME( ID, 'D' ) ) THEN
|
|
DIR = 0
|
|
ELSE IF( LSAME( ID, 'I' ) ) THEN
|
|
DIR = 1
|
|
END IF
|
|
IF( DIR.EQ.-1 ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 ) THEN
|
|
INFO = -2
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DLASRT', -INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.1 )
|
|
$ RETURN
|
|
*
|
|
STKPNT = 1
|
|
STACK( 1, 1 ) = 1
|
|
STACK( 2, 1 ) = N
|
|
10 CONTINUE
|
|
START = STACK( 1, STKPNT )
|
|
ENDD = STACK( 2, STKPNT )
|
|
STKPNT = STKPNT - 1
|
|
IF( ENDD-START.LE.SELECT .AND. ENDD-START.GT.0 ) THEN
|
|
*
|
|
* Do Insertion sort on D( START:ENDD )
|
|
*
|
|
IF( DIR.EQ.0 ) THEN
|
|
*
|
|
* Sort into decreasing order
|
|
*
|
|
DO 30 I = START + 1, ENDD
|
|
DO 20 J = I, START + 1, -1
|
|
IF( D( J ).GT.D( J-1 ) ) THEN
|
|
DMNMX = D( J )
|
|
D( J ) = D( J-1 )
|
|
D( J-1 ) = DMNMX
|
|
ELSE
|
|
GO TO 30
|
|
END IF
|
|
20 CONTINUE
|
|
30 CONTINUE
|
|
*
|
|
ELSE
|
|
*
|
|
* Sort into increasing order
|
|
*
|
|
DO 50 I = START + 1, ENDD
|
|
DO 40 J = I, START + 1, -1
|
|
IF( D( J ).LT.D( J-1 ) ) THEN
|
|
DMNMX = D( J )
|
|
D( J ) = D( J-1 )
|
|
D( J-1 ) = DMNMX
|
|
ELSE
|
|
GO TO 50
|
|
END IF
|
|
40 CONTINUE
|
|
50 CONTINUE
|
|
*
|
|
END IF
|
|
*
|
|
ELSE IF( ENDD-START.GT.SELECT ) THEN
|
|
*
|
|
* Partition D( START:ENDD ) and stack parts, largest one first
|
|
*
|
|
* Choose partition entry as median of 3
|
|
*
|
|
D1 = D( START )
|
|
D2 = D( ENDD )
|
|
I = ( START+ENDD ) / 2
|
|
D3 = D( I )
|
|
IF( D1.LT.D2 ) THEN
|
|
IF( D3.LT.D1 ) THEN
|
|
DMNMX = D1
|
|
ELSE IF( D3.LT.D2 ) THEN
|
|
DMNMX = D3
|
|
ELSE
|
|
DMNMX = D2
|
|
END IF
|
|
ELSE
|
|
IF( D3.LT.D2 ) THEN
|
|
DMNMX = D2
|
|
ELSE IF( D3.LT.D1 ) THEN
|
|
DMNMX = D3
|
|
ELSE
|
|
DMNMX = D1
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( DIR.EQ.0 ) THEN
|
|
*
|
|
* Sort into decreasing order
|
|
*
|
|
I = START - 1
|
|
J = ENDD + 1
|
|
60 CONTINUE
|
|
70 CONTINUE
|
|
J = J - 1
|
|
IF( D( J ).LT.DMNMX )
|
|
$ GO TO 70
|
|
80 CONTINUE
|
|
I = I + 1
|
|
IF( D( I ).GT.DMNMX )
|
|
$ GO TO 80
|
|
IF( I.LT.J ) THEN
|
|
TMP = D( I )
|
|
D( I ) = D( J )
|
|
D( J ) = TMP
|
|
GO TO 60
|
|
END IF
|
|
IF( J-START.GT.ENDD-J-1 ) THEN
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = START
|
|
STACK( 2, STKPNT ) = J
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = J + 1
|
|
STACK( 2, STKPNT ) = ENDD
|
|
ELSE
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = J + 1
|
|
STACK( 2, STKPNT ) = ENDD
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = START
|
|
STACK( 2, STKPNT ) = J
|
|
END IF
|
|
ELSE
|
|
*
|
|
* Sort into increasing order
|
|
*
|
|
I = START - 1
|
|
J = ENDD + 1
|
|
90 CONTINUE
|
|
100 CONTINUE
|
|
J = J - 1
|
|
IF( D( J ).GT.DMNMX )
|
|
$ GO TO 100
|
|
110 CONTINUE
|
|
I = I + 1
|
|
IF( D( I ).LT.DMNMX )
|
|
$ GO TO 110
|
|
IF( I.LT.J ) THEN
|
|
TMP = D( I )
|
|
D( I ) = D( J )
|
|
D( J ) = TMP
|
|
GO TO 90
|
|
END IF
|
|
IF( J-START.GT.ENDD-J-1 ) THEN
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = START
|
|
STACK( 2, STKPNT ) = J
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = J + 1
|
|
STACK( 2, STKPNT ) = ENDD
|
|
ELSE
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = J + 1
|
|
STACK( 2, STKPNT ) = ENDD
|
|
STKPNT = STKPNT + 1
|
|
STACK( 1, STKPNT ) = START
|
|
STACK( 2, STKPNT ) = J
|
|
END IF
|
|
END IF
|
|
END IF
|
|
IF( STKPNT.GT.0 )
|
|
$ GO TO 10
|
|
RETURN
|
|
*
|
|
* End of DLASRT
|
|
*
|
|
END
|
|
SUBROUTINE DLASSQ( N, X, INCX, SCALE, SUMSQ )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INCX, N
|
|
DOUBLE PRECISION SCALE, SUMSQ
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION X( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLASSQ returns the values scl and smsq such that
|
|
*
|
|
* ( scl**2 )*smsq = x( 1 )**2 +...+ x( n )**2 + ( scale**2 )*sumsq,
|
|
*
|
|
* where x( i ) = X( 1 + ( i - 1 )*INCX ). The value of sumsq is
|
|
* assumed to be non-negative and scl returns the value
|
|
*
|
|
* scl = max( scale, abs( x( i ) ) ).
|
|
*
|
|
* scale and sumsq must be supplied in SCALE and SUMSQ and
|
|
* scl and smsq are overwritten on SCALE and SUMSQ respectively.
|
|
*
|
|
* The routine makes only one pass through the vector x.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of elements to be used from the vector X.
|
|
*
|
|
* X (input) DOUBLE PRECISION array, dimension (N)
|
|
* The vector for which a scaled sum of squares is computed.
|
|
* x( i ) = X( 1 + ( i - 1 )*INCX ), 1 <= i <= n.
|
|
*
|
|
* INCX (input) INTEGER
|
|
* The increment between successive values of the vector X.
|
|
* INCX > 0.
|
|
*
|
|
* SCALE (input/output) DOUBLE PRECISION
|
|
* On entry, the value scale in the equation above.
|
|
* On exit, SCALE is overwritten with scl , the scaling factor
|
|
* for the sum of squares.
|
|
*
|
|
* SUMSQ (input/output) DOUBLE PRECISION
|
|
* On entry, the value sumsq in the equation above.
|
|
* On exit, SUMSQ is overwritten with smsq , the basic sum of
|
|
* squares from which scl has been factored out.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER IX
|
|
DOUBLE PRECISION ABSXI
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
IF( N.GT.0 ) THEN
|
|
DO 10 IX = 1, 1 + ( N-1 )*INCX, INCX
|
|
IF( X( IX ).NE.ZERO ) THEN
|
|
ABSXI = ABS( X( IX ) )
|
|
IF( SCALE.LT.ABSXI ) THEN
|
|
SUMSQ = 1 + SUMSQ*( SCALE / ABSXI )**2
|
|
SCALE = ABSXI
|
|
ELSE
|
|
SUMSQ = SUMSQ + ( ABSXI / SCALE )**2
|
|
END IF
|
|
END IF
|
|
10 CONTINUE
|
|
END IF
|
|
RETURN
|
|
*
|
|
* End of DLASSQ
|
|
*
|
|
END
|
|
SUBROUTINE DLATRD( UPLO, N, NB, A, LDA, E, TAU, W, LDW )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER UPLO
|
|
INTEGER LDA, LDW, N, NB
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), E( * ), TAU( * ), W( LDW, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DLATRD reduces NB rows and columns of a real symmetric matrix A to
|
|
* symmetric tridiagonal form by an orthogonal similarity
|
|
* transformation Q' * A * Q, and returns the matrices V and W which are
|
|
* needed to apply the transformation to the unreduced part of A.
|
|
*
|
|
* If UPLO = 'U', DLATRD reduces the last NB rows and columns of a
|
|
* matrix, of which the upper triangle is supplied;
|
|
* if UPLO = 'L', DLATRD reduces the first NB rows and columns of a
|
|
* matrix, of which the lower triangle is supplied.
|
|
*
|
|
* This is an auxiliary routine called by DSYTRD.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* UPLO (input) CHARACTER*1
|
|
* Specifies whether the upper or lower triangular part of the
|
|
* symmetric matrix A is stored:
|
|
* = 'U': Upper triangular
|
|
* = 'L': Lower triangular
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the matrix A.
|
|
*
|
|
* NB (input) INTEGER
|
|
* The number of rows and columns to be reduced.
|
|
*
|
|
* 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, and the strictly lower
|
|
* triangular part of A is not referenced. If UPLO = 'L', the
|
|
* leading n-by-n lower triangular part of A contains the lower
|
|
* triangular part of the matrix A, and the strictly upper
|
|
* triangular part of A is not referenced.
|
|
* On exit:
|
|
* if UPLO = 'U', the last NB columns have been reduced to
|
|
* tridiagonal form, with the diagonal elements overwriting
|
|
* the diagonal elements of A; the elements above the diagonal
|
|
* with the array TAU, represent the orthogonal matrix Q as a
|
|
* product of elementary reflectors;
|
|
* if UPLO = 'L', the first NB columns have been reduced to
|
|
* tridiagonal form, with the diagonal elements overwriting
|
|
* the diagonal elements of A; the elements below the diagonal
|
|
* with the array TAU, represent the orthogonal matrix Q as a
|
|
* product of elementary reflectors.
|
|
* See Further Details.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= (1,N).
|
|
*
|
|
* E (output) DOUBLE PRECISION array, dimension (N-1)
|
|
* If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal
|
|
* elements of the last NB columns of the reduced matrix;
|
|
* if UPLO = 'L', E(1:nb) contains the subdiagonal elements of
|
|
* the first NB columns of the reduced matrix.
|
|
*
|
|
* TAU (output) DOUBLE PRECISION array, dimension (N-1)
|
|
* The scalar factors of the elementary reflectors, stored in
|
|
* TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'.
|
|
* See Further Details.
|
|
*
|
|
* W (output) DOUBLE PRECISION array, dimension (LDW,NB)
|
|
* The n-by-nb matrix W required to update the unreduced part
|
|
* of A.
|
|
*
|
|
* LDW (input) INTEGER
|
|
* The leading dimension of the array W. LDW >= max(1,N).
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* If UPLO = 'U', the matrix Q is represented as a product of elementary
|
|
* reflectors
|
|
*
|
|
* Q = H(n) H(n-1) . . . H(n-nb+1).
|
|
*
|
|
* Each H(i) has the form
|
|
*
|
|
* H(i) = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar, and v is a real vector with
|
|
* v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i),
|
|
* and tau in TAU(i-1).
|
|
*
|
|
* If UPLO = 'L', the matrix Q is represented as a product of elementary
|
|
* reflectors
|
|
*
|
|
* Q = H(1) H(2) . . . H(nb).
|
|
*
|
|
* Each H(i) has the form
|
|
*
|
|
* H(i) = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar, and v is a real vector with
|
|
* v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i),
|
|
* and tau in TAU(i).
|
|
*
|
|
* The elements of the vectors v together form the n-by-nb matrix V
|
|
* which is needed, with W, to apply the transformation to the unreduced
|
|
* part of the matrix, using a symmetric rank-2k update of the form:
|
|
* A := A - V*W' - W*V'.
|
|
*
|
|
* The contents of A on exit are illustrated by the following examples
|
|
* with n = 5 and nb = 2:
|
|
*
|
|
* if UPLO = 'U': if UPLO = 'L':
|
|
*
|
|
* ( a a a v4 v5 ) ( d )
|
|
* ( a a v4 v5 ) ( 1 d )
|
|
* ( a 1 v5 ) ( v1 1 a )
|
|
* ( d 1 ) ( v1 v2 a a )
|
|
* ( d ) ( v1 v2 a a a )
|
|
*
|
|
* where d denotes a diagonal element of the reduced matrix, a denotes
|
|
* an element of the original matrix that is unchanged, and vi denotes
|
|
* an element of the vector defining H(i).
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, ONE, HALF
|
|
PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0, HALF = 0.5D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, IW
|
|
DOUBLE PRECISION ALPHA
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DAXPY, DGEMV, DLARFG, DSCAL, DSYMV
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
DOUBLE PRECISION DDOT
|
|
EXTERNAL LSAME, DDOT
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MIN
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.0 )
|
|
$ RETURN
|
|
*
|
|
IF( LSAME( UPLO, 'U' ) ) THEN
|
|
*
|
|
* Reduce last NB columns of upper triangle
|
|
*
|
|
DO 10 I = N, N - NB + 1, -1
|
|
IW = I - N + NB
|
|
IF( I.LT.N ) THEN
|
|
*
|
|
* Update A(1:i,i)
|
|
*
|
|
CALL DGEMV( 'No transpose', I, N-I, -ONE, A( 1, I+1 ),
|
|
$ LDA, W( I, IW+1 ), LDW, ONE, A( 1, I ), 1 )
|
|
CALL DGEMV( 'No transpose', I, N-I, -ONE, W( 1, IW+1 ),
|
|
$ LDW, A( I, I+1 ), LDA, ONE, A( 1, I ), 1 )
|
|
END IF
|
|
IF( I.GT.1 ) THEN
|
|
*
|
|
* Generate elementary reflector H(i) to annihilate
|
|
* A(1:i-2,i)
|
|
*
|
|
CALL DLARFG( I-1, A( I-1, I ), A( 1, I ), 1, TAU( I-1 ) )
|
|
E( I-1 ) = A( I-1, I )
|
|
A( I-1, I ) = ONE
|
|
*
|
|
* Compute W(1:i-1,i)
|
|
*
|
|
CALL DSYMV( 'Upper', I-1, ONE, A, LDA, A( 1, I ), 1,
|
|
$ ZERO, W( 1, IW ), 1 )
|
|
IF( I.LT.N ) THEN
|
|
CALL DGEMV( 'Transpose', I-1, N-I, ONE, W( 1, IW+1 ),
|
|
$ LDW, A( 1, I ), 1, ZERO, W( I+1, IW ), 1 )
|
|
CALL DGEMV( 'No transpose', I-1, N-I, -ONE,
|
|
$ A( 1, I+1 ), LDA, W( I+1, IW ), 1, ONE,
|
|
$ W( 1, IW ), 1 )
|
|
CALL DGEMV( 'Transpose', I-1, N-I, ONE, A( 1, I+1 ),
|
|
$ LDA, A( 1, I ), 1, ZERO, W( I+1, IW ), 1 )
|
|
CALL DGEMV( 'No transpose', I-1, N-I, -ONE,
|
|
$ W( 1, IW+1 ), LDW, W( I+1, IW ), 1, ONE,
|
|
$ W( 1, IW ), 1 )
|
|
END IF
|
|
CALL DSCAL( I-1, TAU( I-1 ), W( 1, IW ), 1 )
|
|
ALPHA = -HALF*TAU( I-1 )*DDOT( I-1, W( 1, IW ), 1,
|
|
$ A( 1, I ), 1 )
|
|
CALL DAXPY( I-1, ALPHA, A( 1, I ), 1, W( 1, IW ), 1 )
|
|
END IF
|
|
*
|
|
10 CONTINUE
|
|
ELSE
|
|
*
|
|
* Reduce first NB columns of lower triangle
|
|
*
|
|
DO 20 I = 1, NB
|
|
*
|
|
* Update A(i:n,i)
|
|
*
|
|
CALL DGEMV( 'No transpose', N-I+1, I-1, -ONE, A( I, 1 ),
|
|
$ LDA, W( I, 1 ), LDW, ONE, A( I, I ), 1 )
|
|
CALL DGEMV( 'No transpose', N-I+1, I-1, -ONE, W( I, 1 ),
|
|
$ LDW, A( I, 1 ), LDA, ONE, A( I, I ), 1 )
|
|
IF( I.LT.N ) THEN
|
|
*
|
|
* Generate elementary reflector H(i) to annihilate
|
|
* A(i+2:n,i)
|
|
*
|
|
CALL DLARFG( N-I, A( I+1, I ), A( MIN( I+2, N ), I ), 1,
|
|
$ TAU( I ) )
|
|
E( I ) = A( I+1, I )
|
|
A( I+1, I ) = ONE
|
|
*
|
|
* Compute W(i+1:n,i)
|
|
*
|
|
CALL DSYMV( 'Lower', N-I, ONE, A( I+1, I+1 ), LDA,
|
|
$ A( I+1, I ), 1, ZERO, W( I+1, I ), 1 )
|
|
CALL DGEMV( 'Transpose', N-I, I-1, ONE, W( I+1, 1 ), LDW,
|
|
$ A( I+1, I ), 1, ZERO, W( 1, I ), 1 )
|
|
CALL DGEMV( 'No transpose', N-I, I-1, -ONE, A( I+1, 1 ),
|
|
$ LDA, W( 1, I ), 1, ONE, W( I+1, I ), 1 )
|
|
CALL DGEMV( 'Transpose', N-I, I-1, ONE, A( I+1, 1 ), LDA,
|
|
$ A( I+1, I ), 1, ZERO, W( 1, I ), 1 )
|
|
CALL DGEMV( 'No transpose', N-I, I-1, -ONE, W( I+1, 1 ),
|
|
$ LDW, W( 1, I ), 1, ONE, W( I+1, I ), 1 )
|
|
CALL DSCAL( N-I, TAU( I ), W( I+1, I ), 1 )
|
|
ALPHA = -HALF*TAU( I )*DDOT( N-I, W( I+1, I ), 1,
|
|
$ A( I+1, I ), 1 )
|
|
CALL DAXPY( N-I, ALPHA, A( I+1, I ), 1, W( I+1, I ), 1 )
|
|
END IF
|
|
*
|
|
20 CONTINUE
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DLATRD
|
|
*
|
|
END
|
|
SUBROUTINE DORG2L( M, N, K, A, LDA, TAU, WORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INFO, K, LDA, M, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DORG2L generates an m by n real matrix Q with orthonormal columns,
|
|
* which is defined as the last n columns of a product of k elementary
|
|
* reflectors of order m
|
|
*
|
|
* Q = H(k) . . . H(2) H(1)
|
|
*
|
|
* as returned by DGEQLF.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix Q. M >= 0.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix Q. M >= N >= 0.
|
|
*
|
|
* K (input) INTEGER
|
|
* The number of elementary reflectors whose product defines the
|
|
* matrix Q. N >= K >= 0.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* On entry, the (n-k+i)-th column must contain the vector which
|
|
* defines the elementary reflector H(i), for i = 1,2,...,k, as
|
|
* returned by DGEQLF in the last k columns of its array
|
|
* argument A.
|
|
* On exit, the m by n matrix Q.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The first dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* TAU (input) DOUBLE PRECISION array, dimension (K)
|
|
* TAU(i) must contain the scalar factor of the elementary
|
|
* reflector H(i), as returned by DGEQLF.
|
|
*
|
|
* WORK (workspace) DOUBLE PRECISION array, dimension (N)
|
|
*
|
|
* INFO (output) INTEGER
|
|
* = 0: successful exit
|
|
* < 0: if INFO = -i, the i-th argument has an illegal value
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, II, J, L
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLARF, DSCAL, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
IF( M.LT.0 ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 .OR. N.GT.M ) THEN
|
|
INFO = -2
|
|
ELSE IF( K.LT.0 .OR. K.GT.N ) THEN
|
|
INFO = -3
|
|
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = -5
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DORG2L', -INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.0 )
|
|
$ RETURN
|
|
*
|
|
* Initialise columns 1:n-k to columns of the unit matrix
|
|
*
|
|
DO 20 J = 1, N - K
|
|
DO 10 L = 1, M
|
|
A( L, J ) = ZERO
|
|
10 CONTINUE
|
|
A( M-N+J, J ) = ONE
|
|
20 CONTINUE
|
|
*
|
|
DO 40 I = 1, K
|
|
II = N - K + I
|
|
*
|
|
* Apply H(i) to A(1:m-k+i,1:n-k+i) from the left
|
|
*
|
|
A( M-N+II, II ) = ONE
|
|
CALL DLARF( 'Left', M-N+II, II-1, A( 1, II ), 1, TAU( I ), A,
|
|
$ LDA, WORK )
|
|
CALL DSCAL( M-N+II-1, -TAU( I ), A( 1, II ), 1 )
|
|
A( M-N+II, II ) = ONE - TAU( I )
|
|
*
|
|
* Set A(m-k+i+1:m,n-k+i) to zero
|
|
*
|
|
DO 30 L = M - N + II + 1, M
|
|
A( L, II ) = ZERO
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
RETURN
|
|
*
|
|
* End of DORG2L
|
|
*
|
|
END
|
|
SUBROUTINE DORG2R( M, N, K, A, LDA, TAU, WORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INFO, K, LDA, M, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DORG2R generates an m by n real matrix Q with orthonormal columns,
|
|
* which is defined as the first n columns of a product of k elementary
|
|
* reflectors of order m
|
|
*
|
|
* Q = H(1) H(2) . . . H(k)
|
|
*
|
|
* as returned by DGEQRF.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix Q. M >= 0.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix Q. M >= N >= 0.
|
|
*
|
|
* K (input) INTEGER
|
|
* The number of elementary reflectors whose product defines the
|
|
* matrix Q. N >= K >= 0.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* On entry, the i-th column must contain the vector which
|
|
* defines the elementary reflector H(i), for i = 1,2,...,k, as
|
|
* returned by DGEQRF in the first k columns of its array
|
|
* argument A.
|
|
* On exit, the m-by-n matrix Q.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The first dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* TAU (input) DOUBLE PRECISION array, dimension (K)
|
|
* TAU(i) must contain the scalar factor of the elementary
|
|
* reflector H(i), as returned by DGEQRF.
|
|
*
|
|
* WORK (workspace) DOUBLE PRECISION array, dimension (N)
|
|
*
|
|
* INFO (output) INTEGER
|
|
* = 0: successful exit
|
|
* < 0: if INFO = -i, the i-th argument has an illegal value
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO
|
|
PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, J, L
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLARF, DSCAL, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
IF( M.LT.0 ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 .OR. N.GT.M ) THEN
|
|
INFO = -2
|
|
ELSE IF( K.LT.0 .OR. K.GT.N ) THEN
|
|
INFO = -3
|
|
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = -5
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DORG2R', -INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.0 )
|
|
$ RETURN
|
|
*
|
|
* Initialise columns k+1:n to columns of the unit matrix
|
|
*
|
|
DO 20 J = K + 1, N
|
|
DO 10 L = 1, M
|
|
A( L, J ) = ZERO
|
|
10 CONTINUE
|
|
A( J, J ) = ONE
|
|
20 CONTINUE
|
|
*
|
|
DO 40 I = K, 1, -1
|
|
*
|
|
* Apply H(i) to A(i:m,i:n) from the left
|
|
*
|
|
IF( I.LT.N ) THEN
|
|
A( I, I ) = ONE
|
|
CALL DLARF( 'Left', M-I+1, N-I, A( I, I ), 1, TAU( I ),
|
|
$ A( I, I+1 ), LDA, WORK )
|
|
END IF
|
|
IF( I.LT.M )
|
|
$ CALL DSCAL( M-I, -TAU( I ), A( I+1, I ), 1 )
|
|
A( I, I ) = ONE - TAU( I )
|
|
*
|
|
* Set A(1:i-1,i) to zero
|
|
*
|
|
DO 30 L = 1, I - 1
|
|
A( L, I ) = ZERO
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
RETURN
|
|
*
|
|
* End of DORG2R
|
|
*
|
|
END
|
|
SUBROUTINE DORGQL( M, N, K, A, LDA, TAU, WORK, LWORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INFO, K, LDA, LWORK, M, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DORGQL generates an M-by-N real matrix Q with orthonormal columns,
|
|
* which is defined as the last N columns of a product of K elementary
|
|
* reflectors of order M
|
|
*
|
|
* Q = H(k) . . . H(2) H(1)
|
|
*
|
|
* as returned by DGEQLF.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix Q. M >= 0.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix Q. M >= N >= 0.
|
|
*
|
|
* K (input) INTEGER
|
|
* The number of elementary reflectors whose product defines the
|
|
* matrix Q. N >= K >= 0.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* On entry, the (n-k+i)-th column must contain the vector which
|
|
* defines the elementary reflector H(i), for i = 1,2,...,k, as
|
|
* returned by DGEQLF in the last k columns of its array
|
|
* argument A.
|
|
* On exit, the M-by-N matrix Q.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The first dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* TAU (input) DOUBLE PRECISION array, dimension (K)
|
|
* TAU(i) must contain the scalar factor of the elementary
|
|
* reflector H(i), as returned by DGEQLF.
|
|
*
|
|
* 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 dimension of the array WORK. LWORK >= max(1,N).
|
|
* For optimum performance LWORK >= N*NB, where NB is the
|
|
* optimal blocksize.
|
|
*
|
|
* 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 has an illegal value
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL LQUERY
|
|
INTEGER I, IB, IINFO, IWS, J, KK, L, LDWORK, LWKOPT,
|
|
$ NB, NBMIN, NX
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLARFB, DLARFT, DORG2L, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX, MIN
|
|
* ..
|
|
* .. External Functions ..
|
|
INTEGER ILAENV
|
|
EXTERNAL ILAENV
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
LQUERY = ( LWORK.EQ.-1 )
|
|
IF( M.LT.0 ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 .OR. N.GT.M ) THEN
|
|
INFO = -2
|
|
ELSE IF( K.LT.0 .OR. K.GT.N ) THEN
|
|
INFO = -3
|
|
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = -5
|
|
END IF
|
|
*
|
|
IF( INFO.EQ.0 ) THEN
|
|
IF( N.EQ.0 ) THEN
|
|
LWKOPT = 1
|
|
ELSE
|
|
NB = ILAENV( 1, 'DORGQL', ' ', M, N, K, -1 )
|
|
LWKOPT = N*NB
|
|
END IF
|
|
WORK( 1 ) = LWKOPT
|
|
*
|
|
IF( LWORK.LT.MAX( 1, N ) .AND. .NOT.LQUERY ) THEN
|
|
INFO = -8
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DORGQL', -INFO )
|
|
RETURN
|
|
ELSE IF( LQUERY ) THEN
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.0 ) THEN
|
|
RETURN
|
|
END IF
|
|
*
|
|
NBMIN = 2
|
|
NX = 0
|
|
IWS = N
|
|
IF( NB.GT.1 .AND. NB.LT.K ) THEN
|
|
*
|
|
* Determine when to cross over from blocked to unblocked code.
|
|
*
|
|
NX = MAX( 0, ILAENV( 3, 'DORGQL', ' ', M, N, K, -1 ) )
|
|
IF( NX.LT.K ) THEN
|
|
*
|
|
* Determine if workspace is large enough for blocked code.
|
|
*
|
|
LDWORK = N
|
|
IWS = LDWORK*NB
|
|
IF( LWORK.LT.IWS ) THEN
|
|
*
|
|
* Not enough workspace to use optimal NB: reduce NB and
|
|
* determine the minimum value of NB.
|
|
*
|
|
NB = LWORK / LDWORK
|
|
NBMIN = MAX( 2, ILAENV( 2, 'DORGQL', ' ', M, N, K, -1 ) )
|
|
END IF
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( NB.GE.NBMIN .AND. NB.LT.K .AND. NX.LT.K ) THEN
|
|
*
|
|
* Use blocked code after the first block.
|
|
* The last kk columns are handled by the block method.
|
|
*
|
|
KK = MIN( K, ( ( K-NX+NB-1 ) / NB )*NB )
|
|
*
|
|
* Set A(m-kk+1:m,1:n-kk) to zero.
|
|
*
|
|
DO 20 J = 1, N - KK
|
|
DO 10 I = M - KK + 1, M
|
|
A( I, J ) = ZERO
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
ELSE
|
|
KK = 0
|
|
END IF
|
|
*
|
|
* Use unblocked code for the first or only block.
|
|
*
|
|
CALL DORG2L( M-KK, N-KK, K-KK, A, LDA, TAU, WORK, IINFO )
|
|
*
|
|
IF( KK.GT.0 ) THEN
|
|
*
|
|
* Use blocked code
|
|
*
|
|
DO 50 I = K - KK + 1, K, NB
|
|
IB = MIN( NB, K-I+1 )
|
|
IF( N-K+I.GT.1 ) THEN
|
|
*
|
|
* Form the triangular factor of the block reflector
|
|
* H = H(i+ib-1) . . . H(i+1) H(i)
|
|
*
|
|
CALL DLARFT( 'Backward', 'Columnwise', M-K+I+IB-1, IB,
|
|
$ A( 1, N-K+I ), LDA, TAU( I ), WORK, LDWORK )
|
|
*
|
|
* Apply H to A(1:m-k+i+ib-1,1:n-k+i-1) from the left
|
|
*
|
|
CALL DLARFB( 'Left', 'No transpose', 'Backward',
|
|
$ 'Columnwise', M-K+I+IB-1, N-K+I-1, IB,
|
|
$ A( 1, N-K+I ), LDA, WORK, LDWORK, A, LDA,
|
|
$ WORK( IB+1 ), LDWORK )
|
|
END IF
|
|
*
|
|
* Apply H to rows 1:m-k+i+ib-1 of current block
|
|
*
|
|
CALL DORG2L( M-K+I+IB-1, IB, IB, A( 1, N-K+I ), LDA,
|
|
$ TAU( I ), WORK, IINFO )
|
|
*
|
|
* Set rows m-k+i+ib:m of current block to zero
|
|
*
|
|
DO 40 J = N - K + I, N - K + I + IB - 1
|
|
DO 30 L = M - K + I + IB, M
|
|
A( L, J ) = ZERO
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
50 CONTINUE
|
|
END IF
|
|
*
|
|
WORK( 1 ) = IWS
|
|
RETURN
|
|
*
|
|
* End of DORGQL
|
|
*
|
|
END
|
|
SUBROUTINE DORGQR( M, N, K, A, LDA, TAU, WORK, LWORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INFO, K, LDA, LWORK, M, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DORGQR generates an M-by-N real matrix Q with orthonormal columns,
|
|
* which is defined as the first N columns of a product of K elementary
|
|
* reflectors of order M
|
|
*
|
|
* Q = H(1) H(2) . . . H(k)
|
|
*
|
|
* as returned by DGEQRF.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* M (input) INTEGER
|
|
* The number of rows of the matrix Q. M >= 0.
|
|
*
|
|
* N (input) INTEGER
|
|
* The number of columns of the matrix Q. M >= N >= 0.
|
|
*
|
|
* K (input) INTEGER
|
|
* The number of elementary reflectors whose product defines the
|
|
* matrix Q. N >= K >= 0.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* On entry, the i-th column must contain the vector which
|
|
* defines the elementary reflector H(i), for i = 1,2,...,k, as
|
|
* returned by DGEQRF in the first k columns of its array
|
|
* argument A.
|
|
* On exit, the M-by-N matrix Q.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The first dimension of the array A. LDA >= max(1,M).
|
|
*
|
|
* TAU (input) DOUBLE PRECISION array, dimension (K)
|
|
* TAU(i) must contain the scalar factor of the elementary
|
|
* reflector H(i), as returned by DGEQRF.
|
|
*
|
|
* 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 dimension of the array WORK. LWORK >= max(1,N).
|
|
* For optimum performance LWORK >= N*NB, where NB is the
|
|
* optimal blocksize.
|
|
*
|
|
* 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 has an illegal value
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO
|
|
PARAMETER ( ZERO = 0.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL LQUERY
|
|
INTEGER I, IB, IINFO, IWS, J, KI, KK, L, LDWORK,
|
|
$ LWKOPT, NB, NBMIN, NX
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLARFB, DLARFT, DORG2R, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX, MIN
|
|
* ..
|
|
* .. External Functions ..
|
|
INTEGER ILAENV
|
|
EXTERNAL ILAENV
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
NB = ILAENV( 1, 'DORGQR', ' ', M, N, K, -1 )
|
|
LWKOPT = MAX( 1, N )*NB
|
|
WORK( 1 ) = LWKOPT
|
|
LQUERY = ( LWORK.EQ.-1 )
|
|
IF( M.LT.0 ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 .OR. N.GT.M ) THEN
|
|
INFO = -2
|
|
ELSE IF( K.LT.0 .OR. K.GT.N ) THEN
|
|
INFO = -3
|
|
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = -5
|
|
ELSE IF( LWORK.LT.MAX( 1, N ) .AND. .NOT.LQUERY ) THEN
|
|
INFO = -8
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DORGQR', -INFO )
|
|
RETURN
|
|
ELSE IF( LQUERY ) THEN
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.0 ) THEN
|
|
WORK( 1 ) = 1
|
|
RETURN
|
|
END IF
|
|
*
|
|
NBMIN = 2
|
|
NX = 0
|
|
IWS = N
|
|
IF( NB.GT.1 .AND. NB.LT.K ) THEN
|
|
*
|
|
* Determine when to cross over from blocked to unblocked code.
|
|
*
|
|
NX = MAX( 0, ILAENV( 3, 'DORGQR', ' ', M, N, K, -1 ) )
|
|
IF( NX.LT.K ) THEN
|
|
*
|
|
* Determine if workspace is large enough for blocked code.
|
|
*
|
|
LDWORK = N
|
|
IWS = LDWORK*NB
|
|
IF( LWORK.LT.IWS ) THEN
|
|
*
|
|
* Not enough workspace to use optimal NB: reduce NB and
|
|
* determine the minimum value of NB.
|
|
*
|
|
NB = LWORK / LDWORK
|
|
NBMIN = MAX( 2, ILAENV( 2, 'DORGQR', ' ', M, N, K, -1 ) )
|
|
END IF
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( NB.GE.NBMIN .AND. NB.LT.K .AND. NX.LT.K ) THEN
|
|
*
|
|
* Use blocked code after the last block.
|
|
* The first kk columns are handled by the block method.
|
|
*
|
|
KI = ( ( K-NX-1 ) / NB )*NB
|
|
KK = MIN( K, KI+NB )
|
|
*
|
|
* Set A(1:kk,kk+1:n) to zero.
|
|
*
|
|
DO 20 J = KK + 1, N
|
|
DO 10 I = 1, KK
|
|
A( I, J ) = ZERO
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
ELSE
|
|
KK = 0
|
|
END IF
|
|
*
|
|
* Use unblocked code for the last or only block.
|
|
*
|
|
IF( KK.LT.N )
|
|
$ CALL DORG2R( M-KK, N-KK, K-KK, A( KK+1, KK+1 ), LDA,
|
|
$ TAU( KK+1 ), WORK, IINFO )
|
|
*
|
|
IF( KK.GT.0 ) THEN
|
|
*
|
|
* Use blocked code
|
|
*
|
|
DO 50 I = KI + 1, 1, -NB
|
|
IB = MIN( NB, K-I+1 )
|
|
IF( I+IB.LE.N ) THEN
|
|
*
|
|
* Form the triangular factor of the block reflector
|
|
* H = H(i) H(i+1) . . . H(i+ib-1)
|
|
*
|
|
CALL DLARFT( 'Forward', 'Columnwise', M-I+1, IB,
|
|
$ A( I, I ), LDA, TAU( I ), WORK, LDWORK )
|
|
*
|
|
* Apply H to A(i:m,i+ib:n) from the left
|
|
*
|
|
CALL DLARFB( 'Left', 'No transpose', 'Forward',
|
|
$ 'Columnwise', M-I+1, N-I-IB+1, IB,
|
|
$ A( I, I ), LDA, WORK, LDWORK, A( I, I+IB ),
|
|
$ LDA, WORK( IB+1 ), LDWORK )
|
|
END IF
|
|
*
|
|
* Apply H to rows i:m of current block
|
|
*
|
|
CALL DORG2R( M-I+1, IB, IB, A( I, I ), LDA, TAU( I ), WORK,
|
|
$ IINFO )
|
|
*
|
|
* Set rows 1:i-1 of current block to zero
|
|
*
|
|
DO 40 J = I, I + IB - 1
|
|
DO 30 L = 1, I - 1
|
|
A( L, J ) = ZERO
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
50 CONTINUE
|
|
END IF
|
|
*
|
|
WORK( 1 ) = IWS
|
|
RETURN
|
|
*
|
|
* End of DORGQR
|
|
*
|
|
END
|
|
SUBROUTINE DORGTR( UPLO, N, A, LDA, TAU, WORK, LWORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER UPLO
|
|
INTEGER INFO, LDA, LWORK, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DORGTR generates a real orthogonal matrix Q which is defined as the
|
|
* product of n-1 elementary reflectors of order N, as returned by
|
|
* DSYTRD:
|
|
*
|
|
* if UPLO = 'U', Q = H(n-1) . . . H(2) H(1),
|
|
*
|
|
* if UPLO = 'L', Q = H(1) H(2) . . . H(n-1).
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* UPLO (input) CHARACTER*1
|
|
* = 'U': Upper triangle of A contains elementary reflectors
|
|
* from DSYTRD;
|
|
* = 'L': Lower triangle of A contains elementary reflectors
|
|
* from DSYTRD.
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the matrix Q. N >= 0.
|
|
*
|
|
* A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
|
|
* On entry, the vectors which define the elementary reflectors,
|
|
* as returned by DSYTRD.
|
|
* On exit, the N-by-N orthogonal matrix Q.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(1,N).
|
|
*
|
|
* TAU (input) DOUBLE PRECISION array, dimension (N-1)
|
|
* TAU(i) must contain the scalar factor of the elementary
|
|
* reflector H(i), as returned by DSYTRD.
|
|
*
|
|
* 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 dimension of the array WORK. LWORK >= max(1,N-1).
|
|
* For optimum performance LWORK >= (N-1)*NB, where NB is
|
|
* the optimal blocksize.
|
|
*
|
|
* 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
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, ONE
|
|
PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL LQUERY, UPPER
|
|
INTEGER I, IINFO, J, LWKOPT, NB
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
INTEGER ILAENV
|
|
EXTERNAL LSAME, ILAENV
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DORGQL, DORGQR, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
LQUERY = ( LWORK.EQ.-1 )
|
|
UPPER = LSAME( UPLO, 'U' )
|
|
IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 ) THEN
|
|
INFO = -2
|
|
ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
|
|
INFO = -4
|
|
ELSE IF( LWORK.LT.MAX( 1, N-1 ) .AND. .NOT.LQUERY ) THEN
|
|
INFO = -7
|
|
END IF
|
|
*
|
|
IF( INFO.EQ.0 ) THEN
|
|
IF( UPPER ) THEN
|
|
NB = ILAENV( 1, 'DORGQL', ' ', N-1, N-1, N-1, -1 )
|
|
ELSE
|
|
NB = ILAENV( 1, 'DORGQR', ' ', N-1, N-1, N-1, -1 )
|
|
END IF
|
|
LWKOPT = MAX( 1, N-1 )*NB
|
|
WORK( 1 ) = LWKOPT
|
|
END IF
|
|
*
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DORGTR', -INFO )
|
|
RETURN
|
|
ELSE IF( LQUERY ) THEN
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.EQ.0 ) THEN
|
|
WORK( 1 ) = 1
|
|
RETURN
|
|
END IF
|
|
*
|
|
IF( UPPER ) THEN
|
|
*
|
|
* Q was determined by a call to DSYTRD with UPLO = 'U'
|
|
*
|
|
* Shift the vectors which define the elementary reflectors one
|
|
* column to the left, and set the last row and column of Q to
|
|
* those of the unit matrix
|
|
*
|
|
DO 20 J = 1, N - 1
|
|
DO 10 I = 1, J - 1
|
|
A( I, J ) = A( I, J+1 )
|
|
10 CONTINUE
|
|
A( N, J ) = ZERO
|
|
20 CONTINUE
|
|
DO 30 I = 1, N - 1
|
|
A( I, N ) = ZERO
|
|
30 CONTINUE
|
|
A( N, N ) = ONE
|
|
*
|
|
* Generate Q(1:n-1,1:n-1)
|
|
*
|
|
CALL DORGQL( N-1, N-1, N-1, A, LDA, TAU, WORK, LWORK, IINFO )
|
|
*
|
|
ELSE
|
|
*
|
|
* Q was determined by a call to DSYTRD with UPLO = 'L'.
|
|
*
|
|
* Shift the vectors which define the elementary reflectors one
|
|
* column to the right, and set the first row and column of Q to
|
|
* those of the unit matrix
|
|
*
|
|
DO 50 J = N, 2, -1
|
|
A( 1, J ) = ZERO
|
|
DO 40 I = J + 1, N
|
|
A( I, J ) = A( I, J-1 )
|
|
40 CONTINUE
|
|
50 CONTINUE
|
|
A( 1, 1 ) = ONE
|
|
DO 60 I = 2, N
|
|
A( I, 1 ) = ZERO
|
|
60 CONTINUE
|
|
IF( N.GT.1 ) THEN
|
|
*
|
|
* Generate Q(2:n,2:n)
|
|
*
|
|
CALL DORGQR( N-1, N-1, N-1, A( 2, 2 ), LDA, TAU, WORK,
|
|
$ LWORK, IINFO )
|
|
END IF
|
|
END IF
|
|
WORK( 1 ) = LWKOPT
|
|
RETURN
|
|
*
|
|
* End of DORGTR
|
|
*
|
|
END
|
|
SUBROUTINE DSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER COMPZ
|
|
INTEGER INFO, LDZ, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION D( * ), E( * ), WORK( * ), Z( LDZ, * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSTEQR computes all eigenvalues and, optionally, eigenvectors of a
|
|
* symmetric tridiagonal matrix using the implicit QL or QR method.
|
|
* The eigenvectors of a full or band symmetric matrix can also be found
|
|
* if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to
|
|
* tridiagonal form.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* COMPZ (input) CHARACTER*1
|
|
* = 'N': Compute eigenvalues only.
|
|
* = 'V': Compute eigenvalues and eigenvectors of the original
|
|
* symmetric matrix. On entry, Z must contain the
|
|
* orthogonal matrix used to reduce the original matrix
|
|
* to tridiagonal form.
|
|
* = 'I': Compute eigenvalues and eigenvectors of the
|
|
* tridiagonal matrix. Z is initialized to the identity
|
|
* matrix.
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the matrix. N >= 0.
|
|
*
|
|
* D (input/output) DOUBLE PRECISION 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) DOUBLE PRECISION array, dimension (N-1)
|
|
* On entry, the (n-1) subdiagonal elements of the tridiagonal
|
|
* matrix.
|
|
* On exit, E has been destroyed.
|
|
*
|
|
* Z (input/output) DOUBLE PRECISION array, dimension (LDZ, N)
|
|
* On entry, if COMPZ = 'V', then Z contains the orthogonal
|
|
* 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 symmetric 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, and if
|
|
* eigenvectors are desired, then LDZ >= max(1,N).
|
|
*
|
|
* WORK (workspace) DOUBLE PRECISION array, dimension (max(1,2*N-2))
|
|
* If COMPZ = 'N', then WORK is not referenced.
|
|
*
|
|
* INFO (output) INTEGER
|
|
* = 0: successful exit
|
|
* < 0: if INFO = -i, the i-th argument had an illegal value
|
|
* > 0: the algorithm has failed to find all the eigenvalues in
|
|
* a total of 30*N iterations; if INFO = i, then i
|
|
* elements of E have not converged to zero; on exit, D
|
|
* and E contain the elements of a symmetric tridiagonal
|
|
* matrix which is orthogonally similar to the original
|
|
* matrix.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, ONE, TWO, THREE
|
|
PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0, TWO = 2.0D0,
|
|
$ THREE = 3.0D0 )
|
|
INTEGER MAXIT
|
|
PARAMETER ( MAXIT = 30 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, ICOMPZ, II, ISCALE, J, JTOT, K, L, L1, LEND,
|
|
$ LENDM1, LENDP1, LENDSV, LM1, LSV, M, MM, MM1,
|
|
$ NM1, NMAXIT
|
|
DOUBLE PRECISION ANORM, B, C, EPS, EPS2, F, G, P, R, RT1, RT2,
|
|
$ S, SAFMAX, SAFMIN, SSFMAX, SSFMIN, TST
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
DOUBLE PRECISION DLAMCH, DLANST, DLAPY2
|
|
EXTERNAL LSAME, DLAMCH, DLANST, DLAPY2
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLAE2, DLAEV2, DLARTG, DLASCL, DLASET, DLASR,
|
|
$ DLASRT, DSWAP, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, MAX, SIGN, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
*
|
|
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( 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
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DSTEQR', -INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.EQ.0 )
|
|
$ RETURN
|
|
*
|
|
IF( N.EQ.1 ) THEN
|
|
IF( ICOMPZ.EQ.2 )
|
|
$ Z( 1, 1 ) = ONE
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Determine the unit roundoff and over/underflow thresholds.
|
|
*
|
|
EPS = DLAMCH( 'E' )
|
|
EPS2 = EPS**2
|
|
SAFMIN = DLAMCH( 'S' )
|
|
SAFMAX = ONE / SAFMIN
|
|
SSFMAX = SQRT( SAFMAX ) / THREE
|
|
SSFMIN = SQRT( SAFMIN ) / EPS2
|
|
*
|
|
* Compute the eigenvalues and eigenvectors of the tridiagonal
|
|
* matrix.
|
|
*
|
|
IF( ICOMPZ.EQ.2 )
|
|
$ CALL DLASET( 'Full', N, N, ZERO, ONE, Z, LDZ )
|
|
*
|
|
NMAXIT = N*MAXIT
|
|
JTOT = 0
|
|
*
|
|
* Determine where the matrix splits and choose QL or QR iteration
|
|
* for each block, according to whether top or bottom diagonal
|
|
* element is smaller.
|
|
*
|
|
L1 = 1
|
|
NM1 = N - 1
|
|
*
|
|
10 CONTINUE
|
|
IF( L1.GT.N )
|
|
$ GO TO 160
|
|
IF( L1.GT.1 )
|
|
$ E( L1-1 ) = ZERO
|
|
IF( L1.LE.NM1 ) THEN
|
|
DO 20 M = L1, NM1
|
|
TST = ABS( E( M ) )
|
|
IF( TST.EQ.ZERO )
|
|
$ GO TO 30
|
|
IF( TST.LE.( SQRT( ABS( D( M ) ) )*SQRT( ABS( D( M+
|
|
$ 1 ) ) ) )*EPS ) THEN
|
|
E( M ) = ZERO
|
|
GO TO 30
|
|
END IF
|
|
20 CONTINUE
|
|
END IF
|
|
M = N
|
|
*
|
|
30 CONTINUE
|
|
L = L1
|
|
LSV = L
|
|
LEND = M
|
|
LENDSV = LEND
|
|
L1 = M + 1
|
|
IF( LEND.EQ.L )
|
|
$ GO TO 10
|
|
*
|
|
* Scale submatrix in rows and columns L to LEND
|
|
*
|
|
ANORM = DLANST( 'I', LEND-L+1, D( L ), E( L ) )
|
|
ISCALE = 0
|
|
IF( ANORM.EQ.ZERO )
|
|
$ GO TO 10
|
|
IF( ANORM.GT.SSFMAX ) THEN
|
|
ISCALE = 1
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L+1, 1, D( L ), N,
|
|
$ INFO )
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L, 1, E( L ), N,
|
|
$ INFO )
|
|
ELSE IF( ANORM.LT.SSFMIN ) THEN
|
|
ISCALE = 2
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L+1, 1, D( L ), N,
|
|
$ INFO )
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L, 1, E( L ), N,
|
|
$ INFO )
|
|
END IF
|
|
*
|
|
* Choose between QL and QR iteration
|
|
*
|
|
IF( ABS( D( LEND ) ).LT.ABS( D( L ) ) ) THEN
|
|
LEND = LSV
|
|
L = LENDSV
|
|
END IF
|
|
*
|
|
IF( LEND.GT.L ) THEN
|
|
*
|
|
* QL Iteration
|
|
*
|
|
* Look for small subdiagonal element.
|
|
*
|
|
40 CONTINUE
|
|
IF( L.NE.LEND ) THEN
|
|
LENDM1 = LEND - 1
|
|
DO 50 M = L, LENDM1
|
|
TST = ABS( E( M ) )**2
|
|
IF( TST.LE.( EPS2*ABS( D( M ) ) )*ABS( D( M+1 ) )+
|
|
$ SAFMIN )GO TO 60
|
|
50 CONTINUE
|
|
END IF
|
|
*
|
|
M = LEND
|
|
*
|
|
60 CONTINUE
|
|
IF( M.LT.LEND )
|
|
$ E( M ) = ZERO
|
|
P = D( L )
|
|
IF( M.EQ.L )
|
|
$ GO TO 80
|
|
*
|
|
* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
|
|
* to compute its eigensystem.
|
|
*
|
|
IF( M.EQ.L+1 ) THEN
|
|
IF( ICOMPZ.GT.0 ) THEN
|
|
CALL DLAEV2( D( L ), E( L ), D( L+1 ), RT1, RT2, C, S )
|
|
WORK( L ) = C
|
|
WORK( N-1+L ) = S
|
|
CALL DLASR( 'R', 'V', 'B', N, 2, WORK( L ),
|
|
$ WORK( N-1+L ), Z( 1, L ), LDZ )
|
|
ELSE
|
|
CALL DLAE2( D( L ), E( L ), D( L+1 ), RT1, RT2 )
|
|
END IF
|
|
D( L ) = RT1
|
|
D( L+1 ) = RT2
|
|
E( L ) = ZERO
|
|
L = L + 2
|
|
IF( L.LE.LEND )
|
|
$ GO TO 40
|
|
GO TO 140
|
|
END IF
|
|
*
|
|
IF( JTOT.EQ.NMAXIT )
|
|
$ GO TO 140
|
|
JTOT = JTOT + 1
|
|
*
|
|
* Form shift.
|
|
*
|
|
G = ( D( L+1 )-P ) / ( TWO*E( L ) )
|
|
R = DLAPY2( G, ONE )
|
|
G = D( M ) - P + ( E( L ) / ( G+SIGN( R, G ) ) )
|
|
*
|
|
S = ONE
|
|
C = ONE
|
|
P = ZERO
|
|
*
|
|
* Inner loop
|
|
*
|
|
MM1 = M - 1
|
|
DO 70 I = MM1, L, -1
|
|
F = S*E( I )
|
|
B = C*E( I )
|
|
CALL DLARTG( G, F, C, S, R )
|
|
IF( I.NE.M-1 )
|
|
$ E( I+1 ) = R
|
|
G = D( I+1 ) - P
|
|
R = ( D( I )-G )*S + TWO*C*B
|
|
P = S*R
|
|
D( I+1 ) = G + P
|
|
G = C*R - B
|
|
*
|
|
* If eigenvectors are desired, then save rotations.
|
|
*
|
|
IF( ICOMPZ.GT.0 ) THEN
|
|
WORK( I ) = C
|
|
WORK( N-1+I ) = -S
|
|
END IF
|
|
*
|
|
70 CONTINUE
|
|
*
|
|
* If eigenvectors are desired, then apply saved rotations.
|
|
*
|
|
IF( ICOMPZ.GT.0 ) THEN
|
|
MM = M - L + 1
|
|
CALL DLASR( 'R', 'V', 'B', N, MM, WORK( L ), WORK( N-1+L ),
|
|
$ Z( 1, L ), LDZ )
|
|
END IF
|
|
*
|
|
D( L ) = D( L ) - P
|
|
E( L ) = G
|
|
GO TO 40
|
|
*
|
|
* Eigenvalue found.
|
|
*
|
|
80 CONTINUE
|
|
D( L ) = P
|
|
*
|
|
L = L + 1
|
|
IF( L.LE.LEND )
|
|
$ GO TO 40
|
|
GO TO 140
|
|
*
|
|
ELSE
|
|
*
|
|
* QR Iteration
|
|
*
|
|
* Look for small superdiagonal element.
|
|
*
|
|
90 CONTINUE
|
|
IF( L.NE.LEND ) THEN
|
|
LENDP1 = LEND + 1
|
|
DO 100 M = L, LENDP1, -1
|
|
TST = ABS( E( M-1 ) )**2
|
|
IF( TST.LE.( EPS2*ABS( D( M ) ) )*ABS( D( M-1 ) )+
|
|
$ SAFMIN )GO TO 110
|
|
100 CONTINUE
|
|
END IF
|
|
*
|
|
M = LEND
|
|
*
|
|
110 CONTINUE
|
|
IF( M.GT.LEND )
|
|
$ E( M-1 ) = ZERO
|
|
P = D( L )
|
|
IF( M.EQ.L )
|
|
$ GO TO 130
|
|
*
|
|
* If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
|
|
* to compute its eigensystem.
|
|
*
|
|
IF( M.EQ.L-1 ) THEN
|
|
IF( ICOMPZ.GT.0 ) THEN
|
|
CALL DLAEV2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2, C, S )
|
|
WORK( M ) = C
|
|
WORK( N-1+M ) = S
|
|
CALL DLASR( 'R', 'V', 'F', N, 2, WORK( M ),
|
|
$ WORK( N-1+M ), Z( 1, L-1 ), LDZ )
|
|
ELSE
|
|
CALL DLAE2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2 )
|
|
END IF
|
|
D( L-1 ) = RT1
|
|
D( L ) = RT2
|
|
E( L-1 ) = ZERO
|
|
L = L - 2
|
|
IF( L.GE.LEND )
|
|
$ GO TO 90
|
|
GO TO 140
|
|
END IF
|
|
*
|
|
IF( JTOT.EQ.NMAXIT )
|
|
$ GO TO 140
|
|
JTOT = JTOT + 1
|
|
*
|
|
* Form shift.
|
|
*
|
|
G = ( D( L-1 )-P ) / ( TWO*E( L-1 ) )
|
|
R = DLAPY2( G, ONE )
|
|
G = D( M ) - P + ( E( L-1 ) / ( G+SIGN( R, G ) ) )
|
|
*
|
|
S = ONE
|
|
C = ONE
|
|
P = ZERO
|
|
*
|
|
* Inner loop
|
|
*
|
|
LM1 = L - 1
|
|
DO 120 I = M, LM1
|
|
F = S*E( I )
|
|
B = C*E( I )
|
|
CALL DLARTG( G, F, C, S, R )
|
|
IF( I.NE.M )
|
|
$ E( I-1 ) = R
|
|
G = D( I ) - P
|
|
R = ( D( I+1 )-G )*S + TWO*C*B
|
|
P = S*R
|
|
D( I ) = G + P
|
|
G = C*R - B
|
|
*
|
|
* If eigenvectors are desired, then save rotations.
|
|
*
|
|
IF( ICOMPZ.GT.0 ) THEN
|
|
WORK( I ) = C
|
|
WORK( N-1+I ) = S
|
|
END IF
|
|
*
|
|
120 CONTINUE
|
|
*
|
|
* If eigenvectors are desired, then apply saved rotations.
|
|
*
|
|
IF( ICOMPZ.GT.0 ) THEN
|
|
MM = L - M + 1
|
|
CALL DLASR( 'R', 'V', 'F', N, MM, WORK( M ), WORK( N-1+M ),
|
|
$ Z( 1, M ), LDZ )
|
|
END IF
|
|
*
|
|
D( L ) = D( L ) - P
|
|
E( LM1 ) = G
|
|
GO TO 90
|
|
*
|
|
* Eigenvalue found.
|
|
*
|
|
130 CONTINUE
|
|
D( L ) = P
|
|
*
|
|
L = L - 1
|
|
IF( L.GE.LEND )
|
|
$ GO TO 90
|
|
GO TO 140
|
|
*
|
|
END IF
|
|
*
|
|
* Undo scaling if necessary
|
|
*
|
|
140 CONTINUE
|
|
IF( ISCALE.EQ.1 ) THEN
|
|
CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV+1, 1,
|
|
$ D( LSV ), N, INFO )
|
|
CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV, 1, E( LSV ),
|
|
$ N, INFO )
|
|
ELSE IF( ISCALE.EQ.2 ) THEN
|
|
CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV+1, 1,
|
|
$ D( LSV ), N, INFO )
|
|
CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV, 1, E( LSV ),
|
|
$ N, INFO )
|
|
END IF
|
|
*
|
|
* Check for no convergence to an eigenvalue after a total
|
|
* of N*MAXIT iterations.
|
|
*
|
|
IF( JTOT.LT.NMAXIT )
|
|
$ GO TO 10
|
|
DO 150 I = 1, N - 1
|
|
IF( E( I ).NE.ZERO )
|
|
$ INFO = INFO + 1
|
|
150 CONTINUE
|
|
GO TO 190
|
|
*
|
|
* Order eigenvalues and eigenvectors.
|
|
*
|
|
160 CONTINUE
|
|
IF( ICOMPZ.EQ.0 ) THEN
|
|
*
|
|
* Use Quick Sort
|
|
*
|
|
CALL DLASRT( 'I', N, D, INFO )
|
|
*
|
|
ELSE
|
|
*
|
|
* Use Selection Sort to minimize swaps of eigenvectors
|
|
*
|
|
DO 180 II = 2, N
|
|
I = II - 1
|
|
K = I
|
|
P = D( I )
|
|
DO 170 J = II, N
|
|
IF( D( J ).LT.P ) THEN
|
|
K = J
|
|
P = D( J )
|
|
END IF
|
|
170 CONTINUE
|
|
IF( K.NE.I ) THEN
|
|
D( K ) = D( I )
|
|
D( I ) = P
|
|
CALL DSWAP( N, Z( 1, I ), 1, Z( 1, K ), 1 )
|
|
END IF
|
|
180 CONTINUE
|
|
END IF
|
|
*
|
|
190 CONTINUE
|
|
RETURN
|
|
*
|
|
* End of DSTEQR
|
|
*
|
|
END
|
|
SUBROUTINE DSTERF( N, D, E, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER INFO, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION D( * ), E( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSTERF computes all eigenvalues of a symmetric tridiagonal matrix
|
|
* using the Pal-Walker-Kahan variant of the QL or QR algorithm.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* N (input) INTEGER
|
|
* The order of the matrix. N >= 0.
|
|
*
|
|
* D (input/output) DOUBLE PRECISION array, dimension (N)
|
|
* On entry, the n diagonal elements of the tridiagonal matrix.
|
|
* On exit, if INFO = 0, the eigenvalues in ascending order.
|
|
*
|
|
* E (input/output) DOUBLE PRECISION array, dimension (N-1)
|
|
* On entry, the (n-1) subdiagonal elements of the tridiagonal
|
|
* matrix.
|
|
* On exit, E has been destroyed.
|
|
*
|
|
* INFO (output) INTEGER
|
|
* = 0: successful exit
|
|
* < 0: if INFO = -i, the i-th argument had an illegal value
|
|
* > 0: the algorithm failed to find all of the eigenvalues in
|
|
* a total of 30*N iterations; if INFO = i, then i
|
|
* elements of E have not converged to zero.
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, ONE, TWO, THREE
|
|
PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0, TWO = 2.0D0,
|
|
$ THREE = 3.0D0 )
|
|
INTEGER MAXIT
|
|
PARAMETER ( MAXIT = 30 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER I, ISCALE, JTOT, L, L1, LEND, LENDSV, LSV, M,
|
|
$ NMAXIT
|
|
DOUBLE PRECISION ALPHA, ANORM, BB, C, EPS, EPS2, GAMMA, OLDC,
|
|
$ OLDGAM, P, R, RT1, RT2, RTE, S, SAFMAX, SAFMIN,
|
|
$ SIGMA, SSFMAX, SSFMIN
|
|
* ..
|
|
* .. External Functions ..
|
|
DOUBLE PRECISION DLAMCH, DLANST, DLAPY2
|
|
EXTERNAL DLAMCH, DLANST, DLAPY2
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLAE2, DLASCL, DLASRT, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC ABS, SIGN, SQRT
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters.
|
|
*
|
|
INFO = 0
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LT.0 ) THEN
|
|
INFO = -1
|
|
CALL XERBLA( 'DSTERF', -INFO )
|
|
RETURN
|
|
END IF
|
|
IF( N.LE.1 )
|
|
$ RETURN
|
|
*
|
|
* Determine the unit roundoff for this environment.
|
|
*
|
|
EPS = DLAMCH( 'E' )
|
|
EPS2 = EPS**2
|
|
SAFMIN = DLAMCH( 'S' )
|
|
SAFMAX = ONE / SAFMIN
|
|
SSFMAX = SQRT( SAFMAX ) / THREE
|
|
SSFMIN = SQRT( SAFMIN ) / EPS2
|
|
*
|
|
* Compute the eigenvalues of the tridiagonal matrix.
|
|
*
|
|
NMAXIT = N*MAXIT
|
|
SIGMA = ZERO
|
|
JTOT = 0
|
|
*
|
|
* Determine where the matrix splits and choose QL or QR iteration
|
|
* for each block, according to whether top or bottom diagonal
|
|
* element is smaller.
|
|
*
|
|
L1 = 1
|
|
*
|
|
10 CONTINUE
|
|
IF( L1.GT.N )
|
|
$ GO TO 170
|
|
IF( L1.GT.1 )
|
|
$ E( L1-1 ) = ZERO
|
|
DO 20 M = L1, N - 1
|
|
IF( ABS( E( M ) ).LE.( SQRT( ABS( D( M ) ) )*SQRT( ABS( D( M+
|
|
$ 1 ) ) ) )*EPS ) THEN
|
|
E( M ) = ZERO
|
|
GO TO 30
|
|
END IF
|
|
20 CONTINUE
|
|
M = N
|
|
*
|
|
30 CONTINUE
|
|
L = L1
|
|
LSV = L
|
|
LEND = M
|
|
LENDSV = LEND
|
|
L1 = M + 1
|
|
IF( LEND.EQ.L )
|
|
$ GO TO 10
|
|
*
|
|
* Scale submatrix in rows and columns L to LEND
|
|
*
|
|
ANORM = DLANST( 'I', LEND-L+1, D( L ), E( L ) )
|
|
ISCALE = 0
|
|
IF( ANORM.GT.SSFMAX ) THEN
|
|
ISCALE = 1
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L+1, 1, D( L ), N,
|
|
$ INFO )
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L, 1, E( L ), N,
|
|
$ INFO )
|
|
ELSE IF( ANORM.LT.SSFMIN ) THEN
|
|
ISCALE = 2
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L+1, 1, D( L ), N,
|
|
$ INFO )
|
|
CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L, 1, E( L ), N,
|
|
$ INFO )
|
|
END IF
|
|
*
|
|
DO 40 I = L, LEND - 1
|
|
E( I ) = E( I )**2
|
|
40 CONTINUE
|
|
*
|
|
* Choose between QL and QR iteration
|
|
*
|
|
IF( ABS( D( LEND ) ).LT.ABS( D( L ) ) ) THEN
|
|
LEND = LSV
|
|
L = LENDSV
|
|
END IF
|
|
*
|
|
IF( LEND.GE.L ) THEN
|
|
*
|
|
* QL Iteration
|
|
*
|
|
* Look for small subdiagonal element.
|
|
*
|
|
50 CONTINUE
|
|
IF( L.NE.LEND ) THEN
|
|
DO 60 M = L, LEND - 1
|
|
IF( ABS( E( M ) ).LE.EPS2*ABS( D( M )*D( M+1 ) ) )
|
|
$ GO TO 70
|
|
60 CONTINUE
|
|
END IF
|
|
M = LEND
|
|
*
|
|
70 CONTINUE
|
|
IF( M.LT.LEND )
|
|
$ E( M ) = ZERO
|
|
P = D( L )
|
|
IF( M.EQ.L )
|
|
$ GO TO 90
|
|
*
|
|
* If remaining matrix is 2 by 2, use DLAE2 to compute its
|
|
* eigenvalues.
|
|
*
|
|
IF( M.EQ.L+1 ) THEN
|
|
RTE = SQRT( E( L ) )
|
|
CALL DLAE2( D( L ), RTE, D( L+1 ), RT1, RT2 )
|
|
D( L ) = RT1
|
|
D( L+1 ) = RT2
|
|
E( L ) = ZERO
|
|
L = L + 2
|
|
IF( L.LE.LEND )
|
|
$ GO TO 50
|
|
GO TO 150
|
|
END IF
|
|
*
|
|
IF( JTOT.EQ.NMAXIT )
|
|
$ GO TO 150
|
|
JTOT = JTOT + 1
|
|
*
|
|
* Form shift.
|
|
*
|
|
RTE = SQRT( E( L ) )
|
|
SIGMA = ( D( L+1 )-P ) / ( TWO*RTE )
|
|
R = DLAPY2( SIGMA, ONE )
|
|
SIGMA = P - ( RTE / ( SIGMA+SIGN( R, SIGMA ) ) )
|
|
*
|
|
C = ONE
|
|
S = ZERO
|
|
GAMMA = D( M ) - SIGMA
|
|
P = GAMMA*GAMMA
|
|
*
|
|
* Inner loop
|
|
*
|
|
DO 80 I = M - 1, L, -1
|
|
BB = E( I )
|
|
R = P + BB
|
|
IF( I.NE.M-1 )
|
|
$ E( I+1 ) = S*R
|
|
OLDC = C
|
|
C = P / R
|
|
S = BB / R
|
|
OLDGAM = GAMMA
|
|
ALPHA = D( I )
|
|
GAMMA = C*( ALPHA-SIGMA ) - S*OLDGAM
|
|
D( I+1 ) = OLDGAM + ( ALPHA-GAMMA )
|
|
IF( C.NE.ZERO ) THEN
|
|
P = ( GAMMA*GAMMA ) / C
|
|
ELSE
|
|
P = OLDC*BB
|
|
END IF
|
|
80 CONTINUE
|
|
*
|
|
E( L ) = S*P
|
|
D( L ) = SIGMA + GAMMA
|
|
GO TO 50
|
|
*
|
|
* Eigenvalue found.
|
|
*
|
|
90 CONTINUE
|
|
D( L ) = P
|
|
*
|
|
L = L + 1
|
|
IF( L.LE.LEND )
|
|
$ GO TO 50
|
|
GO TO 150
|
|
*
|
|
ELSE
|
|
*
|
|
* QR Iteration
|
|
*
|
|
* Look for small superdiagonal element.
|
|
*
|
|
100 CONTINUE
|
|
DO 110 M = L, LEND + 1, -1
|
|
IF( ABS( E( M-1 ) ).LE.EPS2*ABS( D( M )*D( M-1 ) ) )
|
|
$ GO TO 120
|
|
110 CONTINUE
|
|
M = LEND
|
|
*
|
|
120 CONTINUE
|
|
IF( M.GT.LEND )
|
|
$ E( M-1 ) = ZERO
|
|
P = D( L )
|
|
IF( M.EQ.L )
|
|
$ GO TO 140
|
|
*
|
|
* If remaining matrix is 2 by 2, use DLAE2 to compute its
|
|
* eigenvalues.
|
|
*
|
|
IF( M.EQ.L-1 ) THEN
|
|
RTE = SQRT( E( L-1 ) )
|
|
CALL DLAE2( D( L ), RTE, D( L-1 ), RT1, RT2 )
|
|
D( L ) = RT1
|
|
D( L-1 ) = RT2
|
|
E( L-1 ) = ZERO
|
|
L = L - 2
|
|
IF( L.GE.LEND )
|
|
$ GO TO 100
|
|
GO TO 150
|
|
END IF
|
|
*
|
|
IF( JTOT.EQ.NMAXIT )
|
|
$ GO TO 150
|
|
JTOT = JTOT + 1
|
|
*
|
|
* Form shift.
|
|
*
|
|
RTE = SQRT( E( L-1 ) )
|
|
SIGMA = ( D( L-1 )-P ) / ( TWO*RTE )
|
|
R = DLAPY2( SIGMA, ONE )
|
|
SIGMA = P - ( RTE / ( SIGMA+SIGN( R, SIGMA ) ) )
|
|
*
|
|
C = ONE
|
|
S = ZERO
|
|
GAMMA = D( M ) - SIGMA
|
|
P = GAMMA*GAMMA
|
|
*
|
|
* Inner loop
|
|
*
|
|
DO 130 I = M, L - 1
|
|
BB = E( I )
|
|
R = P + BB
|
|
IF( I.NE.M )
|
|
$ E( I-1 ) = S*R
|
|
OLDC = C
|
|
C = P / R
|
|
S = BB / R
|
|
OLDGAM = GAMMA
|
|
ALPHA = D( I+1 )
|
|
GAMMA = C*( ALPHA-SIGMA ) - S*OLDGAM
|
|
D( I ) = OLDGAM + ( ALPHA-GAMMA )
|
|
IF( C.NE.ZERO ) THEN
|
|
P = ( GAMMA*GAMMA ) / C
|
|
ELSE
|
|
P = OLDC*BB
|
|
END IF
|
|
130 CONTINUE
|
|
*
|
|
E( L-1 ) = S*P
|
|
D( L ) = SIGMA + GAMMA
|
|
GO TO 100
|
|
*
|
|
* Eigenvalue found.
|
|
*
|
|
140 CONTINUE
|
|
D( L ) = P
|
|
*
|
|
L = L - 1
|
|
IF( L.GE.LEND )
|
|
$ GO TO 100
|
|
GO TO 150
|
|
*
|
|
END IF
|
|
*
|
|
* Undo scaling if necessary
|
|
*
|
|
150 CONTINUE
|
|
IF( ISCALE.EQ.1 )
|
|
$ CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV+1, 1,
|
|
$ D( LSV ), N, INFO )
|
|
IF( ISCALE.EQ.2 )
|
|
$ CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV+1, 1,
|
|
$ D( LSV ), N, INFO )
|
|
*
|
|
* Check for no convergence to an eigenvalue after a total
|
|
* of N*MAXIT iterations.
|
|
*
|
|
IF( JTOT.LT.NMAXIT )
|
|
$ GO TO 10
|
|
DO 160 I = 1, N - 1
|
|
IF( E( I ).NE.ZERO )
|
|
$ INFO = INFO + 1
|
|
160 CONTINUE
|
|
GO TO 180
|
|
*
|
|
* Sort eigenvalues in increasing order.
|
|
*
|
|
170 CONTINUE
|
|
CALL DLASRT( 'I', N, D, INFO )
|
|
*
|
|
180 CONTINUE
|
|
RETURN
|
|
*
|
|
* End of DSTERF
|
|
*
|
|
END
|
|
|
|
SUBROUTINE DSYTD2( UPLO, N, A, LDA, D, E, TAU, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER UPLO
|
|
INTEGER INFO, LDA, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAU( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSYTD2 reduces a real symmetric matrix A to symmetric tridiagonal
|
|
* form T by an orthogonal similarity transformation: Q' * A * Q = T.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* UPLO (input) CHARACTER*1
|
|
* Specifies whether the upper or lower triangular part of the
|
|
* symmetric matrix A is stored:
|
|
* = 'U': Upper triangular
|
|
* = 'L': Lower triangular
|
|
*
|
|
* 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, and the strictly lower
|
|
* triangular part of A is not referenced. If UPLO = 'L', the
|
|
* leading n-by-n lower triangular part of A contains the lower
|
|
* triangular part of the matrix A, and the strictly upper
|
|
* triangular part of A is not referenced.
|
|
* On exit, if UPLO = 'U', the diagonal and first superdiagonal
|
|
* of A are overwritten by the corresponding elements of the
|
|
* tridiagonal matrix T, and the elements above the first
|
|
* superdiagonal, with the array TAU, represent the orthogonal
|
|
* matrix Q as a product of elementary reflectors; if UPLO
|
|
* = 'L', the diagonal and first subdiagonal of A are over-
|
|
* written by the corresponding elements of the tridiagonal
|
|
* matrix T, and the elements below the first subdiagonal, with
|
|
* the array TAU, represent the orthogonal matrix Q as a product
|
|
* of elementary reflectors. See Further Details.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(1,N).
|
|
*
|
|
* D (output) DOUBLE PRECISION array, dimension (N)
|
|
* The diagonal elements of the tridiagonal matrix T:
|
|
* D(i) = A(i,i).
|
|
*
|
|
* E (output) DOUBLE PRECISION array, dimension (N-1)
|
|
* The off-diagonal elements of the tridiagonal matrix T:
|
|
* E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'.
|
|
*
|
|
* TAU (output) DOUBLE PRECISION array, dimension (N-1)
|
|
* The scalar factors of the elementary reflectors (see Further
|
|
* Details).
|
|
*
|
|
* INFO (output) INTEGER
|
|
* = 0: successful exit
|
|
* < 0: if INFO = -i, the i-th argument had an illegal value.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* If UPLO = 'U', the matrix Q is represented as a product of elementary
|
|
* reflectors
|
|
*
|
|
* Q = H(n-1) . . . H(2) H(1).
|
|
*
|
|
* Each H(i) has the form
|
|
*
|
|
* H(i) = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar, and v is a real vector with
|
|
* v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in
|
|
* A(1:i-1,i+1), and tau in TAU(i).
|
|
*
|
|
* If UPLO = 'L', the matrix Q is represented as a product of elementary
|
|
* reflectors
|
|
*
|
|
* Q = H(1) H(2) . . . H(n-1).
|
|
*
|
|
* Each H(i) has the form
|
|
*
|
|
* H(i) = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar, and v is a real vector with
|
|
* v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i),
|
|
* and tau in TAU(i).
|
|
*
|
|
* The contents of A on exit are illustrated by the following examples
|
|
* with n = 5:
|
|
*
|
|
* if UPLO = 'U': if UPLO = 'L':
|
|
*
|
|
* ( d e v2 v3 v4 ) ( d )
|
|
* ( d e v3 v4 ) ( e d )
|
|
* ( d e v4 ) ( v1 e d )
|
|
* ( d e ) ( v1 v2 e d )
|
|
* ( d ) ( v1 v2 v3 e d )
|
|
*
|
|
* where d and e denote diagonal and off-diagonal elements of T, and vi
|
|
* denotes an element of the vector defining H(i).
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE, ZERO, HALF
|
|
PARAMETER ( ONE = 1.0D0, ZERO = 0.0D0,
|
|
$ HALF = 1.0D0 / 2.0D0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL UPPER
|
|
INTEGER I
|
|
DOUBLE PRECISION ALPHA, TAUI
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DAXPY, DLARFG, DSYMV, DSYR2, XERBLA
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
DOUBLE PRECISION DDOT
|
|
EXTERNAL LSAME, DDOT
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX, MIN
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters
|
|
*
|
|
INFO = 0
|
|
UPPER = LSAME( UPLO, 'U' )
|
|
IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 ) THEN
|
|
INFO = -2
|
|
ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
|
|
INFO = -4
|
|
END IF
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DSYTD2', -INFO )
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.LE.0 )
|
|
$ RETURN
|
|
*
|
|
IF( UPPER ) THEN
|
|
*
|
|
* Reduce the upper triangle of A
|
|
*
|
|
DO 10 I = N - 1, 1, -1
|
|
*
|
|
* Generate elementary reflector H(i) = I - tau * v * v'
|
|
* to annihilate A(1:i-1,i+1)
|
|
*
|
|
CALL DLARFG( I, A( I, I+1 ), A( 1, I+1 ), 1, TAUI )
|
|
E( I ) = A( I, I+1 )
|
|
*
|
|
IF( TAUI.NE.ZERO ) THEN
|
|
*
|
|
* Apply H(i) from both sides to A(1:i,1:i)
|
|
*
|
|
A( I, I+1 ) = ONE
|
|
*
|
|
* Compute x := tau * A * v storing x in TAU(1:i)
|
|
*
|
|
CALL DSYMV( UPLO, I, TAUI, A, LDA, A( 1, I+1 ), 1, ZERO,
|
|
$ TAU, 1 )
|
|
*
|
|
* Compute w := x - 1/2 * tau * (x'*v) * v
|
|
*
|
|
ALPHA = -HALF*TAUI*DDOT( I, TAU, 1, A( 1, I+1 ), 1 )
|
|
CALL DAXPY( I, ALPHA, A( 1, I+1 ), 1, TAU, 1 )
|
|
*
|
|
* Apply the transformation as a rank-2 update:
|
|
* A := A - v * w' - w * v'
|
|
*
|
|
CALL DSYR2( UPLO, I, -ONE, A( 1, I+1 ), 1, TAU, 1, A,
|
|
$ LDA )
|
|
*
|
|
A( I, I+1 ) = E( I )
|
|
END IF
|
|
D( I+1 ) = A( I+1, I+1 )
|
|
TAU( I ) = TAUI
|
|
10 CONTINUE
|
|
D( 1 ) = A( 1, 1 )
|
|
ELSE
|
|
*
|
|
* Reduce the lower triangle of A
|
|
*
|
|
DO 20 I = 1, N - 1
|
|
*
|
|
* Generate elementary reflector H(i) = I - tau * v * v'
|
|
* to annihilate A(i+2:n,i)
|
|
*
|
|
CALL DLARFG( N-I, A( I+1, I ), A( MIN( I+2, N ), I ), 1,
|
|
$ TAUI )
|
|
E( I ) = A( I+1, I )
|
|
*
|
|
IF( TAUI.NE.ZERO ) THEN
|
|
*
|
|
* Apply H(i) from both sides to A(i+1:n,i+1:n)
|
|
*
|
|
A( I+1, I ) = ONE
|
|
*
|
|
* Compute x := tau * A * v storing y in TAU(i:n-1)
|
|
*
|
|
CALL DSYMV( UPLO, N-I, TAUI, A( I+1, I+1 ), LDA,
|
|
$ A( I+1, I ), 1, ZERO, TAU( I ), 1 )
|
|
*
|
|
* Compute w := x - 1/2 * tau * (x'*v) * v
|
|
*
|
|
ALPHA = -HALF*TAUI*DDOT( N-I, TAU( I ), 1, A( I+1, I ),
|
|
$ 1 )
|
|
CALL DAXPY( N-I, ALPHA, A( I+1, I ), 1, TAU( I ), 1 )
|
|
*
|
|
* Apply the transformation as a rank-2 update:
|
|
* A := A - v * w' - w * v'
|
|
*
|
|
CALL DSYR2( UPLO, N-I, -ONE, A( I+1, I ), 1, TAU( I ), 1,
|
|
$ A( I+1, I+1 ), LDA )
|
|
*
|
|
A( I+1, I ) = E( I )
|
|
END IF
|
|
D( I ) = A( I, I )
|
|
TAU( I ) = TAUI
|
|
20 CONTINUE
|
|
D( N ) = A( N, N )
|
|
END IF
|
|
*
|
|
RETURN
|
|
*
|
|
* End of DSYTD2
|
|
*
|
|
END
|
|
SUBROUTINE DSYTRD( UPLO, N, A, LDA, D, E, TAU, WORK, LWORK, INFO )
|
|
*
|
|
* -- LAPACK routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER UPLO
|
|
INTEGER INFO, LDA, LWORK, N
|
|
* ..
|
|
* .. Array Arguments ..
|
|
DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAU( * ),
|
|
$ WORK( * )
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* DSYTRD reduces a real symmetric matrix A to real symmetric
|
|
* tridiagonal form T by an orthogonal similarity transformation:
|
|
* Q**T * A * Q = T.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* 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, and the strictly lower
|
|
* triangular part of A is not referenced. If UPLO = 'L', the
|
|
* leading N-by-N lower triangular part of A contains the lower
|
|
* triangular part of the matrix A, and the strictly upper
|
|
* triangular part of A is not referenced.
|
|
* On exit, if UPLO = 'U', the diagonal and first superdiagonal
|
|
* of A are overwritten by the corresponding elements of the
|
|
* tridiagonal matrix T, and the elements above the first
|
|
* superdiagonal, with the array TAU, represent the orthogonal
|
|
* matrix Q as a product of elementary reflectors; if UPLO
|
|
* = 'L', the diagonal and first subdiagonal of A are over-
|
|
* written by the corresponding elements of the tridiagonal
|
|
* matrix T, and the elements below the first subdiagonal, with
|
|
* the array TAU, represent the orthogonal matrix Q as a product
|
|
* of elementary reflectors. See Further Details.
|
|
*
|
|
* LDA (input) INTEGER
|
|
* The leading dimension of the array A. LDA >= max(1,N).
|
|
*
|
|
* D (output) DOUBLE PRECISION array, dimension (N)
|
|
* The diagonal elements of the tridiagonal matrix T:
|
|
* D(i) = A(i,i).
|
|
*
|
|
* E (output) DOUBLE PRECISION array, dimension (N-1)
|
|
* The off-diagonal elements of the tridiagonal matrix T:
|
|
* E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'.
|
|
*
|
|
* TAU (output) DOUBLE PRECISION array, dimension (N-1)
|
|
* The scalar factors of the elementary reflectors (see Further
|
|
* Details).
|
|
*
|
|
* 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 dimension of the array WORK. LWORK >= 1.
|
|
* For optimum performance LWORK >= N*NB, where NB is the
|
|
* optimal blocksize.
|
|
*
|
|
* 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
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* If UPLO = 'U', the matrix Q is represented as a product of elementary
|
|
* reflectors
|
|
*
|
|
* Q = H(n-1) . . . H(2) H(1).
|
|
*
|
|
* Each H(i) has the form
|
|
*
|
|
* H(i) = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar, and v is a real vector with
|
|
* v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in
|
|
* A(1:i-1,i+1), and tau in TAU(i).
|
|
*
|
|
* If UPLO = 'L', the matrix Q is represented as a product of elementary
|
|
* reflectors
|
|
*
|
|
* Q = H(1) H(2) . . . H(n-1).
|
|
*
|
|
* Each H(i) has the form
|
|
*
|
|
* H(i) = I - tau * v * v'
|
|
*
|
|
* where tau is a real scalar, and v is a real vector with
|
|
* v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i),
|
|
* and tau in TAU(i).
|
|
*
|
|
* The contents of A on exit are illustrated by the following examples
|
|
* with n = 5:
|
|
*
|
|
* if UPLO = 'U': if UPLO = 'L':
|
|
*
|
|
* ( d e v2 v3 v4 ) ( d )
|
|
* ( d e v3 v4 ) ( e d )
|
|
* ( d e v4 ) ( v1 e d )
|
|
* ( d e ) ( v1 v2 e d )
|
|
* ( d ) ( v1 v2 v3 e d )
|
|
*
|
|
* where d and e denote diagonal and off-diagonal elements of T, and vi
|
|
* denotes an element of the vector defining H(i).
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ONE
|
|
PARAMETER ( ONE = 1.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL LQUERY, UPPER
|
|
INTEGER I, IINFO, IWS, J, KK, LDWORK, LWKOPT, NB,
|
|
$ NBMIN, NX
|
|
* ..
|
|
* .. External Subroutines ..
|
|
EXTERNAL DLATRD, DSYR2K, DSYTD2, XERBLA
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC MAX
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL LSAME
|
|
INTEGER ILAENV
|
|
EXTERNAL LSAME, ILAENV
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input parameters
|
|
*
|
|
INFO = 0
|
|
UPPER = LSAME( UPLO, 'U' )
|
|
LQUERY = ( LWORK.EQ.-1 )
|
|
IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN
|
|
INFO = -1
|
|
ELSE IF( N.LT.0 ) THEN
|
|
INFO = -2
|
|
ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
|
|
INFO = -4
|
|
ELSE IF( LWORK.LT.1 .AND. .NOT.LQUERY ) THEN
|
|
INFO = -9
|
|
END IF
|
|
*
|
|
IF( INFO.EQ.0 ) THEN
|
|
*
|
|
* Determine the block size.
|
|
*
|
|
NB = ILAENV( 1, 'DSYTRD', UPLO, N, -1, -1, -1 )
|
|
LWKOPT = N*NB
|
|
WORK( 1 ) = LWKOPT
|
|
END IF
|
|
*
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DSYTRD', -INFO )
|
|
RETURN
|
|
ELSE IF( LQUERY ) THEN
|
|
RETURN
|
|
END IF
|
|
*
|
|
* Quick return if possible
|
|
*
|
|
IF( N.EQ.0 ) THEN
|
|
WORK( 1 ) = 1
|
|
RETURN
|
|
END IF
|
|
*
|
|
NX = N
|
|
IWS = 1
|
|
IF( NB.GT.1 .AND. NB.LT.N ) THEN
|
|
*
|
|
* Determine when to cross over from blocked to unblocked code
|
|
* (last block is always handled by unblocked code).
|
|
*
|
|
NX = MAX( NB, ILAENV( 3, 'DSYTRD', UPLO, N, -1, -1, -1 ) )
|
|
IF( NX.LT.N ) THEN
|
|
*
|
|
* Determine if workspace is large enough for blocked code.
|
|
*
|
|
LDWORK = N
|
|
IWS = LDWORK*NB
|
|
IF( LWORK.LT.IWS ) THEN
|
|
*
|
|
* Not enough workspace to use optimal NB: determine the
|
|
* minimum value of NB, and reduce NB or force use of
|
|
* unblocked code by setting NX = N.
|
|
*
|
|
NB = MAX( LWORK / LDWORK, 1 )
|
|
NBMIN = ILAENV( 2, 'DSYTRD', UPLO, N, -1, -1, -1 )
|
|
IF( NB.LT.NBMIN )
|
|
$ NX = N
|
|
END IF
|
|
ELSE
|
|
NX = N
|
|
END IF
|
|
ELSE
|
|
NB = 1
|
|
END IF
|
|
*
|
|
IF( UPPER ) THEN
|
|
*
|
|
* Reduce the upper triangle of A.
|
|
* Columns 1:kk are handled by the unblocked method.
|
|
*
|
|
KK = N - ( ( N-NX+NB-1 ) / NB )*NB
|
|
DO 20 I = N - NB + 1, KK + 1, -NB
|
|
*
|
|
* Reduce columns i:i+nb-1 to tridiagonal form and form the
|
|
* matrix W which is needed to update the unreduced part of
|
|
* the matrix
|
|
*
|
|
CALL DLATRD( UPLO, I+NB-1, NB, A, LDA, E, TAU, WORK,
|
|
$ LDWORK )
|
|
*
|
|
* Update the unreduced submatrix A(1:i-1,1:i-1), using an
|
|
* update of the form: A := A - V*W' - W*V'
|
|
*
|
|
CALL DSYR2K( UPLO, 'No transpose', I-1, NB, -ONE, A( 1, I ),
|
|
$ LDA, WORK, LDWORK, ONE, A, LDA )
|
|
*
|
|
* Copy superdiagonal elements back into A, and diagonal
|
|
* elements into D
|
|
*
|
|
DO 10 J = I, I + NB - 1
|
|
A( J-1, J ) = E( J-1 )
|
|
D( J ) = A( J, J )
|
|
10 CONTINUE
|
|
20 CONTINUE
|
|
*
|
|
* Use unblocked code to reduce the last or only block
|
|
*
|
|
CALL DSYTD2( UPLO, KK, A, LDA, D, E, TAU, IINFO )
|
|
ELSE
|
|
*
|
|
* Reduce the lower triangle of A
|
|
*
|
|
DO 40 I = 1, N - NX, NB
|
|
*
|
|
* Reduce columns i:i+nb-1 to tridiagonal form and form the
|
|
* matrix W which is needed to update the unreduced part of
|
|
* the matrix
|
|
*
|
|
CALL DLATRD( UPLO, N-I+1, NB, A( I, I ), LDA, E( I ),
|
|
$ TAU( I ), WORK, LDWORK )
|
|
*
|
|
* Update the unreduced submatrix A(i+ib:n,i+ib:n), using
|
|
* an update of the form: A := A - V*W' - W*V'
|
|
*
|
|
CALL DSYR2K( UPLO, 'No transpose', N-I-NB+1, NB, -ONE,
|
|
$ A( I+NB, I ), LDA, WORK( NB+1 ), LDWORK, ONE,
|
|
$ A( I+NB, I+NB ), LDA )
|
|
*
|
|
* Copy subdiagonal elements back into A, and diagonal
|
|
* elements into D
|
|
*
|
|
DO 30 J = I, I + NB - 1
|
|
A( J+1, J ) = E( J )
|
|
D( J ) = A( J, J )
|
|
30 CONTINUE
|
|
40 CONTINUE
|
|
*
|
|
* Use unblocked code to reduce the last or only block
|
|
*
|
|
CALL DSYTD2( UPLO, N-I+1, A( I, I ), LDA, D( I ), E( I ),
|
|
$ TAU( I ), IINFO )
|
|
END IF
|
|
*
|
|
WORK( 1 ) = LWKOPT
|
|
RETURN
|
|
*
|
|
* End of DSYTRD
|
|
*
|
|
END
|
|
INTEGER FUNCTION IEEECK( ISPEC, ZERO, ONE )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER ISPEC
|
|
REAL ONE, ZERO
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* IEEECK is called from the ILAENV to verify that Infinity and
|
|
* possibly NaN arithmetic is safe (i.e. will not trap).
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* ISPEC (input) INTEGER
|
|
* Specifies whether to test just for inifinity arithmetic
|
|
* or whether to test for infinity and NaN arithmetic.
|
|
* = 0: Verify infinity arithmetic only.
|
|
* = 1: Verify infinity and NaN arithmetic.
|
|
*
|
|
* ZERO (input) REAL
|
|
* Must contain the value 0.0
|
|
* This is passed to prevent the compiler from optimizing
|
|
* away this code.
|
|
*
|
|
* ONE (input) REAL
|
|
* Must contain the value 1.0
|
|
* This is passed to prevent the compiler from optimizing
|
|
* away this code.
|
|
*
|
|
* RETURN VALUE: INTEGER
|
|
* = 0: Arithmetic failed to produce the correct answers
|
|
* = 1: Arithmetic produced the correct answers
|
|
*
|
|
* .. Local Scalars ..
|
|
REAL NAN1, NAN2, NAN3, NAN4, NAN5, NAN6, NEGINF,
|
|
$ NEGZRO, NEWZRO, POSINF
|
|
* ..
|
|
* .. Executable Statements ..
|
|
IEEECK = 1
|
|
*
|
|
POSINF = ONE / ZERO
|
|
IF( POSINF.LE.ONE ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
NEGINF = -ONE / ZERO
|
|
IF( NEGINF.GE.ZERO ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
NEGZRO = ONE / ( NEGINF+ONE )
|
|
IF( NEGZRO.NE.ZERO ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
NEGINF = ONE / NEGZRO
|
|
IF( NEGINF.GE.ZERO ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
NEWZRO = NEGZRO + ZERO
|
|
IF( NEWZRO.NE.ZERO ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
POSINF = ONE / NEWZRO
|
|
IF( POSINF.LE.ONE ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
NEGINF = NEGINF*POSINF
|
|
IF( NEGINF.GE.ZERO ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
POSINF = POSINF*POSINF
|
|
IF( POSINF.LE.ONE ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* Return if we were only asked to check infinity arithmetic
|
|
*
|
|
IF( ISPEC.EQ.0 )
|
|
$ RETURN
|
|
*
|
|
NAN1 = POSINF + NEGINF
|
|
*
|
|
NAN2 = POSINF / NEGINF
|
|
*
|
|
NAN3 = POSINF / POSINF
|
|
*
|
|
NAN4 = POSINF*ZERO
|
|
*
|
|
NAN5 = NEGINF*NEGZRO
|
|
*
|
|
NAN6 = NAN5*0.0
|
|
*
|
|
IF( NAN1.EQ.NAN1 ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
IF( NAN2.EQ.NAN2 ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
IF( NAN3.EQ.NAN3 ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
IF( NAN4.EQ.NAN4 ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
IF( NAN5.EQ.NAN5 ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
IF( NAN6.EQ.NAN6 ) THEN
|
|
IEEECK = 0
|
|
RETURN
|
|
END IF
|
|
*
|
|
RETURN
|
|
END
|
|
INTEGER FUNCTION ILAENV( ISPEC, NAME, OPTS, N1, N2, N3, N4 )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER*( * ) NAME, OPTS
|
|
INTEGER ISPEC, N1, N2, N3, N4
|
|
* ..
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* ILAENV is called from the LAPACK routines to choose problem-dependent
|
|
* parameters for the local environment. See ISPEC for a description of
|
|
* the parameters.
|
|
*
|
|
* This version provides a set of parameters which should give good,
|
|
* but not optimal, performance on many of the currently available
|
|
* computers. Users are encouraged to modify this subroutine to set
|
|
* the tuning parameters for their particular machine using the option
|
|
* and problem size information in the arguments.
|
|
*
|
|
* This routine will not function correctly if it is converted to all
|
|
* lower case. Converting it to all upper case is allowed.
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* ISPEC (input) INTEGER
|
|
* Specifies the parameter to be returned as the value of
|
|
* ILAENV.
|
|
* = 1: the optimal blocksize; if this value is 1, an unblocked
|
|
* algorithm will give the best performance.
|
|
* = 2: the minimum block size for which the block routine
|
|
* should be used; if the usable block size is less than
|
|
* this value, an unblocked routine should be used.
|
|
* = 3: the crossover point (in a block routine, for N less
|
|
* than this value, an unblocked routine should be used)
|
|
* = 4: the number of shifts, used in the nonsymmetric
|
|
* eigenvalue routines (DEPRECATED)
|
|
* = 5: the minimum column dimension for blocking to be used;
|
|
* rectangular blocks must have dimension at least k by m,
|
|
* where k is given by ILAENV(2,...) and m by ILAENV(5,...)
|
|
* = 6: the crossover point for the SVD (when reducing an m by n
|
|
* matrix to bidiagonal form, if max(m,n)/min(m,n) exceeds
|
|
* this value, a QR factorization is used first to reduce
|
|
* the matrix to a triangular form.)
|
|
* = 7: the number of processors
|
|
* = 8: the crossover point for the multishift QR method
|
|
* for nonsymmetric eigenvalue problems (DEPRECATED)
|
|
* = 9: maximum size of the subproblems at the bottom of the
|
|
* computation tree in the divide-and-conquer algorithm
|
|
* (used by xGELSD and xGESDD)
|
|
* =10: ieee NaN arithmetic can be trusted not to trap
|
|
* =11: infinity arithmetic can be trusted not to trap
|
|
* 12 <= ISPEC <= 16:
|
|
* xHSEQR or one of its subroutines,
|
|
* see IPARMQ for detailed explanation
|
|
*
|
|
* NAME (input) CHARACTER*(*)
|
|
* The name of the calling subroutine, in either upper case or
|
|
* lower case.
|
|
*
|
|
* OPTS (input) CHARACTER*(*)
|
|
* The character options to the subroutine NAME, concatenated
|
|
* into a single character string. For example, UPLO = 'U',
|
|
* TRANS = 'T', and DIAG = 'N' for a triangular routine would
|
|
* be specified as OPTS = 'UTN'.
|
|
*
|
|
* N1 (input) INTEGER
|
|
* N2 (input) INTEGER
|
|
* N3 (input) INTEGER
|
|
* N4 (input) INTEGER
|
|
* Problem dimensions for the subroutine NAME; these may not all
|
|
* be required.
|
|
*
|
|
* (ILAENV) (output) INTEGER
|
|
* >= 0: the value of the parameter specified by ISPEC
|
|
* < 0: if ILAENV = -k, the k-th argument had an illegal value.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* The following conventions have been used when calling ILAENV from the
|
|
* LAPACK routines:
|
|
* 1) OPTS is a concatenation of all of the character options to
|
|
* subroutine NAME, in the same order that they appear in the
|
|
* argument list for NAME, even if they are not used in determining
|
|
* the value of the parameter specified by ISPEC.
|
|
* 2) The problem dimensions N1, N2, N3, N4 are specified in the order
|
|
* that they appear in the argument list for NAME. N1 is used
|
|
* first, N2 second, and so on, and unused problem dimensions are
|
|
* passed a value of -1.
|
|
* 3) The parameter value returned by ILAENV is checked for validity in
|
|
* the calling subroutine. For example, ILAENV is used to retrieve
|
|
* the optimal blocksize for STRTRI as follows:
|
|
*
|
|
* NB = ILAENV( 1, 'STRTRI', UPLO // DIAG, N, -1, -1, -1 )
|
|
* IF( NB.LE.1 ) NB = MAX( 1, N )
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Local Scalars ..
|
|
INTEGER I, IC, IZ, NB, NBMIN, NX
|
|
LOGICAL CNAME, SNAME
|
|
CHARACTER C1*1, C2*2, C4*2, C3*3, SUBNAM*6
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC CHAR, ICHAR, INT, MIN, REAL
|
|
* ..
|
|
* .. External Functions ..
|
|
INTEGER IEEECK, IPARMQ
|
|
EXTERNAL IEEECK, IPARMQ
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
GO TO ( 10, 10, 10, 80, 90, 100, 110, 120,
|
|
$ 130, 140, 150, 160, 160, 160, 160, 160 )ISPEC
|
|
*
|
|
* Invalid value for ISPEC
|
|
*
|
|
ILAENV = -1
|
|
RETURN
|
|
*
|
|
10 CONTINUE
|
|
*
|
|
* Convert NAME to upper case if the first character is lower case.
|
|
*
|
|
ILAENV = 1
|
|
SUBNAM = NAME
|
|
IC = ICHAR( SUBNAM( 1: 1 ) )
|
|
IZ = ICHAR( 'Z' )
|
|
IF( IZ.EQ.90 .OR. IZ.EQ.122 ) THEN
|
|
*
|
|
* ASCII character set
|
|
*
|
|
IF( IC.GE.97 .AND. IC.LE.122 ) THEN
|
|
SUBNAM( 1: 1 ) = CHAR( IC-32 )
|
|
DO 20 I = 2, 6
|
|
IC = ICHAR( SUBNAM( I: I ) )
|
|
IF( IC.GE.97 .AND. IC.LE.122 )
|
|
$ SUBNAM( I: I ) = CHAR( IC-32 )
|
|
20 CONTINUE
|
|
END IF
|
|
*
|
|
ELSE IF( IZ.EQ.233 .OR. IZ.EQ.169 ) THEN
|
|
*
|
|
* EBCDIC character set
|
|
*
|
|
IF( ( IC.GE.129 .AND. IC.LE.137 ) .OR.
|
|
$ ( IC.GE.145 .AND. IC.LE.153 ) .OR.
|
|
$ ( IC.GE.162 .AND. IC.LE.169 ) ) THEN
|
|
SUBNAM( 1: 1 ) = CHAR( IC+64 )
|
|
DO 30 I = 2, 6
|
|
IC = ICHAR( SUBNAM( I: I ) )
|
|
IF( ( IC.GE.129 .AND. IC.LE.137 ) .OR.
|
|
$ ( IC.GE.145 .AND. IC.LE.153 ) .OR.
|
|
$ ( IC.GE.162 .AND. IC.LE.169 ) )SUBNAM( I:
|
|
$ I ) = CHAR( IC+64 )
|
|
30 CONTINUE
|
|
END IF
|
|
*
|
|
ELSE IF( IZ.EQ.218 .OR. IZ.EQ.250 ) THEN
|
|
*
|
|
* Prime machines: ASCII+128
|
|
*
|
|
IF( IC.GE.225 .AND. IC.LE.250 ) THEN
|
|
SUBNAM( 1: 1 ) = CHAR( IC-32 )
|
|
DO 40 I = 2, 6
|
|
IC = ICHAR( SUBNAM( I: I ) )
|
|
IF( IC.GE.225 .AND. IC.LE.250 )
|
|
$ SUBNAM( I: I ) = CHAR( IC-32 )
|
|
40 CONTINUE
|
|
END IF
|
|
END IF
|
|
*
|
|
C1 = SUBNAM( 1: 1 )
|
|
SNAME = C1.EQ.'S' .OR. C1.EQ.'D'
|
|
CNAME = C1.EQ.'C' .OR. C1.EQ.'Z'
|
|
IF( .NOT.( CNAME .OR. SNAME ) )
|
|
$ RETURN
|
|
C2 = SUBNAM( 2: 3 )
|
|
C3 = SUBNAM( 4: 6 )
|
|
C4 = C3( 2: 3 )
|
|
*
|
|
GO TO ( 50, 60, 70 )ISPEC
|
|
*
|
|
50 CONTINUE
|
|
*
|
|
* ISPEC = 1: block size
|
|
*
|
|
* In these examples, separate code is provided for setting NB for
|
|
* real and complex. We assume that NB will take the same value in
|
|
* single or double precision.
|
|
*
|
|
NB = 1
|
|
*
|
|
IF( C2.EQ.'GE' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 64
|
|
ELSE
|
|
NB = 64
|
|
END IF
|
|
ELSE IF( C3.EQ.'QRF' .OR. C3.EQ.'RQF' .OR. C3.EQ.'LQF' .OR.
|
|
$ C3.EQ.'QLF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 32
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
ELSE IF( C3.EQ.'HRD' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 32
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
ELSE IF( C3.EQ.'BRD' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 32
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
ELSE IF( C3.EQ.'TRI' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 64
|
|
ELSE
|
|
NB = 64
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'PO' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 64
|
|
ELSE
|
|
NB = 64
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'SY' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 64
|
|
ELSE
|
|
NB = 64
|
|
END IF
|
|
ELSE IF( SNAME .AND. C3.EQ.'TRD' ) THEN
|
|
NB = 32
|
|
ELSE IF( SNAME .AND. C3.EQ.'GST' ) THEN
|
|
NB = 64
|
|
END IF
|
|
ELSE IF( CNAME .AND. C2.EQ.'HE' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
NB = 64
|
|
ELSE IF( C3.EQ.'TRD' ) THEN
|
|
NB = 32
|
|
ELSE IF( C3.EQ.'GST' ) THEN
|
|
NB = 64
|
|
END IF
|
|
ELSE IF( SNAME .AND. C2.EQ.'OR' ) THEN
|
|
IF( C3( 1: 1 ).EQ.'G' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NB = 32
|
|
END IF
|
|
ELSE IF( C3( 1: 1 ).EQ.'M' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NB = 32
|
|
END IF
|
|
END IF
|
|
ELSE IF( CNAME .AND. C2.EQ.'UN' ) THEN
|
|
IF( C3( 1: 1 ).EQ.'G' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NB = 32
|
|
END IF
|
|
ELSE IF( C3( 1: 1 ).EQ.'M' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NB = 32
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'GB' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
IF( SNAME ) THEN
|
|
IF( N4.LE.64 ) THEN
|
|
NB = 1
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
ELSE
|
|
IF( N4.LE.64 ) THEN
|
|
NB = 1
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'PB' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
IF( SNAME ) THEN
|
|
IF( N2.LE.64 ) THEN
|
|
NB = 1
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
ELSE
|
|
IF( N2.LE.64 ) THEN
|
|
NB = 1
|
|
ELSE
|
|
NB = 32
|
|
END IF
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'TR' ) THEN
|
|
IF( C3.EQ.'TRI' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 64
|
|
ELSE
|
|
NB = 64
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'LA' ) THEN
|
|
IF( C3.EQ.'UUM' ) THEN
|
|
IF( SNAME ) THEN
|
|
NB = 64
|
|
ELSE
|
|
NB = 64
|
|
END IF
|
|
END IF
|
|
ELSE IF( SNAME .AND. C2.EQ.'ST' ) THEN
|
|
IF( C3.EQ.'EBZ' ) THEN
|
|
NB = 1
|
|
END IF
|
|
END IF
|
|
ILAENV = NB
|
|
RETURN
|
|
*
|
|
60 CONTINUE
|
|
*
|
|
* ISPEC = 2: minimum block size
|
|
*
|
|
NBMIN = 2
|
|
IF( C2.EQ.'GE' ) THEN
|
|
IF( C3.EQ.'QRF' .OR. C3.EQ.'RQF' .OR. C3.EQ.'LQF' .OR. C3.EQ.
|
|
$ 'QLF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NBMIN = 2
|
|
ELSE
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( C3.EQ.'HRD' ) THEN
|
|
IF( SNAME ) THEN
|
|
NBMIN = 2
|
|
ELSE
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( C3.EQ.'BRD' ) THEN
|
|
IF( SNAME ) THEN
|
|
NBMIN = 2
|
|
ELSE
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( C3.EQ.'TRI' ) THEN
|
|
IF( SNAME ) THEN
|
|
NBMIN = 2
|
|
ELSE
|
|
NBMIN = 2
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'SY' ) THEN
|
|
IF( C3.EQ.'TRF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NBMIN = 8
|
|
ELSE
|
|
NBMIN = 8
|
|
END IF
|
|
ELSE IF( SNAME .AND. C3.EQ.'TRD' ) THEN
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( CNAME .AND. C2.EQ.'HE' ) THEN
|
|
IF( C3.EQ.'TRD' ) THEN
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( SNAME .AND. C2.EQ.'OR' ) THEN
|
|
IF( C3( 1: 1 ).EQ.'G' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( C3( 1: 1 ).EQ.'M' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NBMIN = 2
|
|
END IF
|
|
END IF
|
|
ELSE IF( CNAME .AND. C2.EQ.'UN' ) THEN
|
|
IF( C3( 1: 1 ).EQ.'G' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NBMIN = 2
|
|
END IF
|
|
ELSE IF( C3( 1: 1 ).EQ.'M' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NBMIN = 2
|
|
END IF
|
|
END IF
|
|
END IF
|
|
ILAENV = NBMIN
|
|
RETURN
|
|
*
|
|
70 CONTINUE
|
|
*
|
|
* ISPEC = 3: crossover point
|
|
*
|
|
NX = 0
|
|
IF( C2.EQ.'GE' ) THEN
|
|
IF( C3.EQ.'QRF' .OR. C3.EQ.'RQF' .OR. C3.EQ.'LQF' .OR. C3.EQ.
|
|
$ 'QLF' ) THEN
|
|
IF( SNAME ) THEN
|
|
NX = 128
|
|
ELSE
|
|
NX = 128
|
|
END IF
|
|
ELSE IF( C3.EQ.'HRD' ) THEN
|
|
IF( SNAME ) THEN
|
|
NX = 128
|
|
ELSE
|
|
NX = 128
|
|
END IF
|
|
ELSE IF( C3.EQ.'BRD' ) THEN
|
|
IF( SNAME ) THEN
|
|
NX = 128
|
|
ELSE
|
|
NX = 128
|
|
END IF
|
|
END IF
|
|
ELSE IF( C2.EQ.'SY' ) THEN
|
|
IF( SNAME .AND. C3.EQ.'TRD' ) THEN
|
|
NX = 32
|
|
END IF
|
|
ELSE IF( CNAME .AND. C2.EQ.'HE' ) THEN
|
|
IF( C3.EQ.'TRD' ) THEN
|
|
NX = 32
|
|
END IF
|
|
ELSE IF( SNAME .AND. C2.EQ.'OR' ) THEN
|
|
IF( C3( 1: 1 ).EQ.'G' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NX = 128
|
|
END IF
|
|
END IF
|
|
ELSE IF( CNAME .AND. C2.EQ.'UN' ) THEN
|
|
IF( C3( 1: 1 ).EQ.'G' ) THEN
|
|
IF( C4.EQ.'QR' .OR. C4.EQ.'RQ' .OR. C4.EQ.'LQ' .OR. C4.EQ.
|
|
$ 'QL' .OR. C4.EQ.'HR' .OR. C4.EQ.'TR' .OR. C4.EQ.'BR' )
|
|
$ THEN
|
|
NX = 128
|
|
END IF
|
|
END IF
|
|
END IF
|
|
ILAENV = NX
|
|
RETURN
|
|
*
|
|
80 CONTINUE
|
|
*
|
|
* ISPEC = 4: number of shifts (used by xHSEQR)
|
|
*
|
|
ILAENV = 6
|
|
RETURN
|
|
*
|
|
90 CONTINUE
|
|
*
|
|
* ISPEC = 5: minimum column dimension (not used)
|
|
*
|
|
ILAENV = 2
|
|
RETURN
|
|
*
|
|
100 CONTINUE
|
|
*
|
|
* ISPEC = 6: crossover point for SVD (used by xGELSS and xGESVD)
|
|
*
|
|
ILAENV = INT( REAL( MIN( N1, N2 ) )*1.6E0 )
|
|
RETURN
|
|
*
|
|
110 CONTINUE
|
|
*
|
|
* ISPEC = 7: number of processors (not used)
|
|
*
|
|
ILAENV = 1
|
|
RETURN
|
|
*
|
|
120 CONTINUE
|
|
*
|
|
* ISPEC = 8: crossover point for multishift (used by xHSEQR)
|
|
*
|
|
ILAENV = 50
|
|
RETURN
|
|
*
|
|
130 CONTINUE
|
|
*
|
|
* ISPEC = 9: maximum size of the subproblems at the bottom of the
|
|
* computation tree in the divide-and-conquer algorithm
|
|
* (used by xGELSD and xGESDD)
|
|
*
|
|
ILAENV = 25
|
|
RETURN
|
|
*
|
|
140 CONTINUE
|
|
*
|
|
* ISPEC = 10: ieee NaN arithmetic can be trusted not to trap
|
|
*
|
|
* ILAENV = 0
|
|
ILAENV = 1
|
|
IF( ILAENV.EQ.1 ) THEN
|
|
ILAENV = IEEECK( 0, 0.0, 1.0 )
|
|
END IF
|
|
RETURN
|
|
*
|
|
150 CONTINUE
|
|
*
|
|
* ISPEC = 11: infinity arithmetic can be trusted not to trap
|
|
*
|
|
* ILAENV = 0
|
|
ILAENV = 1
|
|
IF( ILAENV.EQ.1 ) THEN
|
|
ILAENV = IEEECK( 1, 0.0, 1.0 )
|
|
END IF
|
|
RETURN
|
|
*
|
|
160 CONTINUE
|
|
*
|
|
* 12 <= ISPEC <= 16: xHSEQR or one of its subroutines.
|
|
*
|
|
ILAENV = IPARMQ( ISPEC, NAME, OPTS, N1, N2, N3, N4 )
|
|
RETURN
|
|
*
|
|
* End of ILAENV
|
|
*
|
|
END
|
|
INTEGER FUNCTION IPARMQ( ISPEC, NAME, OPTS, N, ILO, IHI, LWORK )
|
|
*
|
|
* -- LAPACK auxiliary routine (version 3.1) --
|
|
* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
|
|
* November 2006
|
|
*
|
|
* .. Scalar Arguments ..
|
|
INTEGER IHI, ILO, ISPEC, LWORK, N
|
|
CHARACTER NAME*( * ), OPTS*( * )
|
|
*
|
|
* Purpose
|
|
* =======
|
|
*
|
|
* This program sets problem and machine dependent parameters
|
|
* useful for xHSEQR and its subroutines. It is called whenever
|
|
* ILAENV is called with 12 <= ISPEC <= 16
|
|
*
|
|
* Arguments
|
|
* =========
|
|
*
|
|
* ISPEC (input) integer scalar
|
|
* ISPEC specifies which tunable parameter IPARMQ should
|
|
* return.
|
|
*
|
|
* ISPEC=12: (INMIN) Matrices of order nmin or less
|
|
* are sent directly to xLAHQR, the implicit
|
|
* double shift QR algorithm. NMIN must be
|
|
* at least 11.
|
|
*
|
|
* ISPEC=13: (INWIN) Size of the deflation window.
|
|
* This is best set greater than or equal to
|
|
* the number of simultaneous shifts NS.
|
|
* Larger matrices benefit from larger deflation
|
|
* windows.
|
|
*
|
|
* ISPEC=14: (INIBL) Determines when to stop nibbling and
|
|
* invest in an (expensive) multi-shift QR sweep.
|
|
* If the aggressive early deflation subroutine
|
|
* finds LD converged eigenvalues from an order
|
|
* NW deflation window and LD.GT.(NW*NIBBLE)/100,
|
|
* then the next QR sweep is skipped and early
|
|
* deflation is applied immediately to the
|
|
* remaining active diagonal block. Setting
|
|
* IPARMQ(ISPEC=14) = 0 causes TTQRE to skip a
|
|
* multi-shift QR sweep whenever early deflation
|
|
* finds a converged eigenvalue. Setting
|
|
* IPARMQ(ISPEC=14) greater than or equal to 100
|
|
* prevents TTQRE from skipping a multi-shift
|
|
* QR sweep.
|
|
*
|
|
* ISPEC=15: (NSHFTS) The number of simultaneous shifts in
|
|
* a multi-shift QR iteration.
|
|
*
|
|
* ISPEC=16: (IACC22) IPARMQ is set to 0, 1 or 2 with the
|
|
* following meanings.
|
|
* 0: During the multi-shift QR sweep,
|
|
* xLAQR5 does not accumulate reflections and
|
|
* does not use matrix-matrix multiply to
|
|
* update the far-from-diagonal matrix
|
|
* entries.
|
|
* 1: During the multi-shift QR sweep,
|
|
* xLAQR5 and/or xLAQRaccumulates reflections and uses
|
|
* matrix-matrix multiply to update the
|
|
* far-from-diagonal matrix entries.
|
|
* 2: During the multi-shift QR sweep.
|
|
* xLAQR5 accumulates reflections and takes
|
|
* advantage of 2-by-2 block structure during
|
|
* matrix-matrix multiplies.
|
|
* (If xTRMM is slower than xGEMM, then
|
|
* IPARMQ(ISPEC=16)=1 may be more efficient than
|
|
* IPARMQ(ISPEC=16)=2 despite the greater level of
|
|
* arithmetic work implied by the latter choice.)
|
|
*
|
|
* NAME (input) character string
|
|
* Name of the calling subroutine
|
|
*
|
|
* OPTS (input) character string
|
|
* This is a concatenation of the string arguments to
|
|
* TTQRE.
|
|
*
|
|
* N (input) integer scalar
|
|
* N is the order of the Hessenberg matrix H.
|
|
*
|
|
* ILO (input) INTEGER
|
|
* IHI (input) INTEGER
|
|
* It is assumed that H is already upper triangular
|
|
* in rows and columns 1:ILO-1 and IHI+1:N.
|
|
*
|
|
* LWORK (input) integer scalar
|
|
* The amount of workspace available.
|
|
*
|
|
* Further Details
|
|
* ===============
|
|
*
|
|
* Little is known about how best to choose these parameters.
|
|
* It is possible to use different values of the parameters
|
|
* for each of CHSEQR, DHSEQR, SHSEQR and ZHSEQR.
|
|
*
|
|
* It is probably best to choose different parameters for
|
|
* different matrices and different parameters at different
|
|
* times during the iteration, but this has not been
|
|
* implemented --- yet.
|
|
*
|
|
*
|
|
* The best choices of most of the parameters depend
|
|
* in an ill-understood way on the relative execution
|
|
* rate of xLAQR3 and xLAQR5 and on the nature of each
|
|
* particular eigenvalue problem. Experiment may be the
|
|
* only practical way to determine which choices are most
|
|
* effective.
|
|
*
|
|
* Following is a list of default values supplied by IPARMQ.
|
|
* These defaults may be adjusted in order to attain better
|
|
* performance in any particular computational environment.
|
|
*
|
|
* IPARMQ(ISPEC=12) The xLAHQR vs xLAQR0 crossover point.
|
|
* Default: 75. (Must be at least 11.)
|
|
*
|
|
* IPARMQ(ISPEC=13) Recommended deflation window size.
|
|
* This depends on ILO, IHI and NS, the
|
|
* number of simultaneous shifts returned
|
|
* by IPARMQ(ISPEC=15). The default for
|
|
* (IHI-ILO+1).LE.500 is NS. The default
|
|
* for (IHI-ILO+1).GT.500 is 3*NS/2.
|
|
*
|
|
* IPARMQ(ISPEC=14) Nibble crossover point. Default: 14.
|
|
*
|
|
* IPARMQ(ISPEC=15) Number of simultaneous shifts, NS.
|
|
* a multi-shift QR iteration.
|
|
*
|
|
* If IHI-ILO+1 is ...
|
|
*
|
|
* greater than ...but less ... the
|
|
* or equal to ... than default is
|
|
*
|
|
* 0 30 NS = 2+
|
|
* 30 60 NS = 4+
|
|
* 60 150 NS = 10
|
|
* 150 590 NS = **
|
|
* 590 3000 NS = 64
|
|
* 3000 6000 NS = 128
|
|
* 6000 infinity NS = 256
|
|
*
|
|
* (+) By default matrices of this order are
|
|
* passed to the implicit double shift routine
|
|
* xLAHQR. See IPARMQ(ISPEC=12) above. These
|
|
* values of NS are used only in case of a rare
|
|
* xLAHQR failure.
|
|
*
|
|
* (**) The asterisks (**) indicate an ad-hoc
|
|
* function increasing from 10 to 64.
|
|
*
|
|
* IPARMQ(ISPEC=16) Select structured matrix multiply.
|
|
* (See ISPEC=16 above for details.)
|
|
* Default: 3.
|
|
*
|
|
* ================================================================
|
|
* .. Parameters ..
|
|
INTEGER INMIN, INWIN, INIBL, ISHFTS, IACC22
|
|
PARAMETER ( INMIN = 12, INWIN = 13, INIBL = 14,
|
|
$ ISHFTS = 15, IACC22 = 16 )
|
|
INTEGER NMIN, K22MIN, KACMIN, NIBBLE, KNWSWP
|
|
PARAMETER ( NMIN = 75, K22MIN = 14, KACMIN = 14,
|
|
$ NIBBLE = 14, KNWSWP = 500 )
|
|
REAL TWO
|
|
PARAMETER ( TWO = 2.0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
INTEGER NH, NS
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC LOG, MAX, MOD, NINT, REAL
|
|
* ..
|
|
* .. Executable Statements ..
|
|
IF( ( ISPEC.EQ.ISHFTS ) .OR. ( ISPEC.EQ.INWIN ) .OR.
|
|
$ ( ISPEC.EQ.IACC22 ) ) THEN
|
|
*
|
|
* ==== Set the number simultaneous shifts ====
|
|
*
|
|
NH = IHI - ILO + 1
|
|
NS = 2
|
|
IF( NH.GE.30 )
|
|
$ NS = 4
|
|
IF( NH.GE.60 )
|
|
$ NS = 10
|
|
IF( NH.GE.150 )
|
|
$ NS = MAX( 10, NH / NINT( LOG( REAL( NH ) ) / LOG( TWO ) ) )
|
|
IF( NH.GE.590 )
|
|
$ NS = 64
|
|
IF( NH.GE.3000 )
|
|
$ NS = 128
|
|
IF( NH.GE.6000 )
|
|
$ NS = 256
|
|
NS = MAX( 2, NS-MOD( NS, 2 ) )
|
|
END IF
|
|
*
|
|
IF( ISPEC.EQ.INMIN ) THEN
|
|
*
|
|
*
|
|
* ===== Matrices of order smaller than NMIN get sent
|
|
* . to xLAHQR, the classic double shift algorithm.
|
|
* . This must be at least 11. ====
|
|
*
|
|
IPARMQ = NMIN
|
|
*
|
|
ELSE IF( ISPEC.EQ.INIBL ) THEN
|
|
*
|
|
* ==== INIBL: skip a multi-shift qr iteration and
|
|
* . whenever aggressive early deflation finds
|
|
* . at least (NIBBLE*(window size)/100) deflations. ====
|
|
*
|
|
IPARMQ = NIBBLE
|
|
*
|
|
ELSE IF( ISPEC.EQ.ISHFTS ) THEN
|
|
*
|
|
* ==== NSHFTS: The number of simultaneous shifts =====
|
|
*
|
|
IPARMQ = NS
|
|
*
|
|
ELSE IF( ISPEC.EQ.INWIN ) THEN
|
|
*
|
|
* ==== NW: deflation window size. ====
|
|
*
|
|
IF( NH.LE.KNWSWP ) THEN
|
|
IPARMQ = NS
|
|
ELSE
|
|
IPARMQ = 3*NS / 2
|
|
END IF
|
|
*
|
|
ELSE IF( ISPEC.EQ.IACC22 ) THEN
|
|
*
|
|
* ==== IACC22: Whether to accumulate reflections
|
|
* . before updating the far-from-diagonal elements
|
|
* . and whether to use 2-by-2 block structure while
|
|
* . doing it. A small amount of work could be saved
|
|
* . by making this choice dependent also upon the
|
|
* . NH=IHI-ILO+1.
|
|
*
|
|
IPARMQ = 0
|
|
IF( NS.GE.KACMIN )
|
|
$ IPARMQ = 1
|
|
IF( NS.GE.K22MIN )
|
|
$ IPARMQ = 2
|
|
*
|
|
ELSE
|
|
* ===== invalid value of ispec =====
|
|
IPARMQ = -1
|
|
*
|
|
END IF
|
|
*
|
|
* ==== End of IPARMQ ====
|
|
*
|
|
END
|