factor a band matrix using gaussian elimination.
dgbfa is usually called by dgbco, but it can be called
directly with a saving in time if rcond
is not needed.
if a
is a band matrix, the following program segment
will set up the input.
ml = (band width below the diagonal)
mu = (band width above the diagonal)
m = ml + mu + 1
do j = 1, n
i1 = max(1, j-mu)
i2 = min(n, j+ml)
do i = i1, i2
k = i - j + m
abd(k,j) = a(i,j)
end do
end do
this uses rows ml+1
through 2*ml+mu+1
of abd
.
in addition, the first ml
rows in abd
are used for
elements generated during the triangularization.
the total number of rows needed in abd
is 2*ml+mu+1
.
the ml+mu
by ml+mu
upper left triangle and the
ml
by ml
lower right triangle are not referenced.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=wp), | intent(inout) | :: | abd(lda,*) |
|
||
integer, | intent(in) | :: | lda |
the leading dimension of the array |
||
integer, | intent(in) | :: | n |
the order of the original matrix. |
||
integer, | intent(in) | :: | ml |
number of diagonals below the main diagonal.
|
||
integer, | intent(in) | :: | mu |
number of diagonals above the main diagonal.
|
||
integer, | intent(out) | :: | ipvt(*) |
an integer vector of pivot indices. |
||
integer, | intent(out) | :: | info |
subroutine dgbfa(abd,lda,n,ml,mu,ipvt,info) integer,intent(in) :: lda !! the leading dimension of the array `abd` . !! `lda` must be `>= 2*ml + mu + 1` . integer,intent(in) :: n !! the order of the original matrix. integer,intent(in) :: ml !! number of diagonals below the main diagonal. !! `0 <= ml < n` . integer,intent(in) :: mu !! number of diagonals above the main diagonal. !! `0 <= mu < n` . !! more efficient if `ml <= mu` . integer,intent(out) :: ipvt(*) !! an integer vector of pivot indices. integer,intent(out) :: info !! * 0 normal value. !! * k if `u(k,k) == 0.0` . this is not an error !! condition for this subroutine, but it does !! indicate that [[dgbsl]] will divide by zero if !! called. use rcond in [[dgbco]] for a reliable !! indication of singularity. real(wp),intent(inout) :: abd(lda,*) !! * **input:** contains the matrix in band storage. the columns !! of the matrix are stored in the columns of `abd` and !! the diagonals of the matrix are stored in rows !! `ml+1` through `2*ml+mu+1` of `abd` . !! see the comments below for details. !! * **output:** an upper triangular matrix in band storage and !! the multipliers which were used to obtain it. !! the factorization can be written `a = l*u` where !! `l` is a product of permutation and unit lower !! triangular matrices and `u` is upper triangular. real(wp) :: t integer :: i , i0 , j , ju , jz , j0 , j1 , k , kp1 , l , & lm , m , mm , nm1 #ifdef HAS_BLAS ! user is linking against an external BLAS library integer,external :: idamax #endif m = ml + mu + 1 info = 0 ! zero initial fill-in columns j0 = mu + 2 j1 = min(n,m) - 1 if ( j1>=j0 ) then do jz = j0 , j1 i0 = m + 1 - jz do i = i0 , ml abd(i,jz) = 0.0_wp enddo enddo endif jz = j1 ju = 0 ! gaussian elimination with partial pivoting nm1 = n - 1 if ( nm1>=1 ) then do k = 1 , nm1 kp1 = k + 1 ! zero next fill-in column jz = jz + 1 if ( jz<=n ) then if ( ml>=1 ) then do i = 1 , ml abd(i,jz) = 0.0_wp enddo endif endif ! find l = pivot index lm = min(ml,n-k) l = idamax(lm+1,abd(m,k),1) + m - 1 ipvt(k) = l + k - m ! zero pivot implies this column already triangularized if ( abd(l,k)==0.0_wp ) then info = k else ! interchange if necessary if ( l/=m ) then t = abd(l,k) abd(l,k) = abd(m,k) abd(m,k) = t endif ! compute multipliers t = -1.0_wp/abd(m,k) call dscal(lm,t,abd(m+1,k),1) ! row elimination with column indexing ju = min(max(ju,mu+ipvt(k)),n) mm = m if ( ju>=kp1 ) then do j = kp1 , ju l = l - 1 mm = mm - 1 t = abd(l,j) if ( l/=mm ) then abd(l,j) = abd(mm,j) abd(mm,j) = t endif call daxpy(lm,t,abd(m+1,k),1,abd(mm+1,j),1) enddo endif endif enddo endif ipvt(n) = n if ( abd(m,n)==0.0_wp ) info = n end subroutine dgbfa