1985 lines
58 KiB
Fortran
1985 lines
58 KiB
Fortran
|
module minpack
|
||
|
|
||
|
use const_and_precisions, only : wp_
|
||
|
implicit none
|
||
|
|
||
|
contains
|
||
|
|
||
|
subroutine hybrj1(fcn,n,x,fvec,fjac,ldfjac,tol,info,wa,lwa)
|
||
|
use const_and_precisions, only : zero, one
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: n, ldfjac, lwa
|
||
|
integer, intent(out) :: info
|
||
|
real(wp_), intent(in) :: tol
|
||
|
real(wp_), intent(out) :: wa(lwa)
|
||
|
real(wp_), intent(inout) :: fvec(n), fjac(ldfjac,n), x(n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine hybrj1
|
||
|
!
|
||
|
! the purpose of hybrj1 is to find a zero of a system of
|
||
|
! n nonlinear functions in n variables by a modification
|
||
|
! of the powell hybrid method. this is done by using the
|
||
|
! more general nonlinear equation solver hybrj. the user
|
||
|
! must provide a subroutine which calculates the functions
|
||
|
! and the jacobian.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine hybrj1(fcn,n,x,fvec,fjac,ldfjac,tol,info,wa,lwa)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! fcn is the name of the user-supplied subroutine which
|
||
|
! calculates the functions and the jacobian. fcn must
|
||
|
! be declared in an external statement in the user
|
||
|
! calling program, and should be written as follows.
|
||
|
!
|
||
|
! subroutine fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
! integer n,ldfjac,iflag
|
||
|
! real(8) x(n),fvec(n),fjac(ldfjac,n)
|
||
|
! ----------
|
||
|
! if iflag = 1 calculate the functions at x and
|
||
|
! return this vector in fvec. do not alter fjac.
|
||
|
! if iflag = 2 calculate the jacobian at x and
|
||
|
! return this matrix in fjac. do not alter fvec.
|
||
|
! ---------
|
||
|
! return
|
||
|
! end
|
||
|
!
|
||
|
! the value of iflag should not be changed by fcn unless
|
||
|
! the user wants to terminate execution of hybrj1.
|
||
|
! in this case set iflag to a negative integer.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of functions and variables.
|
||
|
!
|
||
|
! x is an array of length n. on input x must contain
|
||
|
! an initial estimate of the solution vector. on output x
|
||
|
! contains the final estimate of the solution vector.
|
||
|
!
|
||
|
! fvec is an output array of length n which contains
|
||
|
! the functions evaluated at the output x.
|
||
|
!
|
||
|
! fjac is an output n by n array which contains the
|
||
|
! orthogonal matrix q produced by the qr factorization
|
||
|
! of the final approximate jacobian.
|
||
|
!
|
||
|
! ldfjac is a positive integer input variable not less than n
|
||
|
! which specifies the leading dimension of the array fjac.
|
||
|
!
|
||
|
! tol is a nonnegative input variable. termination occurs
|
||
|
! when the algorithm estimates that the relative error
|
||
|
! between x and the solution is at most tol.
|
||
|
!
|
||
|
! info is an integer output variable. if the user has
|
||
|
! terminated execution, info is set to the (negative)
|
||
|
! value of iflag. see description of fcn. otherwise,
|
||
|
! info is set as follows.
|
||
|
!
|
||
|
! info = 0 improper input parameters.
|
||
|
!
|
||
|
! info = 1 algorithm estimates that the relative error
|
||
|
! between x and the solution is at most tol.
|
||
|
!
|
||
|
! info = 2 number of calls to fcn with iflag = 1 has
|
||
|
! reached 100*(n+1).
|
||
|
!
|
||
|
! info = 3 tol is too small. no further improvement in
|
||
|
! the approximate solution x is possible.
|
||
|
!
|
||
|
! info = 4 iteration is not making good progress.
|
||
|
!
|
||
|
! wa is a work array of length lwa.
|
||
|
!
|
||
|
! lwa is a positive integer input variable not less than
|
||
|
! (n*(n+13))/2.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! user-supplied ...... fcn
|
||
|
!
|
||
|
! minpack-supplied ... hybrj
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: j, lr, maxfev, mode, nfev, njev, nprint
|
||
|
real(wp_) :: xtol
|
||
|
! parameters
|
||
|
real(wp_), parameter :: factor=1.0e2_wp_
|
||
|
|
||
|
interface
|
||
|
subroutine fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
use const_and_precisions, only : wp_
|
||
|
implicit none
|
||
|
integer, intent(in) :: n,ldfjac,iflag
|
||
|
real(wp_), intent(in) :: x(n)
|
||
|
real(wp_), intent(inout) :: fvec(n),fjac(ldfjac,n)
|
||
|
end subroutine fcn
|
||
|
end interface
|
||
|
|
||
|
info = 0
|
||
|
!
|
||
|
! check the input parameters for errors.
|
||
|
!
|
||
|
if (n <= 0 .or. ldfjac < n .or. tol < zero &
|
||
|
.or. lwa < (n*(n + 13))/2) return
|
||
|
!
|
||
|
! call hybrj.
|
||
|
!
|
||
|
maxfev = 100*(n + 1)
|
||
|
xtol = tol
|
||
|
mode = 2
|
||
|
do j = 1, n
|
||
|
wa(j) = one
|
||
|
end do
|
||
|
nprint = 0
|
||
|
lr = (n*(n + 1))/2
|
||
|
call hybrj(fcn,n,x,fvec,fjac,ldfjac,xtol,maxfev,wa(1),mode, &
|
||
|
factor,nprint,info,nfev,njev,wa(6*n+1),lr,wa(n+1), &
|
||
|
wa(2*n+1),wa(3*n+1),wa(4*n+1),wa(5*n+1))
|
||
|
if (info == 5) info = 4
|
||
|
end subroutine hybrj1
|
||
|
|
||
|
subroutine hybrj(fcn,n,x,fvec,fjac,ldfjac,xtol,maxfev,diag,mode, &
|
||
|
factor,nprint,info,nfev,njev,r,lr,qtf,wa1,wa2, &
|
||
|
wa3,wa4)
|
||
|
use const_and_precisions, only : zero, one, epsmch=>comp_eps
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: n, ldfjac, maxfev, mode, nprint, lr
|
||
|
integer, intent(out) :: info, nfev, njev
|
||
|
real(wp_), intent(in) :: xtol, factor
|
||
|
real(wp_), intent(out) :: fvec(n), fjac(ldfjac,n), r(lr), qtf(n), &
|
||
|
wa1(n), wa2(n), wa3(n), wa4(n)
|
||
|
real(wp_), intent(inout) :: x(n), diag(n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine hybrj
|
||
|
!
|
||
|
! the purpose of hybrj is to find a zero of a system of
|
||
|
! n nonlinear functions in n variables by a modification
|
||
|
! of the powell hybrid method. the user must provide a
|
||
|
! subroutine which calculates the functions and the jacobian.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine hybrj(fcn,n,x,fvec,fjac,ldfjac,xtol,maxfev,diag,
|
||
|
! mode,factor,nprint,info,nfev,njev,r,lr,qtf,
|
||
|
! wa1,wa2,wa3,wa4)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! fcn is the name of the user-supplied subroutine which
|
||
|
! calculates the functions and the jacobian. fcn must
|
||
|
! be declared in an external statement in the user
|
||
|
! calling program, and should be written as follows.
|
||
|
!
|
||
|
! subroutine fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
! integer n,ldfjac,iflag
|
||
|
! real(8) x(n),fvec(n),fjac(ldfjac,n)
|
||
|
! ----------
|
||
|
! if iflag = 1 calculate the functions at x and
|
||
|
! return this vector in fvec. do not alter fjac.
|
||
|
! if iflag = 2 calculate the jacobian at x and
|
||
|
! return this matrix in fjac. do not alter fvec.
|
||
|
! ---------
|
||
|
! return
|
||
|
! end
|
||
|
!
|
||
|
! the value of iflag should not be changed by fcn unless
|
||
|
! the user wants to terminate execution of hybrj.
|
||
|
! in this case set iflag to a negative integer.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of functions and variables.
|
||
|
!
|
||
|
! x is an array of length n. on input x must contain
|
||
|
! an initial estimate of the solution vector. on output x
|
||
|
! contains the final estimate of the solution vector.
|
||
|
!
|
||
|
! fvec is an output array of length n which contains
|
||
|
! the functions evaluated at the output x.
|
||
|
!
|
||
|
! fjac is an output n by n array which contains the
|
||
|
! orthogonal matrix q produced by the qr factorization
|
||
|
! of the final approximate jacobian.
|
||
|
!
|
||
|
! ldfjac is a positive integer input variable not less than n
|
||
|
! which specifies the leading dimension of the array fjac.
|
||
|
!
|
||
|
! xtol is a nonnegative input variable. termination
|
||
|
! occurs when the relative error between two consecutive
|
||
|
! iterates is at most xtol.
|
||
|
!
|
||
|
! maxfev is a positive integer input variable. termination
|
||
|
! occurs when the number of calls to fcn with iflag = 1
|
||
|
! has reached maxfev.
|
||
|
!
|
||
|
! diag is an array of length n. if mode = 1 (see
|
||
|
! below), diag is internally set. if mode = 2, diag
|
||
|
! must contain positive entries that serve as
|
||
|
! multiplicative scale factors for the variables.
|
||
|
!
|
||
|
! mode is an integer input variable. if mode = 1, the
|
||
|
! variables will be scaled internally. if mode = 2,
|
||
|
! the scaling is specified by the input diag. other
|
||
|
! values of mode are equivalent to mode = 1.
|
||
|
!
|
||
|
! factor is a positive input variable used in determining the
|
||
|
! initial step bound. this bound is set to the product of
|
||
|
! factor and the euclidean norm of diag*x if nonzero, or else
|
||
|
! to factor itself. in most cases factor should lie in the
|
||
|
! interval (.1,100.). 100. is a generally recommended value.
|
||
|
!
|
||
|
! nprint is an integer input variable that enables controlled
|
||
|
! printing of iterates if it is positive. in this case,
|
||
|
! fcn is called with iflag = 0 at the beginning of the first
|
||
|
! iteration and every nprint iterations thereafter and
|
||
|
! immediately prior to return, with x and fvec available
|
||
|
! for printing. fvec and fjac should not be altered.
|
||
|
! if nprint is not positive, no special calls of fcn
|
||
|
! with iflag = 0 are made.
|
||
|
!
|
||
|
! info is an integer output variable. if the user has
|
||
|
! terminated execution, info is set to the (negative)
|
||
|
! value of iflag. see description of fcn. otherwise,
|
||
|
! info is set as follows.
|
||
|
!
|
||
|
! info = 0 improper input parameters.
|
||
|
!
|
||
|
! info = 1 relative error between two consecutive iterates
|
||
|
! is at most xtol.
|
||
|
!
|
||
|
! info = 2 number of calls to fcn with iflag = 1 has
|
||
|
! reached maxfev.
|
||
|
!
|
||
|
! info = 3 xtol is too small. no further improvement in
|
||
|
! the approximate solution x is possible.
|
||
|
!
|
||
|
! info = 4 iteration is not making good progress, as
|
||
|
! measured by the improvement from the last
|
||
|
! five jacobian evaluations.
|
||
|
!
|
||
|
! info = 5 iteration is not making good progress, as
|
||
|
! measured by the improvement from the last
|
||
|
! ten iterations.
|
||
|
!
|
||
|
! nfev is an integer output variable set to the number of
|
||
|
! calls to fcn with iflag = 1.
|
||
|
!
|
||
|
! njev is an integer output variable set to the number of
|
||
|
! calls to fcn with iflag = 2.
|
||
|
!
|
||
|
! r is an output array of length lr which contains the
|
||
|
! upper triangular matrix produced by the qr factorization
|
||
|
! of the final approximate jacobian, stored rowwise.
|
||
|
!
|
||
|
! lr is a positive integer input variable not less than
|
||
|
! (n*(n+1))/2.
|
||
|
!
|
||
|
! qtf is an output array of length n which contains
|
||
|
! the vector (q transpose)*fvec.
|
||
|
!
|
||
|
! wa1, wa2, wa3, and wa4 are work arrays of length n.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! user-supplied ...... fcn
|
||
|
!
|
||
|
! minpack-supplied ... dogleg,enorm,
|
||
|
! qform,qrfac,r1mpyq,r1updt
|
||
|
!
|
||
|
! fortran-supplied ... abs,dmax1,dmin1,mod
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, iflag, iter, j, jm1, l, ncfail, ncsuc, nslow1, nslow2
|
||
|
integer, dimension(1) :: iwa
|
||
|
logical :: jeval, sing
|
||
|
real(wp_) :: actred, delta, fnorm, fnorm1, pnorm, prered, &
|
||
|
ratio, summ, temp, xnorm
|
||
|
! parameters
|
||
|
real(wp_), parameter :: p1 = 1.0e-1_wp_, p5 = 5.0e-1_wp_, &
|
||
|
p001 = 1.0e-3_wp_, p0001 = 1.0e-4_wp_
|
||
|
|
||
|
interface
|
||
|
subroutine fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
use const_and_precisions, only : wp_
|
||
|
implicit none
|
||
|
integer, intent(in) :: n,ldfjac,iflag
|
||
|
real(wp_), intent(in) :: x(n)
|
||
|
real(wp_), intent(inout) :: fvec(n),fjac(ldfjac,n)
|
||
|
end subroutine fcn
|
||
|
end interface
|
||
|
!
|
||
|
info = 0
|
||
|
iflag = 0
|
||
|
nfev = 0
|
||
|
njev = 0
|
||
|
!
|
||
|
! check the input parameters for errors.
|
||
|
!
|
||
|
if (n <= 0 .or. ldfjac < n .or. xtol < zero &
|
||
|
.or. maxfev <= 0 .or. factor <= zero &
|
||
|
.or. lr < (n*(n + 1))/2) go to 300
|
||
|
if (mode == 2) then
|
||
|
do j = 1, n
|
||
|
if (diag(j) <= zero) go to 300
|
||
|
end do
|
||
|
end if
|
||
|
!
|
||
|
! evaluate the function at the starting point
|
||
|
! and calculate its norm.
|
||
|
!
|
||
|
iflag = 1
|
||
|
call fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
nfev = 1
|
||
|
if (iflag < 0) go to 300
|
||
|
fnorm = enorm(n,fvec)
|
||
|
!
|
||
|
! initialize iteration counter and monitors.
|
||
|
!
|
||
|
iter = 1
|
||
|
ncsuc = 0
|
||
|
ncfail = 0
|
||
|
nslow1 = 0
|
||
|
nslow2 = 0
|
||
|
!
|
||
|
! beginning of the outer loop.
|
||
|
!
|
||
|
do
|
||
|
jeval = .true.
|
||
|
!
|
||
|
! calculate the jacobian matrix.
|
||
|
!
|
||
|
iflag = 2
|
||
|
call fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
njev = njev + 1
|
||
|
if (iflag < 0) go to 300
|
||
|
!
|
||
|
! compute the qr factorization of the jacobian.
|
||
|
!
|
||
|
call qrfac(n,n,fjac,ldfjac,.false.,iwa,1,wa1,wa2,wa3)
|
||
|
!
|
||
|
! on the first iteration and if mode is 1, scale according
|
||
|
! to the norms of the columns of the initial jacobian.
|
||
|
!
|
||
|
if (iter == 1) then
|
||
|
if (mode /= 2) then
|
||
|
do j = 1, n
|
||
|
diag(j) = wa2(j)
|
||
|
if (wa2(j) == zero) diag(j) = one
|
||
|
end do
|
||
|
end if
|
||
|
!
|
||
|
! on the first iteration, calculate the norm of the scaled x
|
||
|
! and initialize the step bound delta.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
wa3(j) = diag(j)*x(j)
|
||
|
end do
|
||
|
xnorm = enorm(n,wa3)
|
||
|
delta = factor*xnorm
|
||
|
if (delta == zero) delta = factor
|
||
|
end if
|
||
|
!
|
||
|
! form (q transpose)*fvec and store in qtf.
|
||
|
!
|
||
|
do i = 1, n
|
||
|
qtf(i) = fvec(i)
|
||
|
end do
|
||
|
do j = 1, n
|
||
|
if (fjac(j,j) /= zero) then
|
||
|
summ = zero
|
||
|
do i = j, n
|
||
|
summ = summ + fjac(i,j)*qtf(i)
|
||
|
end do
|
||
|
temp = -summ/fjac(j,j)
|
||
|
do i = j, n
|
||
|
qtf(i) = qtf(i) + fjac(i,j)*temp
|
||
|
end do
|
||
|
end if
|
||
|
end do
|
||
|
!
|
||
|
! copy the triangular factor of the qr factorization into r.
|
||
|
!
|
||
|
sing = .false.
|
||
|
do j = 1, n
|
||
|
l = j
|
||
|
jm1 = j - 1
|
||
|
do i = 1, jm1
|
||
|
r(l) = fjac(i,j)
|
||
|
l = l + n - i
|
||
|
end do
|
||
|
r(l) = wa1(j)
|
||
|
if (wa1(j) == zero) sing = .true.
|
||
|
end do
|
||
|
!
|
||
|
! accumulate the orthogonal factor in fjac.
|
||
|
!
|
||
|
call qform(n,n,fjac,ldfjac,wa1)
|
||
|
!
|
||
|
! rescale if necessary.
|
||
|
!
|
||
|
if (mode /= 2) then
|
||
|
do j = 1, n
|
||
|
diag(j) = dmax1(diag(j),wa2(j))
|
||
|
end do
|
||
|
end if
|
||
|
!
|
||
|
! beginning of the inner loop.
|
||
|
!
|
||
|
do
|
||
|
!
|
||
|
! if requested, call fcn to enable printing of iterates.
|
||
|
!
|
||
|
if (nprint > 0) then
|
||
|
iflag = 0
|
||
|
if (mod(iter-1,nprint) == 0) call fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
if (iflag < 0) go to 300
|
||
|
end if
|
||
|
!
|
||
|
! determine the direction p.
|
||
|
!
|
||
|
call dogleg(n,r,lr,diag,qtf,delta,wa1,wa2,wa3)
|
||
|
!
|
||
|
! store the direction p and x + p. calculate the norm of p.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
wa1(j) = -wa1(j)
|
||
|
wa2(j) = x(j) + wa1(j)
|
||
|
wa3(j) = diag(j)*wa1(j)
|
||
|
end do
|
||
|
pnorm = enorm(n,wa3)
|
||
|
!
|
||
|
! on the first iteration, adjust the initial step bound.
|
||
|
!
|
||
|
if (iter == 1) delta = dmin1(delta,pnorm)
|
||
|
!
|
||
|
! evaluate the function at x + p and calculate its norm.
|
||
|
!
|
||
|
iflag = 1
|
||
|
call fcn(n,wa2,wa4,fjac,ldfjac,iflag)
|
||
|
nfev = nfev + 1
|
||
|
if (iflag < 0) go to 300
|
||
|
fnorm1 = enorm(n,wa4)
|
||
|
!
|
||
|
! compute the scaled actual reduction.
|
||
|
!
|
||
|
actred = -one
|
||
|
if (fnorm1 < fnorm) actred = one - (fnorm1/fnorm)**2
|
||
|
!
|
||
|
! compute the scaled predicted reduction.
|
||
|
!
|
||
|
l = 1
|
||
|
do i = 1, n
|
||
|
summ = zero
|
||
|
do j = i, n
|
||
|
summ = summ + r(l)*wa1(j)
|
||
|
l = l + 1
|
||
|
end do
|
||
|
wa3(i) = qtf(i) + summ
|
||
|
end do
|
||
|
temp = enorm(n,wa3)
|
||
|
prered = zero
|
||
|
if (temp < fnorm) prered = one - (temp/fnorm)**2
|
||
|
!
|
||
|
! compute the ratio of the actual to the predicted
|
||
|
! reduction.
|
||
|
!
|
||
|
ratio = zero
|
||
|
if (prered > zero) ratio = actred/prered
|
||
|
!
|
||
|
! update the step bound.
|
||
|
!
|
||
|
if (ratio < p1) then
|
||
|
ncsuc = 0
|
||
|
ncfail = ncfail + 1
|
||
|
delta = p5*delta
|
||
|
else
|
||
|
ncfail = 0
|
||
|
ncsuc = ncsuc + 1
|
||
|
if (ratio >= p5 .or. ncsuc > 1) delta = dmax1(delta,pnorm/p5)
|
||
|
if (abs(ratio-one) <= p1) delta = pnorm/p5
|
||
|
end if
|
||
|
!
|
||
|
! test for successful iteration.
|
||
|
!
|
||
|
if (ratio >= p0001) then
|
||
|
!
|
||
|
! successful iteration. update x, fvec, and their norms.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
x(j) = wa2(j)
|
||
|
wa2(j) = diag(j)*x(j)
|
||
|
fvec(j) = wa4(j)
|
||
|
end do
|
||
|
xnorm = enorm(n,wa2)
|
||
|
fnorm = fnorm1
|
||
|
iter = iter + 1
|
||
|
end if
|
||
|
!
|
||
|
! determine the progress of the iteration.
|
||
|
!
|
||
|
nslow1 = nslow1 + 1
|
||
|
if (actred >= p001) nslow1 = 0
|
||
|
if (jeval) nslow2 = nslow2 + 1
|
||
|
if (actred >= p1) nslow2 = 0
|
||
|
!
|
||
|
! test for convergence.
|
||
|
!
|
||
|
if (delta <= xtol*xnorm .or. fnorm == zero) info = 1
|
||
|
if (info /= 0) go to 300
|
||
|
!
|
||
|
! tests for termination and stringent tolerances.
|
||
|
!
|
||
|
if (nfev >= maxfev) info = 2
|
||
|
if (p1*dmax1(p1*delta,pnorm) <= epsmch*xnorm) info = 3
|
||
|
if (nslow2 == 5) info = 4
|
||
|
if (nslow1 == 10) info = 5
|
||
|
if (info /= 0) go to 300
|
||
|
!
|
||
|
! criterion for recalculating jacobian.
|
||
|
!
|
||
|
if (ncfail == 2) exit
|
||
|
!
|
||
|
! calculate the rank one modification to the jacobian
|
||
|
! and update qtf if necessary.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
summ = zero
|
||
|
do i = 1, n
|
||
|
summ = summ + fjac(i,j)*wa4(i)
|
||
|
end do
|
||
|
wa2(j) = (summ - wa3(j))/pnorm
|
||
|
wa1(j) = diag(j)*((diag(j)*wa1(j))/pnorm)
|
||
|
if (ratio >= p0001) qtf(j) = summ
|
||
|
end do
|
||
|
!
|
||
|
! compute the qr factorization of the updated jacobian.
|
||
|
!
|
||
|
call r1updt(n,n,r,lr,wa1,wa2,wa3,sing)
|
||
|
call r1mpyq(n,n,fjac,ldfjac,wa2,wa3)
|
||
|
call r1mpyq(1,n,qtf,1,wa2,wa3)
|
||
|
!
|
||
|
! end of the inner loop.
|
||
|
!
|
||
|
jeval = .false.
|
||
|
end do
|
||
|
!
|
||
|
! end of the outer loop.
|
||
|
!
|
||
|
end do
|
||
|
300 continue
|
||
|
!
|
||
|
! termination, either normal or user imposed.
|
||
|
!
|
||
|
if (iflag < 0) info = iflag
|
||
|
iflag = 0
|
||
|
if (nprint > 0) call fcn(n,x,fvec,fjac,ldfjac,iflag)
|
||
|
end subroutine hybrj
|
||
|
|
||
|
subroutine hybrj1mv(fcn,n,x,f0,fvec,fjac,ldfjac,tol,info,wa,lwa)
|
||
|
use const_and_precisions, only : zero, one
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: n, ldfjac, lwa
|
||
|
integer, intent(out) :: info
|
||
|
real(wp_), intent(in) :: tol,f0(n)
|
||
|
real(wp_), intent(out) :: wa(lwa)
|
||
|
real(wp_), intent(inout) :: fvec(n), fjac(ldfjac,n), x(n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine hybrj1mv
|
||
|
!
|
||
|
! the purpose of hybrj1mv is to find a zero of a system of
|
||
|
! n nonlinear functions in n variables by a modification
|
||
|
! of the powell hybrid method. this is done by using the
|
||
|
! more general nonlinear equation solver hybrjmv. the user
|
||
|
! must provide a subroutine which calculates the functions
|
||
|
! and the jacobian.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine hybrj1mv(fcn,n,x,f0,fvec,fjac,ldfjac,tol,info,wa,lwa)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! fcn is the name of the user-supplied subroutine which
|
||
|
! calculates the functions and the jacobian. fcn must
|
||
|
! be declared in an external statement in the user
|
||
|
! calling program, and should be written as follows.
|
||
|
!
|
||
|
! subroutine fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
! integer n,ldfjac,iflag
|
||
|
! real(8) x(n),fvec(n),fjac(ldfjac,n)
|
||
|
! ----------
|
||
|
! if iflag = 1 calculate the functions at x and
|
||
|
! return this vector in fvec. do not alter fjac.
|
||
|
! if iflag = 2 calculate the jacobian at x and
|
||
|
! return this matrix in fjac. do not alter fvec.
|
||
|
! ---------
|
||
|
! return
|
||
|
! end
|
||
|
!
|
||
|
! the value of iflag should not be changed by fcn unless
|
||
|
! the user wants to terminate execution of hybrj1mv.
|
||
|
! in this case set iflag to a negative integer.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of functions and variables.
|
||
|
!
|
||
|
! x is an array of length n. on input x must contain
|
||
|
! an initial estimate of the solution vector. on output x
|
||
|
! contains the final estimate of the solution vector.
|
||
|
!
|
||
|
! fvec is an output array of length n which contains
|
||
|
! the functions evaluated at the output x.
|
||
|
!
|
||
|
! fjac is an output n by n array which contains the
|
||
|
! orthogonal matrix q produced by the qr factorization
|
||
|
! of the final approximate jacobian.
|
||
|
!
|
||
|
! ldfjac is a positive integer input variable not less than n
|
||
|
! which specifies the leading dimension of the array fjac.
|
||
|
!
|
||
|
! tol is a nonnegative input variable. termination occurs
|
||
|
! when the algorithm estimates that the relative error
|
||
|
! between x and the solution is at most tol.
|
||
|
!
|
||
|
! info is an integer output variable. if the user has
|
||
|
! terminated execution, info is set to the (negative)
|
||
|
! value of iflag. see description of fcn. otherwise,
|
||
|
! info is set as follows.
|
||
|
!
|
||
|
! info = 0 improper input parameters.
|
||
|
!
|
||
|
! info = 1 algorithm estimates that the relative error
|
||
|
! between x and the solution is at most tol.
|
||
|
!
|
||
|
! info = 2 number of calls to fcn with iflag = 1 has
|
||
|
! reached 100*(n+1).
|
||
|
!
|
||
|
! info = 3 tol is too small. no further improvement in
|
||
|
! the approximate solution x is possible.
|
||
|
!
|
||
|
! info = 4 iteration is not making good progress.
|
||
|
!
|
||
|
! wa is a work array of length lwa.
|
||
|
!
|
||
|
! lwa is a positive integer input variable not less than
|
||
|
! (n*(n+13))/2.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! user-supplied ...... fcn
|
||
|
!
|
||
|
! minpack-supplied ... hybrjmv
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: j, lr, maxfev, mode, nfev, njev, nprint
|
||
|
real(wp_) :: xtol
|
||
|
! parameters
|
||
|
real(wp_), parameter :: factor=1.0e2_wp_
|
||
|
|
||
|
interface
|
||
|
subroutine fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
use const_and_precisions, only : wp_
|
||
|
implicit none
|
||
|
integer, intent(in) :: n,ldfjac,iflag
|
||
|
real(wp_), intent(in) :: x(n),f0(n)
|
||
|
real(wp_), intent(inout) :: fvec(n),fjac(ldfjac,n)
|
||
|
end subroutine fcn
|
||
|
end interface
|
||
|
|
||
|
info = 0
|
||
|
!
|
||
|
! check the input parameters for errors.
|
||
|
!
|
||
|
if (n <= 0 .or. ldfjac < n .or. tol < zero &
|
||
|
.or. lwa < (n*(n + 13))/2) return
|
||
|
!
|
||
|
! call hybrjmv.
|
||
|
!
|
||
|
maxfev = 100*(n + 1)
|
||
|
xtol = tol
|
||
|
mode = 2
|
||
|
do j = 1, n
|
||
|
wa(j) = one
|
||
|
end do
|
||
|
nprint = 0
|
||
|
lr = (n*(n + 1))/2
|
||
|
call hybrjmv(fcn,n,x,f0,fvec,fjac,ldfjac,xtol,maxfev,wa(1),mode, &
|
||
|
factor,nprint,info,nfev,njev,wa(6*n+1),lr,wa(n+1), &
|
||
|
wa(2*n+1),wa(3*n+1),wa(4*n+1),wa(5*n+1))
|
||
|
if (info == 5) info = 4
|
||
|
end subroutine hybrj1mv
|
||
|
|
||
|
subroutine hybrjmv(fcn,n,x,f0,fvec,fjac,ldfjac,xtol,maxfev,diag,mode, &
|
||
|
factor,nprint,info,nfev,njev,r,lr,qtf,wa1,wa2, &
|
||
|
wa3,wa4)
|
||
|
use const_and_precisions, only : zero, one, epsmch=>comp_eps
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: n, ldfjac, maxfev, mode, nprint, lr
|
||
|
integer, intent(out) :: info, nfev, njev
|
||
|
real(wp_), intent(in) :: xtol, factor, f0(n)
|
||
|
real(wp_), intent(out) :: fvec(n), fjac(ldfjac,n), r(lr), qtf(n), &
|
||
|
wa1(n), wa2(n), wa3(n), wa4(n)
|
||
|
real(wp_), intent(inout) :: x(n), diag(n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine hybrj
|
||
|
!
|
||
|
! the purpose of hybrj is to find a zero of a system of
|
||
|
! n nonlinear functions in n variables by a modification
|
||
|
! of the powell hybrid method. the user must provide a
|
||
|
! subroutine which calculates the functions and the jacobian.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine hybrj(fcn,n,x,f0,fvec,fjac,ldfjac,xtol,maxfev,diag,
|
||
|
! mode,factor,nprint,info,nfev,njev,r,lr,qtf,
|
||
|
! wa1,wa2,wa3,wa4)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! fcn is the name of the user-supplied subroutine which
|
||
|
! calculates the functions and the jacobian. fcn must
|
||
|
! be declared in an external statement in the user
|
||
|
! calling program, and should be written as follows.
|
||
|
!
|
||
|
! subroutine fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
! integer n,ldfjac,iflag
|
||
|
! real(8) x(n),f0(n),fvec(n),fjac(ldfjac,n)
|
||
|
! ----------
|
||
|
! if iflag = 1 calculate the functions at x and
|
||
|
! return this vector in fvec. do not alter fjac.
|
||
|
! if iflag = 2 calculate the jacobian at x and
|
||
|
! return this matrix in fjac. do not alter fvec.
|
||
|
! ---------
|
||
|
! return
|
||
|
! end
|
||
|
!
|
||
|
! the value of iflag should not be changed by fcn unless
|
||
|
! the user wants to terminate execution of hybrj.
|
||
|
! in this case set iflag to a negative integer.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of functions and variables.
|
||
|
!
|
||
|
! x is an array of length n. on input x must contain
|
||
|
! an initial estimate of the solution vector. on output x
|
||
|
! contains the final estimate of the solution vector.
|
||
|
!
|
||
|
! fvec is an output array of length n which contains
|
||
|
! the functions evaluated at the output x.
|
||
|
!
|
||
|
! fjac is an output n by n array which contains the
|
||
|
! orthogonal matrix q produced by the qr factorization
|
||
|
! of the final approximate jacobian.
|
||
|
!
|
||
|
! ldfjac is a positive integer input variable not less than n
|
||
|
! which specifies the leading dimension of the array fjac.
|
||
|
!
|
||
|
! xtol is a nonnegative input variable. termination
|
||
|
! occurs when the relative error between two consecutive
|
||
|
! iterates is at most xtol.
|
||
|
!
|
||
|
! maxfev is a positive integer input variable. termination
|
||
|
! occurs when the number of calls to fcn with iflag = 1
|
||
|
! has reached maxfev.
|
||
|
!
|
||
|
! diag is an array of length n. if mode = 1 (see
|
||
|
! below), diag is internally set. if mode = 2, diag
|
||
|
! must contain positive entries that serve as
|
||
|
! multiplicative scale factors for the variables.
|
||
|
!
|
||
|
! mode is an integer input variable. if mode = 1, the
|
||
|
! variables will be scaled internally. if mode = 2,
|
||
|
! the scaling is specified by the input diag. other
|
||
|
! values of mode are equivalent to mode = 1.
|
||
|
!
|
||
|
! factor is a positive input variable used in determining the
|
||
|
! initial step bound. this bound is set to the product of
|
||
|
! factor and the euclidean norm of diag*x if nonzero, or else
|
||
|
! to factor itself. in most cases factor should lie in the
|
||
|
! interval (.1,100.). 100. is a generally recommended value.
|
||
|
!
|
||
|
! nprint is an integer input variable that enables controlled
|
||
|
! printing of iterates if it is positive. in this case,
|
||
|
! fcn is called with iflag = 0 at the beginning of the first
|
||
|
! iteration and every nprint iterations thereafter and
|
||
|
! immediately prior to return, with x and fvec available
|
||
|
! for printing. fvec and fjac should not be altered.
|
||
|
! if nprint is not positive, no special calls of fcn
|
||
|
! with iflag = 0 are made.
|
||
|
!
|
||
|
! info is an integer output variable. if the user has
|
||
|
! terminated execution, info is set to the (negative)
|
||
|
! value of iflag. see description of fcn. otherwise,
|
||
|
! info is set as follows.
|
||
|
!
|
||
|
! info = 0 improper input parameters.
|
||
|
!
|
||
|
! info = 1 relative error between two consecutive iterates
|
||
|
! is at most xtol.
|
||
|
!
|
||
|
! info = 2 number of calls to fcn with iflag = 1 has
|
||
|
! reached maxfev.
|
||
|
!
|
||
|
! info = 3 xtol is too small. no further improvement in
|
||
|
! the approximate solution x is possible.
|
||
|
!
|
||
|
! info = 4 iteration is not making good progress, as
|
||
|
! measured by the improvement from the last
|
||
|
! five jacobian evaluations.
|
||
|
!
|
||
|
! info = 5 iteration is not making good progress, as
|
||
|
! measured by the improvement from the last
|
||
|
! ten iterations.
|
||
|
!
|
||
|
! nfev is an integer output variable set to the number of
|
||
|
! calls to fcn with iflag = 1.
|
||
|
!
|
||
|
! njev is an integer output variable set to the number of
|
||
|
! calls to fcn with iflag = 2.
|
||
|
!
|
||
|
! r is an output array of length lr which contains the
|
||
|
! upper triangular matrix produced by the qr factorization
|
||
|
! of the final approximate jacobian, stored rowwise.
|
||
|
!
|
||
|
! lr is a positive integer input variable not less than
|
||
|
! (n*(n+1))/2.
|
||
|
!
|
||
|
! qtf is an output array of length n which contains
|
||
|
! the vector (q transpose)*fvec.
|
||
|
!
|
||
|
! wa1, wa2, wa3, and wa4 are work arrays of length n.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! user-supplied ...... fcn
|
||
|
!
|
||
|
! minpack-supplied ... dogleg,enorm,
|
||
|
! qform,qrfac,r1mpyq,r1updt
|
||
|
!
|
||
|
! fortran-supplied ... abs,dmax1,dmin1,mod
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, iflag, iter, j, jm1, l, ncfail, ncsuc, nslow1, nslow2
|
||
|
integer, dimension(1) :: iwa
|
||
|
logical :: jeval, sing
|
||
|
real(wp_) :: actred, delta, fnorm, fnorm1, pnorm, prered, &
|
||
|
ratio, summ, temp, xnorm
|
||
|
! parameters
|
||
|
real(wp_), parameter :: p1 = 1.0e-1_wp_, p5 = 5.0e-1_wp_, &
|
||
|
p001 = 1.0e-3_wp_, p0001 = 1.0e-4_wp_
|
||
|
|
||
|
interface
|
||
|
subroutine fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
use const_and_precisions, only : wp_
|
||
|
implicit none
|
||
|
integer, intent(in) :: n,ldfjac,iflag
|
||
|
real(wp_), intent(in) :: x(n),f0(n)
|
||
|
real(wp_), intent(inout) :: fvec(n),fjac(ldfjac,n)
|
||
|
end subroutine fcn
|
||
|
end interface
|
||
|
!
|
||
|
info = 0
|
||
|
iflag = 0
|
||
|
nfev = 0
|
||
|
njev = 0
|
||
|
!
|
||
|
! check the input parameters for errors.
|
||
|
!
|
||
|
if (n <= 0 .or. ldfjac < n .or. xtol < zero &
|
||
|
.or. maxfev <= 0 .or. factor <= zero &
|
||
|
.or. lr < (n*(n + 1))/2) go to 300
|
||
|
if (mode == 2) then
|
||
|
do j = 1, n
|
||
|
if (diag(j) <= zero) go to 300
|
||
|
end do
|
||
|
end if
|
||
|
!
|
||
|
! evaluate the function at the starting point
|
||
|
! and calculate its norm.
|
||
|
!
|
||
|
iflag = 1
|
||
|
call fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
nfev = 1
|
||
|
if (iflag < 0) go to 300
|
||
|
fnorm = enorm(n,fvec)
|
||
|
!
|
||
|
! initialize iteration counter and monitors.
|
||
|
!
|
||
|
iter = 1
|
||
|
ncsuc = 0
|
||
|
ncfail = 0
|
||
|
nslow1 = 0
|
||
|
nslow2 = 0
|
||
|
!
|
||
|
! beginning of the outer loop.
|
||
|
!
|
||
|
do
|
||
|
jeval = .true.
|
||
|
!
|
||
|
! calculate the jacobian matrix.
|
||
|
!
|
||
|
iflag = 2
|
||
|
call fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
njev = njev + 1
|
||
|
if (iflag < 0) go to 300
|
||
|
!
|
||
|
! compute the qr factorization of the jacobian.
|
||
|
!
|
||
|
call qrfac(n,n,fjac,ldfjac,.false.,iwa,1,wa1,wa2,wa3)
|
||
|
!
|
||
|
! on the first iteration and if mode is 1, scale according
|
||
|
! to the norms of the columns of the initial jacobian.
|
||
|
!
|
||
|
if (iter == 1) then
|
||
|
if (mode /= 2) then
|
||
|
do j = 1, n
|
||
|
diag(j) = wa2(j)
|
||
|
if (wa2(j) == zero) diag(j) = one
|
||
|
end do
|
||
|
end if
|
||
|
!
|
||
|
! on the first iteration, calculate the norm of the scaled x
|
||
|
! and initialize the step bound delta.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
wa3(j) = diag(j)*x(j)
|
||
|
end do
|
||
|
xnorm = enorm(n,wa3)
|
||
|
delta = factor*xnorm
|
||
|
if (delta == zero) delta = factor
|
||
|
end if
|
||
|
!
|
||
|
! form (q transpose)*fvec and store in qtf.
|
||
|
!
|
||
|
do i = 1, n
|
||
|
qtf(i) = fvec(i)
|
||
|
end do
|
||
|
do j = 1, n
|
||
|
if (fjac(j,j) /= zero) then
|
||
|
summ = zero
|
||
|
do i = j, n
|
||
|
summ = summ + fjac(i,j)*qtf(i)
|
||
|
end do
|
||
|
temp = -summ/fjac(j,j)
|
||
|
do i = j, n
|
||
|
qtf(i) = qtf(i) + fjac(i,j)*temp
|
||
|
end do
|
||
|
end if
|
||
|
end do
|
||
|
!
|
||
|
! copy the triangular factor of the qr factorization into r.
|
||
|
!
|
||
|
sing = .false.
|
||
|
do j = 1, n
|
||
|
l = j
|
||
|
jm1 = j - 1
|
||
|
do i = 1, jm1
|
||
|
r(l) = fjac(i,j)
|
||
|
l = l + n - i
|
||
|
end do
|
||
|
r(l) = wa1(j)
|
||
|
if (wa1(j) == zero) sing = .true.
|
||
|
end do
|
||
|
!
|
||
|
! accumulate the orthogonal factor in fjac.
|
||
|
!
|
||
|
call qform(n,n,fjac,ldfjac,wa1)
|
||
|
!
|
||
|
! rescale if necessary.
|
||
|
!
|
||
|
if (mode /= 2) then
|
||
|
do j = 1, n
|
||
|
diag(j) = dmax1(diag(j),wa2(j))
|
||
|
end do
|
||
|
end if
|
||
|
!
|
||
|
! beginning of the inner loop.
|
||
|
!
|
||
|
do
|
||
|
!
|
||
|
! if requested, call fcn to enable printing of iterates.
|
||
|
!
|
||
|
if (nprint > 0) then
|
||
|
iflag = 0
|
||
|
if (mod(iter-1,nprint) == 0) call fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
if (iflag < 0) go to 300
|
||
|
end if
|
||
|
!
|
||
|
! determine the direction p.
|
||
|
!
|
||
|
call dogleg(n,r,lr,diag,qtf,delta,wa1,wa2,wa3)
|
||
|
!
|
||
|
! store the direction p and x + p. calculate the norm of p.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
wa1(j) = -wa1(j)
|
||
|
wa2(j) = x(j) + wa1(j)
|
||
|
wa3(j) = diag(j)*wa1(j)
|
||
|
end do
|
||
|
pnorm = enorm(n,wa3)
|
||
|
!
|
||
|
! on the first iteration, adjust the initial step bound.
|
||
|
!
|
||
|
if (iter == 1) delta = dmin1(delta,pnorm)
|
||
|
!
|
||
|
! evaluate the function at x + p and calculate its norm.
|
||
|
!
|
||
|
iflag = 1
|
||
|
call fcn(n,wa2,f0,wa4,fjac,ldfjac,iflag)
|
||
|
nfev = nfev + 1
|
||
|
if (iflag < 0) go to 300
|
||
|
fnorm1 = enorm(n,wa4)
|
||
|
!
|
||
|
! compute the scaled actual reduction.
|
||
|
!
|
||
|
actred = -one
|
||
|
if (fnorm1 < fnorm) actred = one - (fnorm1/fnorm)**2
|
||
|
!
|
||
|
! compute the scaled predicted reduction.
|
||
|
!
|
||
|
l = 1
|
||
|
do i = 1, n
|
||
|
summ = zero
|
||
|
do j = i, n
|
||
|
summ = summ + r(l)*wa1(j)
|
||
|
l = l + 1
|
||
|
end do
|
||
|
wa3(i) = qtf(i) + summ
|
||
|
end do
|
||
|
temp = enorm(n,wa3)
|
||
|
prered = zero
|
||
|
if (temp < fnorm) prered = one - (temp/fnorm)**2
|
||
|
!
|
||
|
! compute the ratio of the actual to the predicted
|
||
|
! reduction.
|
||
|
!
|
||
|
ratio = zero
|
||
|
if (prered > zero) ratio = actred/prered
|
||
|
!
|
||
|
! update the step bound.
|
||
|
!
|
||
|
if (ratio < p1) then
|
||
|
ncsuc = 0
|
||
|
ncfail = ncfail + 1
|
||
|
delta = p5*delta
|
||
|
else
|
||
|
ncfail = 0
|
||
|
ncsuc = ncsuc + 1
|
||
|
if (ratio >= p5 .or. ncsuc > 1) delta = dmax1(delta,pnorm/p5)
|
||
|
if (abs(ratio-one) <= p1) delta = pnorm/p5
|
||
|
end if
|
||
|
!
|
||
|
! test for successful iteration.
|
||
|
!
|
||
|
if (ratio >= p0001) then
|
||
|
!
|
||
|
! successful iteration. update x, fvec, and their norms.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
x(j) = wa2(j)
|
||
|
wa2(j) = diag(j)*x(j)
|
||
|
fvec(j) = wa4(j)
|
||
|
end do
|
||
|
xnorm = enorm(n,wa2)
|
||
|
fnorm = fnorm1
|
||
|
iter = iter + 1
|
||
|
end if
|
||
|
!
|
||
|
! determine the progress of the iteration.
|
||
|
!
|
||
|
nslow1 = nslow1 + 1
|
||
|
if (actred >= p001) nslow1 = 0
|
||
|
if (jeval) nslow2 = nslow2 + 1
|
||
|
if (actred >= p1) nslow2 = 0
|
||
|
!
|
||
|
! test for convergence.
|
||
|
!
|
||
|
if (delta <= xtol*xnorm .or. fnorm == zero) info = 1
|
||
|
if (info /= 0) go to 300
|
||
|
!
|
||
|
! tests for termination and stringent tolerances.
|
||
|
!
|
||
|
if (nfev >= maxfev) info = 2
|
||
|
if (p1*dmax1(p1*delta,pnorm) <= epsmch*xnorm) info = 3
|
||
|
if (nslow2 == 5) info = 4
|
||
|
if (nslow1 == 10) info = 5
|
||
|
if (info /= 0) go to 300
|
||
|
!
|
||
|
! criterion for recalculating jacobian.
|
||
|
!
|
||
|
if (ncfail == 2) exit
|
||
|
!
|
||
|
! calculate the rank one modification to the jacobian
|
||
|
! and update qtf if necessary.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
summ = zero
|
||
|
do i = 1, n
|
||
|
summ = summ + fjac(i,j)*wa4(i)
|
||
|
end do
|
||
|
wa2(j) = (summ - wa3(j))/pnorm
|
||
|
wa1(j) = diag(j)*((diag(j)*wa1(j))/pnorm)
|
||
|
if (ratio >= p0001) qtf(j) = summ
|
||
|
end do
|
||
|
!
|
||
|
! compute the qr factorization of the updated jacobian.
|
||
|
!
|
||
|
call r1updt(n,n,r,lr,wa1,wa2,wa3,sing)
|
||
|
call r1mpyq(n,n,fjac,ldfjac,wa2,wa3)
|
||
|
call r1mpyq(1,n,qtf,1,wa2,wa3)
|
||
|
!
|
||
|
! end of the inner loop.
|
||
|
!
|
||
|
jeval = .false.
|
||
|
end do
|
||
|
!
|
||
|
! end of the outer loop.
|
||
|
!
|
||
|
end do
|
||
|
300 continue
|
||
|
!
|
||
|
! termination, either normal or user imposed.
|
||
|
!
|
||
|
if (iflag < 0) info = iflag
|
||
|
iflag = 0
|
||
|
if (nprint > 0) call fcn(n,x,f0,fvec,fjac,ldfjac,iflag)
|
||
|
end subroutine hybrjmv
|
||
|
|
||
|
subroutine dogleg(n,r,lr,diag,qtb,delta,x,wa1,wa2)
|
||
|
use const_and_precisions, only : zero, one, epsmch=>comp_eps
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: n, lr
|
||
|
real(wp_), intent(in) :: delta, r(lr), diag(n), qtb(n)
|
||
|
real(wp_), intent(out) :: x(n), wa1(n), wa2(n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine dogleg
|
||
|
!
|
||
|
! given an m by n matrix a, an n by n nonsingular diagonal
|
||
|
! matrix d, an m-vector b, and a positive number delta, the
|
||
|
! problem is to determine the convex combination x of the
|
||
|
! gauss-newton and scaled gradient directions that minimizes
|
||
|
! (a*x - b) in the least squares sense, subject to the
|
||
|
! restriction that the euclidean norm of d*x be at most delta.
|
||
|
!
|
||
|
! this subroutine completes the solution of the problem
|
||
|
! if it is provided with the necessary information from the
|
||
|
! qr factorization of a. that is, if a = q*r, where q has
|
||
|
! orthogonal columns and r is an upper triangular matrix,
|
||
|
! then dogleg expects the full upper triangle of r and
|
||
|
! the first n components of (q transpose)*b.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine dogleg(n,r,lr,diag,qtb,delta,x,wa1,wa2)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! n is a positive integer input variable set to the order of r.
|
||
|
!
|
||
|
! r is an input array of length lr which must contain the upper
|
||
|
! triangular matrix r stored by rows.
|
||
|
!
|
||
|
! lr is a positive integer input variable not less than
|
||
|
! (n*(n+1))/2.
|
||
|
!
|
||
|
! diag is an input array of length n which must contain the
|
||
|
! diagonal elements of the matrix d.
|
||
|
!
|
||
|
! qtb is an input array of length n which must contain the first
|
||
|
! n elements of the vector (q transpose)*b.
|
||
|
!
|
||
|
! delta is a positive input variable which specifies an upper
|
||
|
! bound on the euclidean norm of d*x.
|
||
|
!
|
||
|
! x is an output array of length n which contains the desired
|
||
|
! convex combination of the gauss-newton direction and the
|
||
|
! scaled gradient direction.
|
||
|
!
|
||
|
! wa1 and wa2 are work arrays of length n.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! minpack-supplied ... enorm
|
||
|
!
|
||
|
! fortran-supplied ... abs,dmax1,dmin1,sqrt
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, j, jj, jp1, k, l
|
||
|
real(wp_) :: alpha, bnorm, gnorm, qnorm, sgnorm, summ, temp
|
||
|
!
|
||
|
! first, calculate the gauss-newton direction.
|
||
|
!
|
||
|
jj = (n*(n + 1))/2 + 1
|
||
|
do k = 1, n
|
||
|
j = n - k + 1
|
||
|
jp1 = j + 1
|
||
|
jj = jj - k
|
||
|
l = jj + 1
|
||
|
summ = zero
|
||
|
do i = jp1, n
|
||
|
summ = summ + r(l)*x(i)
|
||
|
l = l + 1
|
||
|
end do
|
||
|
temp = r(jj)
|
||
|
if (temp == zero) then
|
||
|
l = j
|
||
|
do i = 1, j
|
||
|
temp = dmax1(temp,abs(r(l)))
|
||
|
l = l + n - i
|
||
|
end do
|
||
|
temp = epsmch*temp
|
||
|
if (temp == zero) temp = epsmch
|
||
|
end if
|
||
|
x(j) = (qtb(j) - summ)/temp
|
||
|
end do
|
||
|
!
|
||
|
! test whether the gauss-newton direction is acceptable.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
wa1(j) = zero
|
||
|
wa2(j) = diag(j)*x(j)
|
||
|
end do
|
||
|
qnorm = enorm(n,wa2)
|
||
|
if (qnorm <= delta) return
|
||
|
!
|
||
|
! the gauss-newton direction is not acceptable.
|
||
|
! next, calculate the scaled gradient direction.
|
||
|
!
|
||
|
l = 1
|
||
|
do j = 1, n
|
||
|
temp = qtb(j)
|
||
|
do i = j, n
|
||
|
wa1(i) = wa1(i) + r(l)*temp
|
||
|
l = l + 1
|
||
|
end do
|
||
|
wa1(j) = wa1(j)/diag(j)
|
||
|
end do
|
||
|
!
|
||
|
! calculate the norm of the scaled gradient and test for
|
||
|
! the special case in which the scaled gradient is zero.
|
||
|
!
|
||
|
gnorm = enorm(n,wa1)
|
||
|
sgnorm = zero
|
||
|
alpha = delta/qnorm
|
||
|
if (gnorm /= zero) then
|
||
|
!
|
||
|
! calculate the point along the scaled gradient
|
||
|
! at which the quadratic is minimized.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
wa1(j) = (wa1(j)/gnorm)/diag(j)
|
||
|
end do
|
||
|
l = 1
|
||
|
do j = 1, n
|
||
|
summ = zero
|
||
|
do i = j, n
|
||
|
summ = summ + r(l)*wa1(i)
|
||
|
l = l + 1
|
||
|
end do
|
||
|
wa2(j) = summ
|
||
|
end do
|
||
|
temp = enorm(n,wa2)
|
||
|
sgnorm = (gnorm/temp)/temp
|
||
|
!
|
||
|
! test whether the scaled gradient direction is acceptable.
|
||
|
!
|
||
|
alpha = zero
|
||
|
if (sgnorm < delta) then
|
||
|
!
|
||
|
! the scaled gradient direction is not acceptable.
|
||
|
! finally, calculate the point along the dogleg
|
||
|
! at which the quadratic is minimized.
|
||
|
!
|
||
|
bnorm = enorm(n,qtb)
|
||
|
temp = (bnorm/gnorm)*(bnorm/qnorm)*(sgnorm/delta)
|
||
|
temp = temp - (delta/qnorm)*(sgnorm/delta)**2 &
|
||
|
+ sqrt((temp-(delta/qnorm))**2 &
|
||
|
+(one-(delta/qnorm)**2)*(one-(sgnorm/delta)**2))
|
||
|
alpha = ((delta/qnorm)*(one - (sgnorm/delta)**2))/temp
|
||
|
end if
|
||
|
end if
|
||
|
!
|
||
|
! form appropriate convex combination of the gauss-newton
|
||
|
! direction and the scaled gradient direction.
|
||
|
!
|
||
|
temp = (one - alpha)*dmin1(sgnorm,delta)
|
||
|
do j = 1, n
|
||
|
x(j) = temp*wa1(j) + alpha*x(j)
|
||
|
end do
|
||
|
end subroutine dogleg
|
||
|
|
||
|
function enorm(n,x)
|
||
|
use const_and_precisions, only : zero, one
|
||
|
implicit none
|
||
|
real(wp_) :: enorm
|
||
|
integer, intent(in) :: n
|
||
|
real(wp_), dimension(n), intent(in) :: x
|
||
|
! **********
|
||
|
!
|
||
|
! function enorm
|
||
|
!
|
||
|
! given an n-vector x, this function calculates the
|
||
|
! euclidean norm of x.
|
||
|
!
|
||
|
! the euclidean norm is computed by accumulating the sum of
|
||
|
! squares in three different sums. the sums of squares for the
|
||
|
! small and large components are scaled so that no overflows
|
||
|
! occur. non-destructive underflows are permitted. underflows
|
||
|
! and overflows do not occur in the computation of the unscaled
|
||
|
! sum of squares for the intermediate components.
|
||
|
! the definitions of small, intermediate and large components
|
||
|
! depend on two constants, rdwarf and rgiant. the main
|
||
|
! restrictions on these constants are that rdwarf**2 not
|
||
|
! underflow and rgiant**2 not overflow. the constants
|
||
|
! given here are suitable for every known computer.
|
||
|
!
|
||
|
! the function statement is
|
||
|
!
|
||
|
! real(8) function enorm(n,x)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! n is a positive integer input variable.
|
||
|
!
|
||
|
! x is an input array of length n.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! fortran-supplied ... abs,sqrt
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
integer :: i
|
||
|
real(wp_) :: agiant,floatn,s1,s2,s3,xabs,x1max,x3max
|
||
|
real(wp_), parameter :: rdwarf=3.834e-20_wp_,rgiant=1.304e19_wp_
|
||
|
s1 = zero
|
||
|
s2 = zero
|
||
|
s3 = zero
|
||
|
x1max = zero
|
||
|
x3max = zero
|
||
|
floatn = n
|
||
|
agiant = rgiant/floatn
|
||
|
do i = 1, n
|
||
|
xabs = abs(x(i))
|
||
|
if (xabs <= rdwarf .or. xabs >= agiant) then
|
||
|
if (xabs > rdwarf) then
|
||
|
!
|
||
|
! sum for large components.
|
||
|
!
|
||
|
if (xabs > x1max) then
|
||
|
s1 = one + s1*(x1max/xabs)**2
|
||
|
x1max = xabs
|
||
|
else
|
||
|
s1 = s1 + (xabs/x1max)**2
|
||
|
end if
|
||
|
else
|
||
|
!
|
||
|
! sum for small components.
|
||
|
!
|
||
|
if (xabs > x3max) then
|
||
|
s3 = one + s3*(x3max/xabs)**2
|
||
|
x3max = xabs
|
||
|
else
|
||
|
if (xabs /= zero) s3 = s3 + (xabs/x3max)**2
|
||
|
end if
|
||
|
end if
|
||
|
else
|
||
|
!
|
||
|
! sum for intermediate components.
|
||
|
!
|
||
|
s2 = s2 + xabs**2
|
||
|
end if
|
||
|
end do
|
||
|
!
|
||
|
! calculation of norm.
|
||
|
!
|
||
|
if (s1 /= zero) then
|
||
|
enorm = x1max*sqrt(s1+(s2/x1max)/x1max)
|
||
|
else
|
||
|
if (s2 /= zero) then
|
||
|
if (s2 >= x3max) enorm = sqrt(s2*(one+(x3max/s2)*(x3max*s3)))
|
||
|
if (s2 < x3max) enorm = sqrt(x3max*((s2/x3max)+(x3max*s3)))
|
||
|
else
|
||
|
enorm = x3max*sqrt(s3)
|
||
|
end if
|
||
|
end if
|
||
|
end function enorm
|
||
|
|
||
|
subroutine qform(m,n,q,ldq,wa)
|
||
|
use const_and_precisions, only : zero, one
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: m,n,ldq
|
||
|
real(wp_), intent(out) :: wa(m)
|
||
|
real(wp_), intent(inout) :: q(ldq,m)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine qform
|
||
|
!
|
||
|
! this subroutine proceeds from the computed qr factorization of
|
||
|
! an m by n matrix a to accumulate the m by m orthogonal matrix
|
||
|
! q from its factored form.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine qform(m,n,q,ldq,wa)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! m is a positive integer input variable set to the number
|
||
|
! of rows of a and the order of q.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of columns of a.
|
||
|
!
|
||
|
! q is an m by m array. on input the full lower trapezoid in
|
||
|
! the first min(m,n) columns of q contains the factored form.
|
||
|
! on output q has been accumulated into a square matrix.
|
||
|
!
|
||
|
! ldq is a positive integer input variable not less than m
|
||
|
! which specifies the leading dimension of the array q.
|
||
|
!
|
||
|
! wa is a work array of length m.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! fortran-supplied ... min0
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, j, jm1, k, l, minmn, np1
|
||
|
real(wp_) :: summ, temp
|
||
|
!
|
||
|
! zero out upper triangle of q in the first min(m,n) columns.
|
||
|
!
|
||
|
minmn = min0(m,n)
|
||
|
do j = 2, minmn
|
||
|
jm1 = j - 1
|
||
|
do i = 1, jm1
|
||
|
q(i,j) = zero
|
||
|
end do
|
||
|
end do
|
||
|
!
|
||
|
! initialize remaining columns to those of the identity matrix.
|
||
|
!
|
||
|
np1 = n + 1
|
||
|
do j = np1, m
|
||
|
do i = 1, m
|
||
|
q(i,j) = zero
|
||
|
end do
|
||
|
q(j,j) = one
|
||
|
end do
|
||
|
!
|
||
|
! accumulate q from its factored form.
|
||
|
!
|
||
|
do l = 1, minmn
|
||
|
k = minmn - l + 1
|
||
|
do i = k, m
|
||
|
wa(i) = q(i,k)
|
||
|
q(i,k) = zero
|
||
|
end do
|
||
|
q(k,k) = one
|
||
|
if (wa(k) /= zero) then
|
||
|
do j = k, m
|
||
|
summ = zero
|
||
|
do i = k, m
|
||
|
summ = summ + q(i,j)*wa(i)
|
||
|
end do
|
||
|
temp = summ/wa(k)
|
||
|
do i = k, m
|
||
|
q(i,j) = q(i,j) - temp*wa(i)
|
||
|
end do
|
||
|
end do
|
||
|
end if
|
||
|
end do
|
||
|
end subroutine qform
|
||
|
|
||
|
subroutine qrfac(m,n,a,lda,pivot,ipvt,lipvt,rdiag,acnorm,wa)
|
||
|
use const_and_precisions, only : zero, one, epsmch=>comp_eps
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: m, n, lda, lipvt
|
||
|
integer, intent(out) :: ipvt(lipvt)
|
||
|
logical, intent(in) :: pivot
|
||
|
real(wp_), intent(out) :: rdiag(n), acnorm(n), wa(n)
|
||
|
real(wp_), intent(inout) :: a(lda,n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine qrfac
|
||
|
!
|
||
|
! this subroutine uses householder transformations with column
|
||
|
! pivoting (optional) to compute a qr factorization of the
|
||
|
! m by n matrix a. that is, qrfac determines an orthogonal
|
||
|
! matrix q, a permutation matrix p, and an upper trapezoidal
|
||
|
! matrix r with diagonal elements of nonincreasing magnitude,
|
||
|
! such that a*p = q*r. the householder transformation for
|
||
|
! column k, k = 1,2,...,min(m,n), is of the form
|
||
|
!
|
||
|
! t
|
||
|
! i - (1/u(k))*u*u
|
||
|
!
|
||
|
! where u has zeros in the first k-1 positions. the form of
|
||
|
! this transformation and the method of pivoting first
|
||
|
! appeared in the corresponding linpack subroutine.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine qrfac(m,n,a,lda,pivot,ipvt,lipvt,rdiag,acnorm,wa)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! m is a positive integer input variable set to the number
|
||
|
! of rows of a.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of columns of a.
|
||
|
!
|
||
|
! a is an m by n array. on input a contains the matrix for
|
||
|
! which the qr factorization is to be computed. on output
|
||
|
! the strict upper trapezoidal part of a contains the strict
|
||
|
! upper trapezoidal part of r, and the lower trapezoidal
|
||
|
! part of a contains a factored form of q (the non-trivial
|
||
|
! elements of the u vectors described above).
|
||
|
!
|
||
|
! lda is a positive integer input variable not less than m
|
||
|
! which specifies the leading dimension of the array a.
|
||
|
!
|
||
|
! pivot is a logical input variable. if pivot is set true,
|
||
|
! then column pivoting is enforced. if pivot is set false,
|
||
|
! then no column pivoting is done.
|
||
|
!
|
||
|
! ipvt is an integer output array of length lipvt. ipvt
|
||
|
! defines the permutation matrix p such that a*p = q*r.
|
||
|
! column j of p is column ipvt(j) of the identity matrix.
|
||
|
! if pivot is false, ipvt is not referenced.
|
||
|
!
|
||
|
! lipvt is a positive integer input variable. if pivot is false,
|
||
|
! then lipvt may be as small as 1. if pivot is true, then
|
||
|
! lipvt must be at least n.
|
||
|
!
|
||
|
! rdiag is an output array of length n which contains the
|
||
|
! diagonal elements of r.
|
||
|
!
|
||
|
! acnorm is an output array of length n which contains the
|
||
|
! norms of the corresponding columns of the input matrix a.
|
||
|
! if this information is not needed, then acnorm can coincide
|
||
|
! with rdiag.
|
||
|
!
|
||
|
! wa is a work array of length n. if pivot is false, then wa
|
||
|
! can coincide with rdiag.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! minpack-supplied ... enorm
|
||
|
!
|
||
|
! fortran-supplied ... dmax1,sqrt,min0
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, j, jp1, k, kmax, minmn
|
||
|
real(wp_) :: ajnorm, summ, temp
|
||
|
! parameters
|
||
|
real(wp_), parameter :: p05=5.0e-2_wp_
|
||
|
!
|
||
|
! compute the initial column norms and initialize several arrays.
|
||
|
!
|
||
|
do j = 1, n
|
||
|
acnorm(j) = enorm(m,a(1,j))
|
||
|
rdiag(j) = acnorm(j)
|
||
|
wa(j) = rdiag(j)
|
||
|
if (pivot) ipvt(j) = j
|
||
|
end do
|
||
|
!
|
||
|
! reduce a to r with householder transformations.
|
||
|
!
|
||
|
minmn = min0(m,n)
|
||
|
do j = 1, minmn
|
||
|
if (pivot) then
|
||
|
!
|
||
|
! bring the column of largest norm into the pivot position.
|
||
|
!
|
||
|
kmax = j
|
||
|
do k = j, n
|
||
|
if (rdiag(k) > rdiag(kmax)) kmax = k
|
||
|
end do
|
||
|
if (kmax /= j) then
|
||
|
do i = 1, m
|
||
|
temp = a(i,j)
|
||
|
a(i,j) = a(i,kmax)
|
||
|
a(i,kmax) = temp
|
||
|
end do
|
||
|
rdiag(kmax) = rdiag(j)
|
||
|
wa(kmax) = wa(j)
|
||
|
k = ipvt(j)
|
||
|
ipvt(j) = ipvt(kmax)
|
||
|
ipvt(kmax) = k
|
||
|
end if
|
||
|
end if
|
||
|
!
|
||
|
! compute the householder transformation to reduce the
|
||
|
! j-th column of a to a multiple of the j-th unit vector.
|
||
|
!
|
||
|
ajnorm = enorm(m-j+1,a(j,j))
|
||
|
if (ajnorm /= zero) then
|
||
|
if (a(j,j) < zero) ajnorm = -ajnorm
|
||
|
do i = j, m
|
||
|
a(i,j) = a(i,j)/ajnorm
|
||
|
end do
|
||
|
a(j,j) = a(j,j) + one
|
||
|
!
|
||
|
! apply the transformation to the remaining columns
|
||
|
! and update the norms.
|
||
|
!
|
||
|
jp1 = j + 1
|
||
|
do k = jp1, n
|
||
|
summ = zero
|
||
|
do i = j, m
|
||
|
summ = summ + a(i,j)*a(i,k)
|
||
|
end do
|
||
|
temp = summ/a(j,j)
|
||
|
do i = j, m
|
||
|
a(i,k) = a(i,k) - temp*a(i,j)
|
||
|
end do
|
||
|
if (pivot .and. rdiag(k) /= zero) then
|
||
|
temp = a(j,k)/rdiag(k)
|
||
|
rdiag(k) = rdiag(k)*sqrt(dmax1(zero,one-temp**2))
|
||
|
if (p05*(rdiag(k)/wa(k))**2 <= epsmch) then
|
||
|
rdiag(k) = enorm(m-j,a(jp1,k))
|
||
|
wa(k) = rdiag(k)
|
||
|
end if
|
||
|
end if
|
||
|
end do
|
||
|
end if
|
||
|
rdiag(j) = -ajnorm
|
||
|
end do
|
||
|
end subroutine qrfac
|
||
|
|
||
|
subroutine r1mpyq(m,n,a,lda,v,w)
|
||
|
use const_and_precisions, only : one
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: m, n, lda
|
||
|
real(wp_), intent(in) :: v(n),w(n)
|
||
|
real(wp_), intent(inout) :: a(lda,n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine r1mpyq
|
||
|
!
|
||
|
! given an m by n matrix a, this subroutine computes a*q where
|
||
|
! q is the product of 2*(n - 1) transformations
|
||
|
!
|
||
|
! gv(n-1)*...*gv(1)*gw(1)*...*gw(n-1)
|
||
|
!
|
||
|
! and gv(i), gw(i) are givens rotations in the (i,n) plane which
|
||
|
! eliminate elements in the i-th and n-th planes, respectively.
|
||
|
! q itself is not given, rather the information to recover the
|
||
|
! gv, gw rotations is supplied.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine r1mpyq(m,n,a,lda,v,w)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! m is a positive integer input variable set to the number
|
||
|
! of rows of a.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of columns of a.
|
||
|
!
|
||
|
! a is an m by n array. on input a must contain the matrix
|
||
|
! to be postmultiplied by the orthogonal matrix q
|
||
|
! described above. on output a*q has replaced a.
|
||
|
!
|
||
|
! lda is a positive integer input variable not less than m
|
||
|
! which specifies the leading dimension of the array a.
|
||
|
!
|
||
|
! v is an input array of length n. v(i) must contain the
|
||
|
! information necessary to recover the givens rotation gv(i)
|
||
|
! described above.
|
||
|
!
|
||
|
! w is an input array of length n. w(i) must contain the
|
||
|
! information necessary to recover the givens rotation gw(i)
|
||
|
! described above.
|
||
|
!
|
||
|
! subroutines called
|
||
|
!
|
||
|
! fortran-supplied ... abs,sqrt
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, j, nmj, nm1
|
||
|
real(wp_) :: cs, sn, temp
|
||
|
!
|
||
|
! apply the first set of givens rotations to a.
|
||
|
!
|
||
|
nm1 = n - 1
|
||
|
if (nm1 < 1) return
|
||
|
do nmj = 1, nm1
|
||
|
j = n - nmj
|
||
|
if (abs(v(j)) > one) cs = one/v(j)
|
||
|
if (abs(v(j)) > one) sn = sqrt(one-cs**2)
|
||
|
if (abs(v(j)) <= one) sn = v(j)
|
||
|
if (abs(v(j)) <= one) cs = sqrt(one-sn**2)
|
||
|
do i = 1, m
|
||
|
temp = cs*a(i,j) - sn*a(i,n)
|
||
|
a(i,n) = sn*a(i,j) + cs*a(i,n)
|
||
|
a(i,j) = temp
|
||
|
end do
|
||
|
end do
|
||
|
!
|
||
|
! apply the second set of givens rotations to a.
|
||
|
!
|
||
|
do j = 1, nm1
|
||
|
if (abs(w(j)) > one) cs = one/w(j)
|
||
|
if (abs(w(j)) > one) sn = sqrt(one-cs**2)
|
||
|
if (abs(w(j)) <= one) sn = w(j)
|
||
|
if (abs(w(j)) <= one) cs = sqrt(one-sn**2)
|
||
|
do i = 1, m
|
||
|
temp = cs*a(i,j) + sn*a(i,n)
|
||
|
a(i,n) = -sn*a(i,j) + cs*a(i,n)
|
||
|
a(i,j) = temp
|
||
|
end do
|
||
|
end do
|
||
|
end subroutine r1mpyq
|
||
|
|
||
|
subroutine r1updt(m,n,s,ls,u,v,w,sing)
|
||
|
use const_and_precisions, only : zero, one, giant=>comp_huge
|
||
|
implicit none
|
||
|
! arguments
|
||
|
integer, intent(in) :: m, n, ls
|
||
|
logical, intent(out) :: sing
|
||
|
real(wp_), intent(in) :: u(m)
|
||
|
real(wp_), intent(out) :: w(m)
|
||
|
real(wp_), intent(inout) :: s(ls), v(n)
|
||
|
! **********
|
||
|
!
|
||
|
! subroutine r1updt
|
||
|
!
|
||
|
! given an m by n lower trapezoidal matrix s, an m-vector u,
|
||
|
! and an n-vector v, the problem is to determine an
|
||
|
! orthogonal matrix q such that
|
||
|
!
|
||
|
! t
|
||
|
! (s + u*v )*q
|
||
|
!
|
||
|
! is again lower trapezoidal.
|
||
|
!
|
||
|
! this subroutine determines q as the product of 2*(n - 1)
|
||
|
! transformations
|
||
|
!
|
||
|
! gv(n-1)*...*gv(1)*gw(1)*...*gw(n-1)
|
||
|
!
|
||
|
! where gv(i), gw(i) are givens rotations in the (i,n) plane
|
||
|
! which eliminate elements in the i-th and n-th planes,
|
||
|
! respectively. q itself is not accumulated, rather the
|
||
|
! information to recover the gv, gw rotations is returned.
|
||
|
!
|
||
|
! the subroutine statement is
|
||
|
!
|
||
|
! subroutine r1updt(m,n,s,ls,u,v,w,sing)
|
||
|
!
|
||
|
! where
|
||
|
!
|
||
|
! m is a positive integer input variable set to the number
|
||
|
! of rows of s.
|
||
|
!
|
||
|
! n is a positive integer input variable set to the number
|
||
|
! of columns of s. n must not exceed m.
|
||
|
!
|
||
|
! s is an array of length ls. on input s must contain the lower
|
||
|
! trapezoidal matrix s stored by columns. on output s contains
|
||
|
! the lower trapezoidal matrix produced as described above.
|
||
|
!
|
||
|
! ls is a positive integer input variable not less than
|
||
|
! (n*(2*m-n+1))/2.
|
||
|
!
|
||
|
! u is an input array of length m which must contain the
|
||
|
! vector u.
|
||
|
!
|
||
|
! v is an array of length n. on input v must contain the vector
|
||
|
! v. on output v(i) contains the information necessary to
|
||
|
! recover the givens rotation gv(i) described above.
|
||
|
!
|
||
|
! w is an output array of length m. w(i) contains information
|
||
|
! necessary to recover the givens rotation gw(i) described
|
||
|
! above.
|
||
|
!
|
||
|
! sing is a logical output variable. sing is set true if any
|
||
|
! of the diagonal elements of the output s are zero. otherwise
|
||
|
! sing is set false.
|
||
|
!
|
||
|
! subprograms called
|
||
|
!
|
||
|
! fortran-supplied ... abs,sqrt
|
||
|
!
|
||
|
! argonne national laboratory. minpack project. march 1980.
|
||
|
! burton s. garbow, kenneth e. hillstrom, jorge j. more,
|
||
|
! john l. nazareth
|
||
|
!
|
||
|
! **********
|
||
|
! local variables
|
||
|
integer :: i, j, jj, l, nmj, nm1
|
||
|
real(wp_) :: cs, cotan, sn, tn, tau, temp
|
||
|
! parameters
|
||
|
real(wp_), parameter :: p5=5.0e-1_wp_, p25=2.5e-1_wp_
|
||
|
!
|
||
|
! initialize the diagonal element pointer.
|
||
|
!
|
||
|
jj = (n*(2*m - n + 1))/2 - (m - n)
|
||
|
!
|
||
|
! move the nontrivial part of the last column of s into w.
|
||
|
!
|
||
|
l = jj
|
||
|
do i = n, m
|
||
|
w(i) = s(l)
|
||
|
l = l + 1
|
||
|
end do
|
||
|
!
|
||
|
! rotate the vector v into a multiple of the n-th unit vector
|
||
|
! in such a way that a spike is introduced into w.
|
||
|
!
|
||
|
nm1 = n - 1
|
||
|
do nmj = 1, nm1
|
||
|
j = n - nmj
|
||
|
jj = jj - (m - j + 1)
|
||
|
w(j) = zero
|
||
|
if (v(j) /= zero) then
|
||
|
!
|
||
|
! determine a givens rotation which eliminates the
|
||
|
! j-th element of v.
|
||
|
!
|
||
|
if (abs(v(n)) < abs(v(j))) then
|
||
|
cotan = v(n)/v(j)
|
||
|
sn = p5/sqrt(p25+p25*cotan**2)
|
||
|
cs = sn*cotan
|
||
|
tau = one
|
||
|
if (abs(cs)*giant > one) tau = one/cs
|
||
|
else
|
||
|
tn = v(j)/v(n)
|
||
|
cs = p5/sqrt(p25+p25*tn**2)
|
||
|
sn = cs*tn
|
||
|
tau = sn
|
||
|
end if
|
||
|
!
|
||
|
! apply the transformation to v and store the information
|
||
|
! necessary to recover the givens rotation.
|
||
|
!
|
||
|
v(n) = sn*v(j) + cs*v(n)
|
||
|
v(j) = tau
|
||
|
!
|
||
|
! apply the transformation to s and extend the spike in w.
|
||
|
!
|
||
|
l = jj
|
||
|
do i = j, m
|
||
|
temp = cs*s(l) - sn*w(i)
|
||
|
w(i) = sn*s(l) + cs*w(i)
|
||
|
s(l) = temp
|
||
|
l = l + 1
|
||
|
end do
|
||
|
end if
|
||
|
end do
|
||
|
!
|
||
|
! add the spike from the rank 1 update to w.
|
||
|
!
|
||
|
do i = 1, m
|
||
|
w(i) = w(i) + v(n)*u(i)
|
||
|
end do
|
||
|
!
|
||
|
! eliminate the spike.
|
||
|
!
|
||
|
sing = .false.
|
||
|
do j = 1, nm1
|
||
|
if (w(j) /= zero) then
|
||
|
!
|
||
|
! determine a givens rotation which eliminates the
|
||
|
! j-th element of the spike.
|
||
|
!
|
||
|
if (abs(s(jj)) < abs(w(j))) then
|
||
|
cotan = s(jj)/w(j)
|
||
|
sn = p5/sqrt(p25+p25*cotan**2)
|
||
|
cs = sn*cotan
|
||
|
tau = one
|
||
|
if (abs(cs)*giant > one) tau = one/cs
|
||
|
else
|
||
|
tn = w(j)/s(jj)
|
||
|
cs = p5/sqrt(p25+p25*tn**2)
|
||
|
sn = cs*tn
|
||
|
tau = sn
|
||
|
end if
|
||
|
!
|
||
|
! apply the transformation to s and reduce the spike in w.
|
||
|
!
|
||
|
l = jj
|
||
|
do i = j, m
|
||
|
temp = cs*s(l) + sn*w(i)
|
||
|
w(i) = -sn*s(l) + cs*w(i)
|
||
|
s(l) = temp
|
||
|
l = l + 1
|
||
|
end do
|
||
|
!
|
||
|
! store the information necessary to recover the
|
||
|
! givens rotation.
|
||
|
!
|
||
|
w(j) = tau
|
||
|
end if
|
||
|
!
|
||
|
! test for zero diagonal elements in the output s.
|
||
|
!
|
||
|
if (s(jj) == zero) sing = .true.
|
||
|
jj = jj + (m - j + 1)
|
||
|
end do
|
||
|
!
|
||
|
! move w back into the last column of the output s.
|
||
|
!
|
||
|
l = jj
|
||
|
do i = n, m
|
||
|
s(l) = w(i)
|
||
|
l = l + 1
|
||
|
end do
|
||
|
if (s(jj) == zero) sing = .true.
|
||
|
!
|
||
|
end subroutine r1updt
|
||
|
|
||
|
end module minpack
|