Files
lapack/SRC/dpbrfs.f
T
Julie e18d437924 Making LAPACK's code eternal... no more version and date in source files.
GitHub is now enabling us to track accurately version and date.
No need for this anymore.
2021-03-25 10:16:58 -07:00

441 lines
13 KiB
FortranFixed

*> \brief \b DPBRFS
*
* =========== DOCUMENTATION ===========
*
* Online html documentation available at
* http://www.netlib.org/lapack/explore-html/
*
*> \htmlonly
*> Download DPBRFS + dependencies
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dpbrfs.f">
*> [TGZ]</a>
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dpbrfs.f">
*> [ZIP]</a>
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dpbrfs.f">
*> [TXT]</a>
*> \endhtmlonly
*
* Definition:
* ===========
*
* SUBROUTINE DPBRFS( UPLO, N, KD, NRHS, AB, LDAB, AFB, LDAFB, B,
* LDB, X, LDX, FERR, BERR, WORK, IWORK, INFO )
*
* .. Scalar Arguments ..
* CHARACTER UPLO
* INTEGER INFO, KD, LDAB, LDAFB, LDB, LDX, N, NRHS
* ..
* .. Array Arguments ..
* INTEGER IWORK( * )
* DOUBLE PRECISION AB( LDAB, * ), AFB( LDAFB, * ), B( LDB, * ),
* $ BERR( * ), FERR( * ), WORK( * ), X( LDX, * )
* ..
*
*
*> \par Purpose:
* =============
*>
*> \verbatim
*>
*> DPBRFS improves the computed solution to a system of linear
*> equations when the coefficient matrix is symmetric positive definite
*> and banded, and provides error bounds and backward error estimates
*> for the solution.
*> \endverbatim
*
* Arguments:
* ==========
*
*> \param[in] UPLO
*> \verbatim
*> UPLO is CHARACTER*1
*> = 'U': Upper triangle of A is stored;
*> = 'L': Lower triangle of A is stored.
*> \endverbatim
*>
*> \param[in] N
*> \verbatim
*> N is INTEGER
*> The order of the matrix A. N >= 0.
*> \endverbatim
*>
*> \param[in] KD
*> \verbatim
*> KD is INTEGER
*> The number of superdiagonals of the matrix A if UPLO = 'U',
*> or the number of subdiagonals if UPLO = 'L'. KD >= 0.
*> \endverbatim
*>
*> \param[in] NRHS
*> \verbatim
*> NRHS is INTEGER
*> The number of right hand sides, i.e., the number of columns
*> of the matrices B and X. NRHS >= 0.
*> \endverbatim
*>
*> \param[in] AB
*> \verbatim
*> AB is DOUBLE PRECISION array, dimension (LDAB,N)
*> The upper or lower triangle of the symmetric band matrix A,
*> stored in the first KD+1 rows of the array. The j-th column
*> of A is stored in the j-th column of the array AB as follows:
*> if UPLO = 'U', AB(kd+1+i-j,j) = A(i,j) for max(1,j-kd)<=i<=j;
*> if UPLO = 'L', AB(1+i-j,j) = A(i,j) for j<=i<=min(n,j+kd).
*> \endverbatim
*>
*> \param[in] LDAB
*> \verbatim
*> LDAB is INTEGER
*> The leading dimension of the array AB. LDAB >= KD+1.
*> \endverbatim
*>
*> \param[in] AFB
*> \verbatim
*> AFB is DOUBLE PRECISION array, dimension (LDAFB,N)
*> The triangular factor U or L from the Cholesky factorization
*> A = U**T*U or A = L*L**T of the band matrix A as computed by
*> DPBTRF, in the same storage format as A (see AB).
*> \endverbatim
*>
*> \param[in] LDAFB
*> \verbatim
*> LDAFB is INTEGER
*> The leading dimension of the array AFB. LDAFB >= KD+1.
*> \endverbatim
*>
*> \param[in] B
*> \verbatim
*> B is DOUBLE PRECISION array, dimension (LDB,NRHS)
*> The right hand side matrix B.
*> \endverbatim
*>
*> \param[in] LDB
*> \verbatim
*> LDB is INTEGER
*> The leading dimension of the array B. LDB >= max(1,N).
*> \endverbatim
*>
*> \param[in,out] X
*> \verbatim
*> X is DOUBLE PRECISION array, dimension (LDX,NRHS)
*> On entry, the solution matrix X, as computed by DPBTRS.
*> On exit, the improved solution matrix X.
*> \endverbatim
*>
*> \param[in] LDX
*> \verbatim
*> LDX is INTEGER
*> The leading dimension of the array X. LDX >= max(1,N).
*> \endverbatim
*>
*> \param[out] FERR
*> \verbatim
*> FERR is DOUBLE PRECISION array, dimension (NRHS)
*> The estimated forward error bound for each solution vector
*> X(j) (the j-th column of the solution matrix X).
*> If XTRUE is the true solution corresponding to X(j), FERR(j)
*> is an estimated upper bound for the magnitude of the largest
*> element in (X(j) - XTRUE) divided by the magnitude of the
*> largest element in X(j). The estimate is as reliable as
*> the estimate for RCOND, and is almost always a slight
*> overestimate of the true error.
*> \endverbatim
*>
*> \param[out] BERR
*> \verbatim
*> BERR is DOUBLE PRECISION array, dimension (NRHS)
*> The componentwise relative backward error of each solution
*> vector X(j) (i.e., the smallest relative change in
*> any element of A or B that makes X(j) an exact solution).
*> \endverbatim
*>
*> \param[out] WORK
*> \verbatim
*> WORK is DOUBLE PRECISION array, dimension (3*N)
*> \endverbatim
*>
*> \param[out] IWORK
*> \verbatim
*> IWORK is INTEGER array, dimension (N)
*> \endverbatim
*>
*> \param[out] INFO
*> \verbatim
*> INFO is INTEGER
*> = 0: successful exit
*> < 0: if INFO = -i, the i-th argument had an illegal value
*> \endverbatim
*
*> \par Internal Parameters:
* =========================
*>
*> \verbatim
*> ITMAX is the maximum number of steps of iterative refinement.
*> \endverbatim
*
* Authors:
* ========
*
*> \author Univ. of Tennessee
*> \author Univ. of California Berkeley
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup doubleOTHERcomputational
*
* =====================================================================
SUBROUTINE DPBRFS( UPLO, N, KD, NRHS, AB, LDAB, AFB, LDAFB, B,
$ LDB, X, LDX, FERR, BERR, WORK, IWORK, INFO )
*
* -- LAPACK computational routine --
* -- LAPACK is a software package provided by Univ. of Tennessee, --
* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
*
* .. Scalar Arguments ..
CHARACTER UPLO
INTEGER INFO, KD, LDAB, LDAFB, LDB, LDX, N, NRHS
* ..
* .. Array Arguments ..
INTEGER IWORK( * )
DOUBLE PRECISION AB( LDAB, * ), AFB( LDAFB, * ), B( LDB, * ),
$ BERR( * ), FERR( * ), WORK( * ), X( LDX, * )
* ..
*
* =====================================================================
*
* .. Parameters ..
INTEGER ITMAX
PARAMETER ( ITMAX = 5 )
DOUBLE PRECISION ZERO
PARAMETER ( ZERO = 0.0D+0 )
DOUBLE PRECISION ONE
PARAMETER ( ONE = 1.0D+0 )
DOUBLE PRECISION TWO
PARAMETER ( TWO = 2.0D+0 )
DOUBLE PRECISION THREE
PARAMETER ( THREE = 3.0D+0 )
* ..
* .. Local Scalars ..
LOGICAL UPPER
INTEGER COUNT, I, J, K, KASE, L, NZ
DOUBLE PRECISION EPS, LSTRES, S, SAFE1, SAFE2, SAFMIN, XK
* ..
* .. Local Arrays ..
INTEGER ISAVE( 3 )
* ..
* .. External Subroutines ..
EXTERNAL DAXPY, DCOPY, DLACN2, DPBTRS, DSBMV, XERBLA
* ..
* .. Intrinsic Functions ..
INTRINSIC ABS, MAX, MIN
* ..
* .. External Functions ..
LOGICAL LSAME
DOUBLE PRECISION DLAMCH
EXTERNAL LSAME, DLAMCH
* ..
* .. 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( KD.LT.0 ) THEN
INFO = -3
ELSE IF( NRHS.LT.0 ) THEN
INFO = -4
ELSE IF( LDAB.LT.KD+1 ) THEN
INFO = -6
ELSE IF( LDAFB.LT.KD+1 ) THEN
INFO = -8
ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
INFO = -10
ELSE IF( LDX.LT.MAX( 1, N ) ) THEN
INFO = -12
END IF
IF( INFO.NE.0 ) THEN
CALL XERBLA( 'DPBRFS', -INFO )
RETURN
END IF
*
* Quick return if possible
*
IF( N.EQ.0 .OR. NRHS.EQ.0 ) THEN
DO 10 J = 1, NRHS
FERR( J ) = ZERO
BERR( J ) = ZERO
10 CONTINUE
RETURN
END IF
*
* NZ = maximum number of nonzero elements in each row of A, plus 1
*
NZ = MIN( N+1, 2*KD+2 )
EPS = DLAMCH( 'Epsilon' )
SAFMIN = DLAMCH( 'Safe minimum' )
SAFE1 = NZ*SAFMIN
SAFE2 = SAFE1 / EPS
*
* Do for each right hand side
*
DO 140 J = 1, NRHS
*
COUNT = 1
LSTRES = THREE
20 CONTINUE
*
* Loop until stopping criterion is satisfied.
*
* Compute residual R = B - A * X
*
CALL DCOPY( N, B( 1, J ), 1, WORK( N+1 ), 1 )
CALL DSBMV( UPLO, N, KD, -ONE, AB, LDAB, X( 1, J ), 1, ONE,
$ WORK( N+1 ), 1 )
*
* Compute componentwise relative backward error from formula
*
* max(i) ( abs(R(i)) / ( abs(A)*abs(X) + abs(B) )(i) )
*
* where abs(Z) is the componentwise absolute value of the matrix
* or vector Z. If the i-th component of the denominator is less
* than SAFE2, then SAFE1 is added to the i-th components of the
* numerator and denominator before dividing.
*
DO 30 I = 1, N
WORK( I ) = ABS( B( I, J ) )
30 CONTINUE
*
* Compute abs(A)*abs(X) + abs(B).
*
IF( UPPER ) THEN
DO 50 K = 1, N
S = ZERO
XK = ABS( X( K, J ) )
L = KD + 1 - K
DO 40 I = MAX( 1, K-KD ), K - 1
WORK( I ) = WORK( I ) + ABS( AB( L+I, K ) )*XK
S = S + ABS( AB( L+I, K ) )*ABS( X( I, J ) )
40 CONTINUE
WORK( K ) = WORK( K ) + ABS( AB( KD+1, K ) )*XK + S
50 CONTINUE
ELSE
DO 70 K = 1, N
S = ZERO
XK = ABS( X( K, J ) )
WORK( K ) = WORK( K ) + ABS( AB( 1, K ) )*XK
L = 1 - K
DO 60 I = K + 1, MIN( N, K+KD )
WORK( I ) = WORK( I ) + ABS( AB( L+I, K ) )*XK
S = S + ABS( AB( L+I, K ) )*ABS( X( I, J ) )
60 CONTINUE
WORK( K ) = WORK( K ) + S
70 CONTINUE
END IF
S = ZERO
DO 80 I = 1, N
IF( WORK( I ).GT.SAFE2 ) THEN
S = MAX( S, ABS( WORK( N+I ) ) / WORK( I ) )
ELSE
S = MAX( S, ( ABS( WORK( N+I ) )+SAFE1 ) /
$ ( WORK( I )+SAFE1 ) )
END IF
80 CONTINUE
BERR( J ) = S
*
* Test stopping criterion. Continue iterating if
* 1) The residual BERR(J) is larger than machine epsilon, and
* 2) BERR(J) decreased by at least a factor of 2 during the
* last iteration, and
* 3) At most ITMAX iterations tried.
*
IF( BERR( J ).GT.EPS .AND. TWO*BERR( J ).LE.LSTRES .AND.
$ COUNT.LE.ITMAX ) THEN
*
* Update solution and try again.
*
CALL DPBTRS( UPLO, N, KD, 1, AFB, LDAFB, WORK( N+1 ), N,
$ INFO )
CALL DAXPY( N, ONE, WORK( N+1 ), 1, X( 1, J ), 1 )
LSTRES = BERR( J )
COUNT = COUNT + 1
GO TO 20
END IF
*
* Bound error from formula
*
* norm(X - XTRUE) / norm(X) .le. FERR =
* norm( abs(inv(A))*
* ( abs(R) + NZ*EPS*( abs(A)*abs(X)+abs(B) ))) / norm(X)
*
* where
* norm(Z) is the magnitude of the largest component of Z
* inv(A) is the inverse of A
* abs(Z) is the componentwise absolute value of the matrix or
* vector Z
* NZ is the maximum number of nonzeros in any row of A, plus 1
* EPS is machine epsilon
*
* The i-th component of abs(R)+NZ*EPS*(abs(A)*abs(X)+abs(B))
* is incremented by SAFE1 if the i-th component of
* abs(A)*abs(X) + abs(B) is less than SAFE2.
*
* Use DLACN2 to estimate the infinity-norm of the matrix
* inv(A) * diag(W),
* where W = abs(R) + NZ*EPS*( abs(A)*abs(X)+abs(B) )))
*
DO 90 I = 1, N
IF( WORK( I ).GT.SAFE2 ) THEN
WORK( I ) = ABS( WORK( N+I ) ) + NZ*EPS*WORK( I )
ELSE
WORK( I ) = ABS( WORK( N+I ) ) + NZ*EPS*WORK( I ) + SAFE1
END IF
90 CONTINUE
*
KASE = 0
100 CONTINUE
CALL DLACN2( N, WORK( 2*N+1 ), WORK( N+1 ), IWORK, FERR( J ),
$ KASE, ISAVE )
IF( KASE.NE.0 ) THEN
IF( KASE.EQ.1 ) THEN
*
* Multiply by diag(W)*inv(A**T).
*
CALL DPBTRS( UPLO, N, KD, 1, AFB, LDAFB, WORK( N+1 ), N,
$ INFO )
DO 110 I = 1, N
WORK( N+I ) = WORK( N+I )*WORK( I )
110 CONTINUE
ELSE IF( KASE.EQ.2 ) THEN
*
* Multiply by inv(A)*diag(W).
*
DO 120 I = 1, N
WORK( N+I ) = WORK( N+I )*WORK( I )
120 CONTINUE
CALL DPBTRS( UPLO, N, KD, 1, AFB, LDAFB, WORK( N+1 ), N,
$ INFO )
END IF
GO TO 100
END IF
*
* Normalize error.
*
LSTRES = ZERO
DO 130 I = 1, N
LSTRES = MAX( LSTRES, ABS( X( I, J ) ) )
130 CONTINUE
IF( LSTRES.NE.ZERO )
$ FERR( J ) = FERR( J ) / LSTRES
*
140 CONTINUE
*
RETURN
*
* End of DPBRFS
*
END