lmpar Subroutine

public subroutine lmpar(n, r, Ldr, Ipvt, Diag, Qtb, Delta, Par, x, Sdiag, Wa1, Wa2)

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 a value for the parameter par such that if x solves the system

        a*x = b ,     sqrt(par)*d*x = 0 ,

in the least squares sense, and dxnorm is the euclidean norm of d*x, then either par is zero and

        (dxnorm-delta) <= 0.1*delta ,

or par is positive and

        abs(dxnorm-delta) <= 0.1*delta .

this subroutine completes the solution of the problem if it is provided with the necessary information from the qr factorization, with column pivoting, of a. that is, if ap = qr, where p is a permutation matrix, q has orthogonal columns, and r is an upper triangular matrix with diagonal elements of nonincreasing magnitude, then lmpar expects the full upper triangle of r, the permutation matrix p, and the first n components of (q transpose)*b. on output lmpar also provides an upper triangular matrix s such that

         t   t                   t
        p *(a *a + par*d*d)*p = s *s .

s is employed within lmpar and may be of separate interest.

only a few iterations are generally needed for convergence of the algorithm. if, however, the limit of 10 iterations is reached, then the output par will contain the best value obtained so far.

Arguments

TypeIntentOptionalAttributesName
integer, intent(in) :: n

a positive integer input variable set to the order of r.

real(kind=wp), intent(inout) :: r(Ldr,n)

an n by n array. on input the full upper triangle must contain the full upper triangle of the matrix r. on output the full upper triangle is unaltered, and the strict lower triangle contains the strict upper triangle (transposed) of the upper triangular matrix s.

integer, intent(in) :: Ldr

a positive integer input variable not less than n which specifies the leading dimension of the array r.

integer, intent(in) :: Ipvt(n)

an integer input array of length n which defines the permutation matrix p such that ap = qr. column j of p is column ipvt(j) of the identity matrix.

real(kind=wp), intent(in) :: Diag(n)

an input array of length n which must contain the diagonal elements of the matrix d.

real(kind=wp), intent(in) :: Qtb(n)

an input array of length n which must contain the first n elements of the vector (q transpose)*b.

real(kind=wp) :: Delta

a positive input variable which specifies an upper bound on the euclidean norm of d*x.

real(kind=wp), intent(inout) :: Par

a nonnegative variable. on input par contains an initial estimate of the levenberg-marquardt parameter. on output par contains the final estimate.

real(kind=wp), intent(out) :: x(n)

an output array of length n which contains the least squares solution of the system ax = b, sqrt(par)d*x = 0, for the output par.

real(kind=wp), intent(out) :: Sdiag(n)

an output array of length n which contains the diagonal elements of the upper triangular matrix s.

real(kind=wp), intent(inout) :: Wa1(n)

work array of length n.

real(kind=wp), intent(inout) :: Wa2(n)

work array of length n.


Calls

proc~~lmpar~~CallsGraph proc~lmpar lmpar proc~qrsolv qrsolv proc~lmpar->proc~qrsolv proc~enorm enorm proc~lmpar->proc~enorm

Called by

proc~~lmpar~~CalledByGraph proc~lmpar lmpar proc~lmdif lmdif proc~lmdif->proc~lmpar proc~lmder lmder proc~lmder->proc~lmpar proc~lmstr lmstr proc~lmstr->proc~lmpar proc~minpack_lmdif minpack_lmdif proc~minpack_lmdif->proc~lmdif proc~lmstr1 lmstr1 proc~lmstr1->proc~lmstr proc~minpack_lmstr minpack_lmstr proc~minpack_lmstr->proc~lmstr proc~minpack_lmder minpack_lmder proc~minpack_lmder->proc~lmder proc~lmdif1 lmdif1 proc~lmdif1->proc~lmdif proc~lmder1 lmder1 proc~lmder1->proc~lmder proc~minpack_lmder1 minpack_lmder1 proc~minpack_lmder1->proc~lmder1 proc~minpack_lmstr1 minpack_lmstr1 proc~minpack_lmstr1->proc~lmstr1 proc~minpack_lmdif1 minpack_lmdif1 proc~minpack_lmdif1->proc~lmdif1

Contents

Source Code


Source Code

    subroutine lmpar(n, r, Ldr, Ipvt, Diag, Qtb, Delta, Par, x, Sdiag, Wa1, Wa2)
        implicit none

        integer, intent(in) :: n !! a positive integer input variable set to the order of r.
        integer, intent(in) :: Ldr !! a positive integer input variable not less than n
                                  !! which specifies the leading dimension of the array r.
        integer, intent(in) :: Ipvt(n) !! an integer input array of length n which defines the
                                      !! permutation matrix p such that a*p = q*r. column j of p
                                      !! is column ipvt(j) of the identity matrix.
        real(wp) :: Delta !! a positive input variable which specifies an upper
                          !! bound on the euclidean norm of d*x.
        real(wp), intent(inout) :: Par !! a nonnegative variable. on input par contains an
                                      !! initial estimate of the levenberg-marquardt parameter.
                                      !! on output par contains the final estimate.
        real(wp), intent(inout) :: r(Ldr, n) !! an n by n array. on input the full upper triangle
                                            !! must contain the full upper triangle of the matrix r.
                                            !! on output the full upper triangle is unaltered, and the
                                            !! strict lower triangle contains the strict upper triangle
                                            !! (transposed) of the upper triangular matrix s.
        real(wp), intent(in) :: Diag(n) !! an input array of length n which must contain the
                                       !! diagonal elements of the matrix d.
        real(wp), intent(in) :: Qtb(n) !! an input array of length n which must contain the first
                                      !! n elements of the vector (q transpose)*b.
        real(wp), intent(out) :: x(n) !! an output array of length n which contains the least
                                     !! squares solution of the system a*x = b, sqrt(par)*d*x = 0,
                                     !! for the output par.
        real(wp), intent(out) :: Sdiag(n) !! an output array of length n which contains the
                                         !! diagonal elements of the upper triangular matrix s.
        real(wp), intent(inout) :: Wa1(n) !! work array of length n.
        real(wp), intent(inout) :: Wa2(n) !! work array of length n.

        integer :: i, iter, j, jm1, jp1, k, l, nsing
        real(wp) :: dxnorm, fp, gnorm, parc, parl, paru, sum, temp

        real(wp), parameter :: p1 = 1.0e-1_wp
        real(wp), parameter :: p001 = 1.0e-3_wp
        real(wp), parameter :: dwarf = dpmpar(2) !! the smallest positive magnitude

        ! compute and store in x the gauss-newton direction. if the
        ! jacobian is rank-deficient, obtain a least squares solution.

        nsing = n
        do j = 1, n
            Wa1(j) = Qtb(j)
            if (r(j, j) == zero .and. nsing == n) nsing = j - 1
            if (nsing < n) Wa1(j) = zero
        end do
        if (nsing >= 1) then
            do k = 1, nsing
                j = nsing - k + 1
                Wa1(j) = Wa1(j)/r(j, j)
                temp = Wa1(j)
                jm1 = j - 1
                if (jm1 >= 1) then
                    do i = 1, jm1
                        Wa1(i) = Wa1(i) - r(i, j)*temp
                    end do
                end if
            end do
        end if
        do j = 1, n
            l = Ipvt(j)
            x(l) = Wa1(j)
        end do

        ! initialize the iteration counter.
        ! evaluate the function at the origin, and test
        ! for acceptance of the gauss-newton direction.

        iter = 0
        do j = 1, n
            Wa2(j) = Diag(j)*x(j)
        end do
        dxnorm = enorm(n, Wa2)
        fp = dxnorm - Delta
        if (fp <= p1*Delta) then
            ! termination.
            if (iter == 0) Par = zero
        else

            ! if the jacobian is not rank deficient, the newton
            ! step provides a lower bound, parl, for the zero of
            ! the function. otherwise set this bound to zero.

            parl = zero
            if (nsing >= n) then
                do j = 1, n
                    l = Ipvt(j)
                    Wa1(j) = Diag(l)*(Wa2(l)/dxnorm)
                end do
                do j = 1, n
                    sum = zero
                    jm1 = j - 1
                    if (jm1 >= 1) then
                        do i = 1, jm1
                            sum = sum + r(i, j)*Wa1(i)
                        end do
                    end if
                    Wa1(j) = (Wa1(j) - sum)/r(j, j)
                end do
                temp = enorm(n, Wa1)
                parl = ((fp/Delta)/temp)/temp
            end if

            ! calculate an upper bound, paru, for the zero of the function.

            do j = 1, n
                sum = zero
                do i = 1, j
                    sum = sum + r(i, j)*Qtb(i)
                end do
                l = Ipvt(j)
                Wa1(j) = sum/Diag(l)
            end do
            gnorm = enorm(n, Wa1)
            paru = gnorm/Delta
            if (paru == zero) paru = dwarf/min(Delta, p1)

            ! if the input par lies outside of the interval (parl,paru),
            ! set par to the closer endpoint.

            Par = max(Par, parl)
            Par = min(Par, paru)
            if (Par == zero) Par = gnorm/dxnorm

            ! beginning of an iteration.
            do

                iter = iter + 1

                ! evaluate the function at the current value of par.

                if (Par == zero) Par = max(dwarf, p001*paru)
                temp = sqrt(Par)
                do j = 1, n
                    Wa1(j) = temp*Diag(j)
                end do
                call qrsolv(n, r, Ldr, Ipvt, Wa1, Qtb, x, Sdiag, Wa2)
                do j = 1, n
                    Wa2(j) = Diag(j)*x(j)
                end do
                dxnorm = enorm(n, Wa2)
                temp = fp
                fp = dxnorm - Delta

                ! if the function is small enough, accept the current value
                ! of par. also test for the exceptional cases where parl
                ! is zero or the number of iterations has reached 10.

                if (abs(fp) <= p1*Delta .or. parl == zero .and. fp <= temp .and. &
                    temp < zero .or. iter == 10) then
                    if (iter == 0) Par = zero
                    exit
                else

                    ! compute the newton correction.

                    do j = 1, n
                        l = Ipvt(j)
                        Wa1(j) = Diag(l)*(Wa2(l)/dxnorm)
                    end do
                    do j = 1, n
                        Wa1(j) = Wa1(j)/Sdiag(j)
                        temp = Wa1(j)
                        jp1 = j + 1
                        if (n >= jp1) then
                            do i = jp1, n
                                Wa1(i) = Wa1(i) - r(i, j)*temp
                            end do
                        end if
                    end do
                    temp = enorm(n, Wa1)
                    parc = ((fp/Delta)/temp)/temp

                    ! depending on the sign of the function, update parl or paru.

                    if (fp > zero) parl = max(parl, Par)
                    if (fp < zero) paru = min(paru, Par)

                    ! compute an improved estimate for par.

                    Par = max(parl, Par + parc)

                end if

            end do ! end of an iteration.

        end if

    end subroutine lmpar