https://github.com/cran/nleqslv
Raw File
Tip revision: 841972b2cdbfaddf568c3813f28ee733b4382d77 authored by Berend Hasselman on 26 November 2023, 23:30:14 UTC
version 3.3.5
Tip revision: 841972b
nwutil.f

      subroutine nwtcvg(xplus,fplus,xc,xtol,retcd,ftol,iter,
     *                  maxit,n,ierr,termcd)

      integer n,iter,maxit,ierr,termcd,retcd
      double precision  xtol,ftol
      double precision  xplus(*),fplus(*),xc(*)

c-------------------------------------------------------------------------
c
c     Decide whether to terminate the nonlinear algorithm
c
c     Arguments
c
c     In       xplus   Real(*)         new x values
c     In       fplus   Real(*)         new f values
c     In       xc      Real(*)         current x values
c     In       xtol    Real            stepsize tolerance
c     In       retcd   Integer         return code from global search routines
c     In       ftol    Real            function tolerance
c     In       iter    Integer         iteration number
c     In       maxit   Integer         maximum number of iterations allowed
c     In       n       Integer         size of x and f
c     In       ierr    Integer         return code of cndjac (condition estimation)
c
c     Out      termcd  Integer         termination code
c                                        0 no termination criterion satisfied
c                                          ==> continue iterating
c                                        1 norm of scaled function value is
c                                          less than ftol
c                                        2 scaled distance between last
c                                          two steps less than xtol
c                                        3 unsuccessful global strategy
c                                          ==> cannot find a better point
c                                        4 iteration limit exceeded
c                                        5 Jacobian too ill-conditioned
c                                        6 Jacobian singular
c                                        7 Jacobian not usable (all zero entries)
c
c-------------------------------------------------------------------------

      double precision  fmax,rsx, nuxnrm
      integer idamax

c     check whether function values are within tolerance

      termcd = 0

      if( ierr .ne. 0 ) then
         termcd = 4 + ierr
         return
      endif

      fmax = abs(fplus(idamax(n,fplus,1)))
      if( fmax .le. ftol) then
         termcd = 1
         return
      endif

c     initial check at start so there is no xplus
c     so only a check of function values is useful
      if(iter .eq. 0) return

      if(retcd .eq. 1) then
         termcd = 3
         return
      endif

c     check whether relative step length is within tolerance
c     Dennis Schnabel Algorithm A7.2.3

      rsx = nuxnrm(n, xplus, xc)
      if(rsx .le. xtol) then
        termcd = 2
        return
      endif

c     check iteration limit

      if(iter .ge. maxit) then
         termcd = 4
      endif

      return
      end

c-----------------------------------------------------------------------

      subroutine nweset(n,xc,fc,fcnorm,xp,fp,fpnorm,gcnt,priter,iter)
      double precision xc(*),fc(*),fcnorm,xp(*),fp(*),fpnorm
      integer n, gcnt, priter, iter

c-------------------------------------------------------------------------
c
c     calling routine got an error in decomposition/update of Jacobian/Broyden
c     jacobian an singular or too ill-conditioned
c     prepare return arguments
c
c     Arguments
c
c     In       n       Integer         size of x
c     In       xc      Real(*)         current (starting) x values
c     In       fc      Real(*)         function values f(xc)
c     In       fcnorm  Real            norm fc
c     Out      xp      Real(*)         final x values
c     Out      fp      Real(*)         function values f(xp)
c     Out      fpnorm  Real            final norm fp
c     Out      gcnt    Integer         # of backtracking steps (here set to 0)
c     In       priter  Integer         flag for type of output
c     In       iter    Integer         iteration counter
c
c-------------------------------------------------------------------------

      call dcopy(n,xc,1,xp,1)
      call dcopy(n,fc,1,fp,1)
      fpnorm = fcnorm
      gcnt   = 0
      if( priter .gt. 0 ) then
         call nwjerr(iter)
      endif

      return
      end

c-----------------------------------------------------------------------

      subroutine chkjac1(A,lda,xc,fc,n,epsm,scalex,fz,wa,xw,fvec,termcd)

      integer lda,n,termcd
      double precision  A(lda,*),xc(*),fc(*)
      double precision  epsm,scalex(*)
      double precision  fz(*),wa(*),xw(*)
      external fvec

c-------------------------------------------------------------------------
c
c     Check the user supplied jacobian against its finite difference approximation
c
c     Arguments
c
c     In       A       Real(lda,*)     user supplied jacobian
c     In       lda     Integer         leading dimension of ajanal
c     In       xc      Real(*)         vector of x values
c     In       fc      Real(*)         function values f(xc)
c     In       n       Integer         size of x
c     In       epsm    Real            machine precision
c     In       scalex  Real(*)         scaling vector for x()
c     Wk       fz      Real(*)         workspace
c     Wk       wa      Real(*)         workspace
c     Wk       xw      Real(*)         workspace
c     In       fvec    Name            name of routine to evaluate f(x)
c     Out      termcd  Integer         return code
c                                        0  user supplied jacobian ok
c                                      -10  user supplied jacobian NOT ok
c
c-------------------------------------------------------------------------

      integer i,j,errcnt
      double precision  ndigit,p,h,xcj,dinf
      double precision  tol
      double precision  rnudif
      integer idamax

      integer MAXERR
      parameter(MAXERR=10)

      double precision Rquart, Rten
      parameter(Rquart=0.25d0, Rten=10.0d0)

      termcd = 0

c     compute the finite difference jacobian and check it against
c     the analytic one

      ndigit = -log10(epsm)
      p = sqrt(max(Rten**(-ndigit),epsm))
      tol    = epsm**Rquart

      errcnt = 0
      call dcopy(n,xc,1,xw,1)
      call vunsc(n,xw,scalex)

      do j=1,n
         h = p + p * abs(xw(j))
         xcj   = xw(j)
         xw(j) = xcj + h

c        avoid (small) rounding errors
c        h = xc(j) - xcj but not here to avoid clever optimizers

         h = rnudif(xw(j), xcj)

         call fvec(xw,fz,n,j)
         xw(j) = xcj

         do i=1,n
            wa(i) = (fz(i)-fc(i))/h
         enddo

         dinf = abs(wa(idamax(n,wa,1)))

         do i=1,n
            if(abs(A(i,j)-wa(i)).gt.tol*dinf) then
               errcnt = errcnt + 1
               if( errcnt .gt. MAXERR ) then
                  termcd = -10
                  return
               endif
               call nwckot(i,j,A(i,j),wa(i))
            endif
         enddo
      enddo

c      call vscal(n,xc,scalex)

      if( errcnt .gt. 0 ) then
         termcd = -10
      endif
      return
      end

c-----------------------------------------------------------------------

      subroutine chkjac2(A,lda,xc,fc,n,epsm,scalex,fz,wa,xw,fvec,termcd,
     *                   dsub,dsuper)

      integer lda,n,termcd,dsub,dsuper
      double precision  A(lda,*),xc(*),fc(*)
      double precision  epsm,scalex(*)
      double precision  fz(*),wa(*),xw(*)
      external fvec

c-------------------------------------------------------------------------
c
c     Check the user supplied jacobian against its finite difference approximation
c
c     Arguments
c
c     In       A       Real(lda,*)     user supplied jacobian
c     In       lda     Integer         leading dimension of ajanal
c     In       xc      Real(*)         vector of x values
c     In       fc      Real(*)         function values f(xc)
c     In       n       Integer         size of x
c     In       epsm    Real            machine precision
c     In       scalex  Real(*)         scaling vector for x()
c     Wk       fz      Real(*)         workspace
c     Wk       wa      Real(*)         workspace
c     Wk       xw      Real(*)         workspace
c     In       fvec    Name            name of routine to evaluate f(x)
c     Out      termcd  Integer         return code
c                                        0  user supplied jacobian ok
c                                      -10  user supplied jacobian NOT ok
c
c-------------------------------------------------------------------------

      integer i,j,k,dsum,errcnt
      double precision  ndigit,p,h,dinf
      double precision  tol
      double precision w(n),xstep(n)

      integer MAXERR
      parameter(MAXERR=10)

      double precision Rquart, Rten, Rzero
      parameter(Rquart=0.25d0, Rten=10.0d0, Rzero=0.0d0)

      dsum = dsub + dsuper + 1

      termcd = 0

c     compute the finite difference jacobian and check it against
c     the user supplied one

      ndigit = -log10(epsm)
      p = sqrt(max(Rten**(-ndigit),epsm))
      tol    = epsm**Rquart

      errcnt = 0
      call dcopy(n,xc,1,xw,1)
      call vunsc(n,xw,scalex)

      do j=1,n
          xstep(j) = p + p * abs(xw(j))
          w(j) = xw(j)
      enddo

      do k=1,dsum
         do j=k,n,dsum
            xw(j) = xw(j) + xstep(j)
         enddo

c        for non finite values error message will be wrong
         call fvec(xw,fz,n,n+k)

         do j=k,n,dsum
             h = xstep(j)
             xw(j) = w(j)
             dinf = Rzero
             do i=max(j-dsuper,1),min(j+dsub,n)
                wa(i) = (fz(i)-fc(i)) / h
                if(abs(wa(i)).gt.dinf) dinf = abs(wa(i))
             enddo

             do i=max(j-dsuper,1),min(j+dsub,n)
                if(abs(A(i,j)-wa(i)).gt.tol*dinf) then
                   errcnt = errcnt + 1
                   if( errcnt .gt. MAXERR ) then
                      termcd = -10
                      return
                   endif
                   call nwckot(i,j,A(i,j),wa(i))
                endif
             enddo
         enddo
      enddo

c      call vscal(n,xc,scalex)

      if( errcnt .gt. 0 ) then
         termcd = -10
      endif
      return
      end

c-----------------------------------------------------------------------

      subroutine chkjac(A,lda,xc,fc,n,epsm,jacflg,scalex,fz,wa,xw,fvec,
     *                  termcd)

      integer lda,n,termcd,jacflg(*)
      double precision  A(lda,*),xc(*),fc(*)
      double precision  epsm,scalex(*)
      double precision  fz(*),wa(*),xw(*)
      external fvec

c-------------------------------------------------------------------------
c
c     Check the user supplied jacobian against its finite difference approximation
c
c     Arguments
c
c     In       A       Real(lda,*)     user supplied jacobian
c     In       lda     Integer         leading dimension of ajanal
c     In       xc      Real(*)         vector of x values
c     In       fc      Real(*)         function values f(xc)
c     In       n       Integer         size of x
c     In       epsm    Real            machine precision
c     In       jacflg  Integer(*)      indicates how to compute jacobian
c                                      jacflg[1]:  0 numeric; 1 user supplied; 2 numerical banded
c                                                  3: user supplied banded
c                                      jacflg[2]: number of sub diagonals or -1 if not banded
c                                      jacflg[3]: number of super diagonals or -1 if not banded
c                                      jacflg[4]: 1 if adjusting jacobian allowed when
c                                                   singular or illconditioned
c     In       scalex  Real(*)         scaling vector for x()
c     Wk       fz      Real(*)         workspace
c     Wk       wa      Real(*)         workspace
c     Wk       xw      Real(*)         workspace
c     In       fvec    Name            name of routine to evaluate f(x)
c     Out      termcd  Integer         return code
c                                        0  user supplied jacobian ok
c                                      -10  user supplied jacobian NOT ok
c
c-------------------------------------------------------------------------

      if(jacflg(1) .eq. 3) then
c        user supplied and banded
         call chkjac2(A,lda,xc,fc,n,epsm,scalex,fz,wa,xw,fvec,termcd,
     *                jacflg(2),jacflg(3))
      else
         call chkjac1(A,lda,xc,fc,n,epsm,scalex,fz,wa,xw,fvec,termcd)
      endif

      return
      end

c-----------------------------------------------------------------------

      subroutine fdjac0(xc,fc,n,epsm,fvec,fz,rjac,ldr)

      integer ldr,n
      double precision  epsm
      double precision  rjac(ldr,*),fz(*),xc(*),fc(*)
      external fvec

c-------------------------------------------------------------------------
c
c     Compute the finite difference jacobian at the current point xc
c
c     Arguments
c
c     In       xc      Real(*)         current point
c     In       fc      Real(*)         function values at current point
c     In       n       Integer         size of x and f
c     In       epsm    Real            machine precision
c     In       fvec    Name            name of routine to evaluate f(x)
c     Wk       fz      Real(*)         workspace
c     Out      rjac    Real(ldr,*)     jacobian matrix at x
c                                        entry [i,j] is derivative of
c                                        f(i) wrt to x(j)
c     In       ldr     Integer         leading dimension of rjac
c
c-------------------------------------------------------------------------

      integer i,j
      double precision  ndigit,p,h,xcj
      double precision  rnudif

      double precision Rten
      parameter(Rten=10d0)

      ndigit = -log10(epsm)
      p = sqrt(max(Rten**(-ndigit),epsm))

      do j=1,n
         h = p + p * abs(xc(j))

c        or as alternative h  = p * max(Rone, abs(xc(j)))

         xcj   = xc(j)
         xc(j) = xcj + h

c        avoid (small) rounding errors
c        h = xc(j) - xcj  but not here to avoid clever optimizers

         h = rnudif(xc(j), xcj)
         call fvec(xc,fz,n,j)
         xc(j) = xcj
         do i=1,n
            rjac(i,j) = (fz(i)-fc(i)) / h
         enddo
      enddo

      return
      end

c-----------------------------------------------------------------------

      subroutine fdjac2(xc,fc,n,epsm,fvec,fz,rjac,ldr,dsub,dsuper,
     *                  w,xstep)

      integer ldr,n,dsub,dsuper
      double precision  epsm
      double precision  rjac(ldr,*),fz(*),xc(*),fc(*)
      double precision  w(*), xstep(*)
      external fvec

c-------------------------------------------------------------------------
c
c     Compute a banded finite difference jacobian at the current point xc
c
c     Arguments
c
c     In       xc      Real(*)         current point
c     In       fc      Real(*)         function values at current point
c     In       n       Integer         size of x and f
c     In       epsm    Real            machine precision
c     In       fvec    Name            name of routine to evaluate f(x)
c     Wk       fz      Real(*)         workspace
c     Out      rjac    Real(ldr,*)     jacobian matrix at x
c                                        entry [i,j] is derivative of
c                                        f(i) wrt to x(j)
c     In       ldr     Integer         leading dimension of rjac
c     In       dsub    Integer         number of subdiagonals
c     In       dsuper  Integer         number of superdiagonals
c     Internal w       Real(*)         for temporary saving of xc
c     Internal xstep   Real(*)         stepsizes
c
c-------------------------------------------------------------------------

      integer i,j,k
      double precision  ndigit,p,h
      double precision  rnudif

      double precision Rten
      parameter(Rten=10d0)

      integer dsum

      dsum = dsub + dsuper + 1

      ndigit = -log10(epsm)
      p = sqrt(max(Rten**(-ndigit),epsm))

      do k=1,n
         xstep(k) = p + p * abs(xc(k))
      enddo

      do k=1,dsum
         do j=k,n,dsum
            w(j) = xc(j)
            xc(j) = xc(j) + xstep(j)
         enddo

         call fvec(xc,fz,n,n+k)
         do j=k,n,dsum
             call nuzero(n,rjac(1,j))
c            fdjac0 for why
c            doing this ensures that results for fdjac2 and fdjac0 will be identical
             h = rnudif(xc(j),w(j))
             xc(j) = w(j)
             do i=max(j-dsuper,1),min(j+dsub,n)
                rjac(i,j) = (fz(i)-fc(i)) / h
             enddo
         enddo
      enddo

      return
      end

c-----------------------------------------------------------------------

      function nudnrm(n, d, x)
      integer n
      double precision  d(*), x(*)
      double precision nudnrm

c-------------------------------------------------------------------------
c
c     calculate  max( abs(d[*]) / max(x[*],1) )
c
c     Arguments
c
c     In   n        Integer       number of elements in d() and x()
c     In   d        Real(*)       vector d
c     In   x        Real(*)       vector x
c
c-------------------------------------------------------------------------

      integer i
      double precision  t

      double precision Rzero, Rone
      parameter(Rzero=0.0d0, Rone=1.0d0)

      t = Rzero
      do i=1,n
         t = max(t, abs(d(i)) / max(abs(x(i)),Rone))
      enddo
      nudnrm = t

      return
      end

c-----------------------------------------------------------------------

      function nuxnrm(n, xn, xc)
      integer n
      double precision  xn(*), xc(*)
      double precision nuxnrm

c-------------------------------------------------------------------------
c
c     calculate  max( abs(xn[*]-xc[*]) / max(xn[*],1) )
c
c     Arguments
c
c     In   n        Integer       number of elements in xn() and xc()
c     In   xn       Real(*)       vector xn
c     In   xc       Real(*)       vector xc
c
c-------------------------------------------------------------------------

      integer i
      double precision  t

      double precision Rzero, Rone
      parameter(Rzero=0.0d0, Rone=1.0d0)

      t = Rzero
      do i=1,n
         t = max(t, abs(xn(i)-xc(i)) / max(abs(xn(i)),Rone))
      enddo
      nuxnrm = t

      return
      end

c-----------------------------------------------------------------------

      function rnudif(x, y)
      double precision x, y
      double precision rnudif

c-------------------------------------------------------------------------
c
c     Return difference of x and y (x - y)
c
c     Arguments
c
c     In   x  Real      argument 1
c     In   y  Real      argument 2
c
c-------------------------------------------------------------------------

      rnudif = x - y
      return
      end

c-----------------------------------------------------------------------

      subroutine compmu(r,ldr,n,mu,y,ierr)

      integer ldr,n,ierr
      double precision r(ldr,*),mu,y(*)

c-------------------------------------------------------------------------
c
c     Compute a small perturbation mu for the (almost) singular matrix R.
c     mu is used in the computation of the Levenberg-Marquardt step.
c
c     Arguments
c
c     In       R       Real(ldr,*)     upper triangular matrix from QR
c     In       ldr     Integer         leading dimension of R
c     In       n       Integer         column dimension of R
c     Out      mu      Real            sqrt(l1 norm of R * infinity norm of R
c                                      * n * epsm * 100) designed to make
c                                        trans(R)*R + mu * I not singular
c     Wk       y       Real(*)         workspace for dlange
c     Out      ierr    Integer         0 indicating mu ok
c                                      3 indicating mu much too small
c
c-------------------------------------------------------------------------

      double precision aifnrm,al1nrm,epsm
      double precision dlantr
      double precision epsmch

      double precision Rhund
      parameter(Rhund=100d0)

c     get the infinity norm of R
c     get the l1 norm of R
      ierr = 0
      aifnrm = dlantr('I','U','N',n,n,r,ldr,y)
      al1nrm = dlantr('1','U','N',n,n,r,ldr,y)
      epsm = epsmch()
      mu = sqrt(n*epsm*Rhund)*aifnrm*al1nrm
c     matrix consists of zero's or near zero's
c     LM correction in liqrev will not work
      if( mu .le. Rhund*epsm ) then
         ierr = 3
      endif
      return
      end

c-----------------------------------------------------------------------

      subroutine cndjac(n,r,ldr,cndtol,rcond,rcdwrk,icdwrk,ierr)
      integer n,ldr,icdwrk(*),ierr
      double precision cndtol,rcond,r(ldr,*),rcdwrk(*)

c---------------------------------------------------------------------
c
c     Check r for singularity and/or ill conditioning
c
c     Arguments
c
c     In       n       Integer         dimension of problem
c     In       r       Real(ldr,*)     upper triangular R from QR decomposition
c     In       ldr     Integer         leading dimension of rjac
c     In       cndtol  Real            tolerance of test for ill conditioning
c                                       when rcond <= cndtol then ierr is set to 1
c                                       cndtol should be >= machine precision
c     Out      rcond   Real            inverse condition  of r
c     Wk       rcdwrk  Real(*)         workspace (for dtrcon)
c     Wk       icdwrk  Integer(*)      workspace (fordtrcon)
c     Out      ierr    Integer         0 indicating Jacobian not ill-conditioned or singular
c                                      1 indicating Jacobian too ill-conditioned
c                                      2 indicating Jacobian completely singular
c
c---------------------------------------------------------------------

      integer i,info
      logical rsing
      double precision Rzero
      parameter(Rzero=0.0d0)

      ierr = 0

      rsing = .false.
      do i=1,n
         if( r(i,i) .eq. Rzero ) then
             rsing = .true.
         endif
      enddo

      if( rsing ) then
         ierr = 2
         rcond = Rzero
      else
         call dtrcon('1','U','N',n,r,ldr,rcond,rcdwrk,icdwrk,info)
         if( rcond .eq. Rzero ) then
             ierr = 2
         elseif( rcond .le. cndtol ) then
             ierr = 1
         endif
      endif

      return
      end

c-----------------------------------------------------------------------

      subroutine nwfjac(x,scalex,f,fq,n,epsm,jacflg,fvec,mkjac,rjac,
     *                  ldr,xw,w,xstep)

      integer ldr,n,jacflg(*)
      double precision  epsm
      double precision  x(*),f(*),scalex(*),xw(*),w(*),xstep(*)
      double precision  rjac(ldr,*),fq(*)
      external fvec,mkjac

c-------------------------------------------------------------------------
c
c     Calculate the jacobian  matrix
c
c     Arguments
c
c     In       x       Real(*)         (scaled) current x values
c     In       scalex  Real(*)         scaling factors x
c     In       f       Real(*)         function values f(x)
c     Wk       fq      Real(*)         (internal) workspace
c     In       n       Integer         size of x and f
c     In       epsm    Real            machine precision
c     In       jacflg  Integer(*)      indicates how to compute jacobian
c                                      jacflg[1]:  0 numeric; 1 user supplied; 2 numerical banded
c                                                  3: user supplied banded
c                                      jacflg[2]: number of sub diagonals or -1 if not banded
c                                      jacflg[3]: number of super diagonals or -1 if not banded
c                                      jacflg[4]: 1 if adjusting jacobian allowed when
c                                                   singular or illconditioned
c     In       fvec    Name            name of routine to evaluate f()
c     In       mkjac   Name            name of routine to evaluate jacobian
c     Out      rjac    Real(ldr,*)     jacobian matrix (unscaled)
c     In       ldr     Integer         leading dimension of rjac
c     Internal xw      Real(*)         used for storing unscaled x
c     Internal w       Real(*)         workspace for banded jacobian
c     Internal xstep   Real(*)         workspace for banded jacobian
c
c-------------------------------------------------------------------------

c     compute the finite difference or analytic jacobian at x

      call dcopy(n,x,1,xw,1)
      call vunsc(n,xw,scalex)
      if(jacflg(1) .eq. 0) then
         call fdjac0(xw,f,n,epsm,fvec,fq,rjac,ldr)
      elseif(jacflg(1) .eq. 2) then
         call fdjac2(xw,f,n,epsm,fvec,fq,rjac,ldr,jacflg(2),jacflg(3),
     *               w,xstep)
      else
         call mkjac(rjac,ldr,xw,n)
      endif

      return
      end

c-----------------------------------------------------------------------

      subroutine nwscjac(n,rjac,ldr,scalex)
      integer n, ldr
      double precision rjac(ldr,*), scalex(*)

c-------------------------------------------------------------------------
c
c     Scale jacobian
c
c     Arguments
c
c     In       n       Integer         size of x and f
c     Inout    rjac    Real(ldr,*)     jacobian matrix
c     In       ldr     Integer         leading dimension of rjac
c     In       scalex  Real(*)         scaling factors for x
c
c-------------------------------------------------------------------------

      integer j
      double precision t, Rone
      parameter(Rone=1.0d0)

      do j = 1,n
         t = Rone/scalex(j)
         call dscal(n,t,rjac(1,j),1)
      enddo

      return
      end

c-----------------------------------------------------------------------

      subroutine nwunscjac(n,rjac,ldr,scalex)
      integer n, ldr
      double precision rjac(ldr,*), scalex(*)

c-------------------------------------------------------------------------
c
c     Unscale jacobian
c
c     Arguments
c
c     In       n       Integer         size of x and f
c     Inout    rjac    Real(ldr,*)     jacobian matrix
c     In       ldr     Integer         leading dimension of rjac
c     In       scalex  Real(*)         scaling factors for x
c
c-------------------------------------------------------------------------

      integer j
      double precision t

      do j = 1,n
         t = scalex(j)
         call dscal(n,t,rjac(1,j),1)
      enddo

      return
      end

c-----------------------------------------------------------------------

      subroutine nwcpsx(n,rjac,ldr,scalex,epsm, mode)

      integer ldr,n,mode
      double precision  epsm
      double precision  scalex(*)
      double precision  rjac(ldr,*)

c-------------------------------------------------------------------------
c
c     Calculate scaling factors from the jacobian  matrix
c
c     Arguments
c
c     In       n       Integer         size of x and f
c     In       rjac    Real(ldr,*)     jacobian matrix
c     In       ldr     Integer         leading dimension of rjac
c     Out      scalex  Real(*)         scaling factors for x
c     In       epsm    Real            machine precision
c     In       mode    Integer         1: initialise, >1: adjust
c-------------------------------------------------------------------------

      integer k
      double precision  dnrm2

      if( mode .eq. 1 ) then
         do k=1,n
            scalex(k) = dnrm2(n,rjac(1,k),1)
            if( scalex(k) .le. epsm ) scalex(k) = 1
         enddo
      else if( mode .gt. 1 ) then
         do k=1,n
            scalex(k) = max(scalex(k),dnrm2(n,rjac(1,k),1))
         enddo
      endif
      return
      end

c-----------------------------------------------------------------------

      subroutine nwcpmt(n, x, scalex, factor, wrk, stepsiz)
      double precision x(*), scalex(*), wrk(*)
      double precision factor, stepsiz
      integer n

c-------------------------------------------------------------------------
c
c     Calculate maximum stepsize
c
c     Arguments
c
c     In       n       Integer     size of x
c     In       x       Real(*)     x-values
c     In       scalex  Real(*)     scaling factors for x
c     In       factor  Real        multiplier
c     Inout    wrk     Real(*)     workspace
c     Out      stepsiz Real        stepsize
c
c     Currently not used
c     Minpack uses this to calculate initial trust region size
c     Not (yet) used in this code because it doesn't seem to help
c     Manually setting an initial trust region size works better
c
c-------------------------------------------------------------------------

      double precision Rzero
      parameter(Rzero=0.0d0)

      double precision  dnrm2

      call dcopy(n,x,1,wrk,1)
      call vscal(n,wrk,scalex)
      stepsiz = factor * dnrm2(n,wrk,1)
      if( stepsiz .eq. Rzero ) stepsiz = factor
      return
      end

c-----------------------------------------------------------------------

      subroutine vscal(n,x,sx)

      integer n
      double precision  x(*),sx(*)

c-------------------------------------------------------------------------
c
c     Scale a vector x
c
c     Arguments
c
c     In       n       Integer         size of x
c     Inout    x       Real(*)         vector to scale
c     In       sx      Real(*)         scaling vector
c
c-------------------------------------------------------------------------

      integer i

      do i = 1,n
         x(i) = sx(i) * x(i)
      enddo

      return
      end

c-----------------------------------------------------------------------

      subroutine vunsc(n,x,sx)

      integer n
      double precision  x(*),sx(*)

c-------------------------------------------------------------------------
c
c     Unscale a vector x
c
c     Arguments
c
c     In       n       Integer         size of x
c     Inout    x       Real(*)         vector to unscale
c     In       sx      Real(*)         scaling vector
c
c-------------------------------------------------------------------------

      integer i

      do i = 1,n
         x(i) = x(i) / sx(i)
      enddo

      return
      end

c-----------------------------------------------------------------------

      subroutine nwfvec(x,n,scalex,fvec,f,fnorm,xw)

      integer n
      double precision  x(*),xw(*),scalex(*),f(*),fnorm
      external fvec

c-------------------------------------------------------------------------
c
c     Evaluate the function at current iterate x and scale its value
c
c     Arguments
c
c     In       x       Real(*)         x
c     In       n       Integer         size of x
c     In       scalex  Real(*)         scaling vector for x
c     In       fvec    Name            name of routine to calculate f(x)
c     Out      f       Real(*)         f(x)
c     Out      fnorm   Real            .5*||f(x)||**2
c     Internal xw      Real(*)         used for storing unscaled xc
c
c-------------------------------------------------------------------------

      double precision dnrm2

      double precision Rhalf
      parameter(Rhalf=0.5d0)

      call dcopy(n,x,1,xw,1)
      call vunsc(n,xw,scalex)
      call fvec(xw,f,n,0)

      fnorm = Rhalf * dnrm2(n,f,1)**2

      return
      end

c-----------------------------------------------------------------------

      function epsmch()

c     Return machine precision
c     Use Lapack routine

      double precision epsmch
      double precision dlamch
      external dlamch

c     dlamch('e') returns negeps (1-eps)
c     dlamch('p') returns 1+eps

      epsmch = dlamch('p')

      return
      end

c-----------------------------------------------------------------------

      function dblhuge()

c     Return largest double precision number
c     Use Lapack routine

      double precision dblhuge
      double precision dlamch
      external dlamch

c     dlamch('o') returns max double precision

      dblhuge = dlamch('o')

      return
      end
back to top