dodlm Subroutine

public subroutine dodlm(n, m, np, nq, npp, f, fjacb, fjacd, wd, ldwd, ld2wd, ss, tt, ldtt, delta, alpha2, tau, epsfcn, isodr, tfjacb, omega, u, qraux, jpvt, s, t, nlms, rcond, irank, wrk1, wrk2, wrk3, wrk4, wrk5, wrk, lwrk, tempret, istopc)

Uses

  • proc~~dodlm~~UsesGraph proc~dodlm dodlm module~blas_interfaces blas_interfaces proc~dodlm->module~blas_interfaces module~odrpack_kinds odrpack_kinds proc~dodlm->module~odrpack_kinds module~blas_interfaces->module~odrpack_kinds iso_fortran_env iso_fortran_env module~odrpack_kinds->iso_fortran_env

Compute Levenberg-Marquardt parameter and steps s and t using analog of the trust-region Levenberg-Marquardt algorithm.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: n

The number of observations.

integer, intent(in) :: m

The number of columns of data in the explanatory variable.

integer, intent(in) :: np

The number of function parameters.

integer, intent(in) :: nq

The number of responses per observation.

integer, intent(in) :: npp

The number of function parameters being estimated.

real(kind=wp), intent(in) :: f(n,nq)

The (weighted) estimated values of epsilon.

real(kind=wp), intent(in) :: fjacb(n,np,nq)

The Jacobian with respect to beta.

real(kind=wp), intent(in) :: fjacd(n,m,nq)

The Jacobian with respect to delta.

real(kind=wp), intent(in) :: wd(ldwd,ld2wd,m)

The delta weights.

integer, intent(in) :: ldwd

The leading dimension of array wd.

integer, intent(in) :: ld2wd

The second dimension of array wd.

real(kind=wp), intent(in) :: ss(np)

The scaling values used for the unfixed betas.

real(kind=wp), intent(in) :: tt(ldtt,m)

The scale used for the deltas.

integer, intent(in) :: ldtt

The leading dimension of array tt.

real(kind=wp), intent(in) :: delta(n,m)

The estimated errors in the explanatory variables.

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

The current Levenberg-Marquardt parameter.

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

The trust region diameter.

real(kind=wp), intent(in) :: epsfcn

The function's precision.

logical, intent(in) :: isodr

The variable designating whether the solution is by ODR (isodr = .true.) or by OLS (isodr = .false.).

real(kind=wp), intent(out) :: tfjacb(n,nq,np)

The array omega*fjacb.

real(kind=wp), intent(out) :: omega(nq,nq)

The array (I-fjacd*inv(p)*trans(fjacd))**(-1/2).

real(kind=wp), intent(out) :: u(np)

The approximate null vector for tfjacb.

real(kind=wp), intent(out) :: qraux(np)

The array required to recover the orthogonal part of the Q-R decomposition.

integer, intent(out) :: jpvt(np)

The pivot vector.

real(kind=wp), intent(out) :: s(np)

The step for beta.

real(kind=wp), intent(out) :: t(n,m)

The step for delta.

integer, intent(out) :: nlms

The number of Levenberg-Marquardt steps taken.

real(kind=wp), intent(out) :: rcond

The approximate reciprocal condition of tfjacb.

integer, intent(out) :: irank

The rank deficiency of the Jacobian wrt beta.

real(kind=wp), intent(out) :: wrk1(n,nq,m)

A work array of (n, nq, m) elements.

real(kind=wp), intent(out) :: wrk2(n,nq)

A work array of (n, nq) elements.

real(kind=wp), intent(out) :: wrk3(np)

A work array of (np) elements.

real(kind=wp), intent(out) :: wrk4(m,m)

A work array of (m, m) elements.

real(kind=wp), intent(out) :: wrk5(m)

A work array of (m) elements.

real(kind=wp), intent(out) :: wrk(lwrk)

A work array of (lwrk) elements, equivalenced to wrk1 and wrk2.

integer, intent(in) :: lwrk

The length of vector wrk.

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

Temporary work array for holding return values before copying to a lower rank array.

integer, intent(out) :: istopc

The variable designating whether the computations were stopped due to some other numerical error detected within subroutine dodstp.


Calls

proc~~dodlm~~CallsGraph proc~dodlm dodlm interface~ddot ddot proc~dodlm->interface~ddot interface~dnrm2 dnrm2 proc~dodlm->interface~dnrm2 proc~dodstp dodstp proc~dodlm->proc~dodstp proc~dscale dscale proc~dodlm->proc~dscale proc~dwght dwght proc~dodlm->proc~dwght proc~dodstp->interface~dnrm2 proc~dodstp->proc~dwght dchex dchex proc~dodstp->dchex dqrdc dqrdc proc~dodstp->dqrdc dqrsl dqrsl proc~dodstp->dqrsl dtrco dtrco proc~dodstp->dtrco dtrsl dtrsl proc~dodstp->dtrsl interface~drot drot proc~dodstp->interface~drot interface~drotg drotg proc~dodstp->interface~drotg interface~idamax idamax proc~dodstp->interface~idamax proc~desubi desubi proc~dodstp->proc~desubi proc~dfctr dfctr proc~dodstp->proc~dfctr proc~dsolve dsolve proc~dodstp->proc~dsolve proc~dvevtr dvevtr proc~dodstp->proc~dvevtr proc~dfctr->interface~ddot proc~dsolve->interface~ddot interface~daxpy daxpy proc~dsolve->interface~daxpy proc~dvevtr->proc~dsolve

Called by

proc~~dodlm~~CalledByGraph proc~dodlm dodlm proc~dodmn dodmn proc~dodmn->proc~dodlm proc~doddrv doddrv proc~doddrv->proc~dodmn proc~dodcnt dodcnt proc~dodcnt->proc~doddrv proc~odr odr proc~odr->proc~dodcnt proc~odr_long_c odr_long_c proc~odr_long_c->proc~odr proc~odr_medium_c odr_medium_c proc~odr_medium_c->proc~odr proc~odr_short_c odr_short_c proc~odr_short_c->proc~odr program~example1 example1 program~example1->proc~odr program~example2 example2 program~example2->proc~odr program~example3 example3 program~example3->proc~odr program~example4 example4 program~example4->proc~odr program~example5 example5 program~example5->proc~odr

Variables

Type Visibility Attributes Name Initial
real(kind=wp), public, parameter :: p001 = 0.001_wp
real(kind=wp), public, parameter :: p1 = 0.1_wp
real(kind=wp), public :: alpha1
real(kind=wp), public :: alphan
real(kind=wp), public :: bot
real(kind=wp), public :: phi1
real(kind=wp), public :: phi2
real(kind=wp), public :: sa
real(kind=wp), public :: top
integer, public :: i
integer, public :: iwrk
integer, public :: j
integer, public :: k
logical, public :: forvcv

Source Code

   subroutine dodlm &
      (n, m, np, nq, npp, &
       f, fjacb, fjacd, &
       wd, ldwd, ld2wd, ss, tt, ldtt, delta, &
       alpha2, tau, epsfcn, isodr, &
       tfjacb, omega, u, qraux, jpvt, &
       s, t, nlms, rcond, irank, &
       wrk1, wrk2, wrk3, wrk4, wrk5, wrk, lwrk, tempret, istopc)
   !! Compute Levenberg-Marquardt parameter and steps `s` and `t` using analog of the
   !! trust-region Levenberg-Marquardt algorithm.
      ! Routines Called  DDOT, DNRM2, DODSTP, DSCALE, DWGHT
      ! Date Written   860529   (YYMMDD)
      ! Revision Date  920619   (YYMMDD)

      use odrpack_kinds, only: zero
      use blas_interfaces, only: ddot, dnrm2

      integer, intent(in) :: n
         !! The number of observations.
      integer, intent(in) :: m
         !! The number of columns of data in the explanatory variable.
      integer, intent(in) :: np
         !! The number of function parameters.
      integer, intent(in) :: nq
         !! The number of responses per observation.
      integer, intent(in) :: npp
         !! The number of function parameters being estimated.
      real(wp), intent(in) :: f(n, nq)
         !! The (weighted) estimated values of `epsilon`.
      real(wp), intent(in) :: fjacb(n, np, nq)
         !! The Jacobian with respect to `beta`.
      real(wp), intent(in) :: fjacd(n, m, nq)
         !! The Jacobian with respect to `delta`.
      real(wp), intent(in) :: wd(ldwd, ld2wd, m)
         !! The `delta` weights.
      integer, intent(in) :: ldwd
         !! The leading dimension of array `wd`.
      integer, intent(in) :: ld2wd
         !! The second dimension of array `wd`.
      real(wp), intent(in) :: ss(np)
         !! The scaling values used for the unfixed `beta`s.
      real(wp), intent(in) :: tt(ldtt, m)
         !! The scale used for the `delta`s.
      integer, intent(in) :: ldtt
         !! The leading dimension of array `tt`.
      real(wp), intent(in) :: delta(n, m)
         !! The estimated errors in the explanatory variables.
      real(wp), intent(inout) :: alpha2
         !! The current Levenberg-Marquardt parameter.
      real(wp), intent(inout) :: tau
         !! The trust region diameter.
      real(wp), intent(in) :: epsfcn
         !! The function's precision.
      logical, intent(in) :: isodr
         !! The variable designating whether the solution is by ODR (`isodr = .true.`)
         !! or by OLS (`isodr = .false.`).
      real(wp), intent(out) :: tfjacb(n, nq, np)
         !! The array `omega*fjacb`.
      real(wp), intent(out) :: omega(nq, nq)
         !! The array `(I-fjacd*inv(p)*trans(fjacd))**(-1/2)`.
      real(wp), intent(out) :: u(np)
         !! The approximate null vector for tfjacb.
      real(wp), intent(out) :: qraux(np)
         !! The array required to recover the orthogonal part of the Q-R decomposition.
      integer, intent(out) :: jpvt(np)
         !! The pivot vector.
      real(wp), intent(out) :: s(np)
         !! The step for `beta`.
      real(wp), intent(out) :: t(n, m)
         !! The step for `delta`.
      integer, intent(out) :: nlms
         !! The number of Levenberg-Marquardt steps taken.
      real(wp), intent(out) :: rcond
         !! The approximate reciprocal condition of `tfjacb`.
      integer, intent(out) :: irank
         !! The rank deficiency of the Jacobian wrt `beta`.
      real(wp), intent(out) :: wrk1(n, nq, m)
         !! A work array of `(n, nq, m)` elements.
      real(wp), intent(out) :: wrk2(n, nq)
         !! A work array of `(n, nq)` elements.
      real(wp), intent(out) :: wrk3(np)
         !! A work array of `(np)` elements.
      real(wp), intent(out) :: wrk4(m, m)
         !! A work array of `(m, m)` elements.
      real(wp), intent(out) :: wrk5(m)
         !! A work array of `(m)` elements.
      real(wp), intent(out) :: wrk(lwrk)
         !! A work array of `(lwrk)` elements, _equivalenced_ to `wrk1` and `wrk2`.
      integer, intent(in) :: lwrk
         !! The length of vector `wrk`.
      real(wp), intent(inout) :: tempret(:, :)
         !! Temporary work array for holding return values before copying to a lower rank array.
      integer, intent(out) :: istopc
         !! The variable designating whether the computations were stopped due to some other
         !! numerical error detected within subroutine `dodstp`.

      ! Local scalars
      real(wp), parameter :: p001 = 0.001_wp, p1 = 0.1_wp
      real(wp) :: alpha1, alphan, bot, phi1, phi2, sa, top
      integer :: i, iwrk, j, k
      logical :: forvcv

      ! Variable Definitions (alphabetically)
      !  ALPHAN:  The new Levenberg-Marquardt parameter.
      !  ALPHA1:  The previous Levenberg-Marquardt parameter.
      !  ALPHA2:  The current Levenberg-Marquardt parameter.
      !  BOT:     The lower limit for setting ALPHA.
      !  DELTA:   The estimated errors in the explanatory variables.
      !  EPSFCN:  The function's precision.
      !  F:       The (weighted) estimated values of EPSILON.
      !  FJACB:   The Jacobian with respect to BETA.
      !  FJACD:   The Jacobian with respect to DELTA.
      !  FORVCV:  The variable designating whether this subroutine was called to set up for the
      !           covariance matrix computations (FORVCV=TRUE) or not (FORVCV=FALSE).
      !  I:       An indexing variable.
      !  IRANK:   The rank deficiency of the Jacobian wrt BETA.
      !  ISODR:   The variable designating whether the solution is by ODR (ISODR=TRUE) or
      !           by OLS (ISODR=FALSE).
      !  ISTOPC:  The variable designating whether the computations were stoped due to some
      !           other numerical error detected within subroutine DODSTP.
      !  IWRK:    An indexing variable.
      !  J:       An indexing variable.
      !  K:       An indexing variable.
      !  L:       An indexing variable.
      !  JPVT:    The pivot vector.
      !  LDTT:    The leading dimension of array TT.
      !  LDWD:    The leading dimension of array WD.
      !  LD2WD:   The second dimension of array WD.
      !  LWRK:    The length of vector WRK.
      !  M:       The number of columns of data in the explanatory variable.
      !  N:       The number of observations.
      !  NLMS:    The number of Levenberg-Marquardt steps taken.
      !  NP:      The number of function parameters.
      !  NPP:     The number of function parameters being estimated.
      !  NQ:      The number of responses per observation.
      !  OMEGA:   The array (I-FJACD*INV(P)*trans(FJACD))**(-1/2)  where
      !            P = trans(FJACD)*FJACD + D**2 + ALPHA*TT**2
      !  P001:    The value 0.001E0_wp
      !  P1:      The value 0.1E0_wp
      !  PHI1:    The previous difference between the norm of the scaled step and the trust
      !           region diameter.
      !  PHI2:    The current difference between the norm of the scaled step and the trust region
      !           diameter.
      !  QRAUX:   The array required to recover the orthogonal part of the Q-R decomposition.
      !  RCOND:   The approximate reciprocal condition of TFJACB.
      !  S:       The step for BETA.
      !  SA:      The scalar PHI2*(ALPHA1-ALPHA2)/(PHI1-PHI2).
      !  SS:      The scaling values used for the unfixed BETAS.
      !  T:       The step for DELTA.
      !  TAU:     The trust region diameter.
      !  TFJACB:  The array OMEGA*FJACB.
      !  TOP:     The upper limit for setting ALPHA.
      !  TT:      The scale used for the DELTA'S.
      !  U:       The approximate null vector for TFJACB.
      !  WD:      The DELTA weights.
      !  WRK:     A work array of (LWRK) elements, equivalenced to WRK1 and WRK2.
      !  WRK1:    A work array of (N by NQ by M) elements.
      !  WRK2:    A work array of (N by NQ) elements.
      !  WRK3:    A work array of (NP) elements.
      !  WRK4:    A work array of (M by M) elements.
      !  WRK5:    A work array of (M) elements.

      forvcv = .false.
      istopc = 0

      ! Compute full Gauss-Newton step (ALPHA=0)
      alpha1 = zero
      call dodstp(n, m, np, nq, npp, &
                  f, fjacb, fjacd, &
                  wd, ldwd, ld2wd, ss, tt, ldtt, delta, &
                  alpha1, epsfcn, isodr, &
                  tfjacb, omega, u, qraux, jpvt, &
                  s, t, phi1, irank, rcond, forvcv, &
                  wrk1, wrk2, wrk3, wrk4, wrk5, wrk, lwrk, tempret, istopc)
      if (istopc /= 0) then
         return
      end if

      ! Initialize TAU if necessary
      if (tau < zero) then
         tau = abs(tau)*phi1
      end if

      ! Check if full Gauss-Newton step is optimal
      if ((phi1 - tau) <= p1*tau) then
         nlms = 1
         alpha2 = zero
         return
      end if

      ! Full Gauss-Newton step is outside trust region - find locally constrained optimal step
      phi1 = phi1 - tau

      ! Initialize upper and lower bounds for ALPHA
      bot = zero

      do k = 1, npp
         tfjacb(1:n, 1:nq, k) = fjacb(1:n, k, 1:nq)
         wrk(k) = ddot(n*nq, tfjacb(1, 1, k), 1, f(1, 1), 1)
      end do
      call dscale(npp, 1, ss, npp, wrk, npp, wrk, npp) ! work is input (as t) and output (as sclt)

      if (isodr) then
         call dwght(n, m, wd, ldwd, ld2wd, delta, tempret(1:n, 1:m))
         wrk(npp + 1:npp + 1 + n*m - 1) = reshape(tempret(1:n, 1:m), (/n*m/))
         iwrk = npp
         do j = 1, m
            do i = 1, n
               iwrk = iwrk + 1
               wrk(iwrk) = wrk(iwrk) + ddot(nq, fjacd(i, j, 1), n*m, f(i, 1), n)
            end do
         end do
         call dscale(n, m, tt, ldtt, wrk(npp + 1), n, wrk(npp + 1), n)
         top = dnrm2(npp + n*m, wrk, 1)/tau
      else
         top = dnrm2(npp, wrk, 1)/tau
      end if

      if (alpha2 > top .or. alpha2 == zero) then
         alpha2 = p001*top
      end if

      ! Main loop

      do i = 1, 10

         ! Compute locally constrained steps S and T and PHI(ALPHA) for current value of ALPHA
         call dodstp(n, m, np, nq, npp, &
                     f, fjacb, fjacd, &
                     wd, ldwd, ld2wd, ss, tt, ldtt, delta, &
                     alpha2, epsfcn, isodr, &
                     tfjacb, omega, u, qraux, jpvt, &
                     s, t, phi2, irank, rcond, forvcv, &
                     wrk1, wrk2, wrk3, wrk4, wrk5, wrk, lwrk, tempret, istopc)
         if (istopc /= 0) then
            return
         end if
         phi2 = phi2 - tau

         ! Check whether current step is optimal
         if (abs(phi2) <= p1*tau .or. (alpha2 == bot .and. phi2 < zero)) then
            nlms = i + 1
            return
         end if

         ! Current step is not optimaL

         ! Update bounds for ALPHA and compute new ALPHA
         if (phi1 - phi2 == zero) then
            nlms = 12
            return
         end if
         sa = phi2*(alpha1 - alpha2)/(phi1 - phi2)
         if (phi2 < zero) then
            top = min(top, alpha2)
         else
            bot = max(bot, alpha2)
         end if
         if (phi1*phi2 > zero) then
            bot = max(bot, alpha2 - sa)
         else
            top = min(top, alpha2 - sa)
         end if

         alphan = alpha2 - sa*(phi1 + tau)/tau
         if (alphan >= top .or. alphan <= bot) then
            alphan = max(p001*top, sqrt(top*bot))
         end if

         ! Get ready for next iteration
         alpha1 = alpha2
         alpha2 = alphan
         phi1 = phi2

      end do

      ! Set NLMS to indicate an optimal step could not be found in 10 trys
      nlms = 12

   end subroutine dodlm