Rev 5457 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
CCC--- FIXME: Instead of subroutines forslv and baksolCCC--- ===== Use ./dtrsl.f !! [see dbksl() in ./S_compat.c !]CCC ~~~~~~~~~CCC subroutines mvmlt[lsu] and sclmul should be REPLACED by BLAS ones!CCCCCC--- choldc(nr,n,a,diagmx,tol,addmax) is ``choleski + tolerance''CCC ------CCC it should make use of BLAS routines as [linkpack's dpofa!]c subroutine fdhesscc this subroutine calculates a numerical approximation to the upperc triangular portion of the second derivative matrix (the hessian).c algorithm a5.6.2 from dennis and schnable (1983), numerical methodsc for unconstrained optimization and nonlinear equations,c prentice-hall, 321-322.cc programmed by richard h. jones, january 11, 1989cc input to subroutinecc n.....the number of parametersc x.....vector of parameter valuesc fval..double precision value of function at xc fun...a function provided by the user which must be declared asc external in the calling program. its call must be of thec call fun(n,x,fval) where fval is the computed value of thec functionc nfd...first dimension of h in the calling programcc output from subroutinecc h.....an n by n matrix of the approximate hessiancc work spacecc step....a real array of length nc f.......a double precision array of length ncsubroutine fdhess(n,x,fval,fun,h,nfd,step,f,ndigit,typx)implicit noneexternal funinteger n,nfd,ndigitdouble precision x(n),fval, h(nfd,nfd),step(n),f(n),typx(n)cdouble precision eta,tempi,tempj,fii,fijinteger i,jeta=(10.0d0**(-ndigit))**(1.0d0/3.0d0)do 10 i=1,nstep(i)=eta*dmax1(x(i),typx(i))if(typx(i).lt.0.0d0)step(i)=-step(i)tempi=x(i)x(i)=x(i)+step(i)step(i)=x(i)-tempicall fun(n,x,f(i))x(i)=tempi10 continuedo 30 i=1,ntempi=x(i)x(i)=x(i)+2.0d0*step(i)call fun(n,x,fii)h(i,i)=((fval-f(i))+(fii-f(i)))/(step(i)*step(i))x(i)=tempi+step(i)if(i.lt.n)thendo 20 j=i+1,ntempj=x(j)x(j)=x(j)+step(j)call fun(n,x,fij)h(i,j)=((fval-f(i))+(fij-f(j)))/(step(i)*step(j))x(j)=tempj20 continueendifx(i)=tempi30 continuereturnendc subroutine baksolcc purposecc solve ax=b where a is upper triangular matrix.c note that a is input as a lower triangular matrix andc that this routine takes its transpose implicitly.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) --> lower triangular matrix (preserved)c x(n) <-- solution vectorc b(n) --> right-hand side vectorcc notecc if b is no longer required by calling routine,c then vectors b and x may share the same storage.ccstaticsubroutine baksol(nr,n,a,x,b)implicit double precision (a-h,o-z)dimension a(nr,*),x(n),b(n)cc solve (l-transpose)x=b. (back solve)ci=nx(i)=b(i)/a(i,i)if(n.eq.1) return30 ip1=ii=i-1sum=0.0d0do 40 j=ip1,nsum=sum+a(j,i)*x(j)40 continuex(i)=(b(i)-sum)/a(i,i)if(i.gt.1) go to 30returnendc subroutine chlhsncc purposecc find the l(l-transpose) [written ll+] decomposition of the perturbedc model hessian matrix a+mu*i(where mu\0 and i is the identity matrix)c which is safely positive definite. if a is safely positive definitec upon entry, then mu=0.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) <--> on entry; "a" is model hessian (only lowerc triangular part and diagonal stored)c on exit: a contains l of ll+ decomposition ofc perturbed model hessian in lower triangularc part and diagonal and contains hessian in upperc triangular part and udiagc epsm --> machine epsilonc sx(n) --> diagonal scaling matrix for xc udiag(n) <-- on exit: contains diagonal of hessiancc internal variablescc tol tolerancec diagmn minimum element on diagonal of ac diagmx maximum element on diagonal of ac offmax maximum off-diagonal element of ac offrow sum of off-diagonal elements in a row of ac evmin minimum eigenvalue of ac evmax maximum eigenvalue of acc descriptioncc 1. if "a" has any negative diagonal elements, then choose mu>0c such that the diagonal of a:=a+mu*i is all positivec with the ratio of its smallest to largest element on thec order of sqrt(epsm).cc 2. "a" undergoes a perturbed cholesky decomposition whichc results in an ll+ decomposition of a+d, where d is ac non-negative diagonal matrix which is implicitly added toc "a" during the decomposition if "a" is not positive definite.c "a" is retained and not changed during this process byc copying l into the upper triangular part of "a" and thec diagonal into udiag. then the cholesky decomposition routinec is called. on return, addmax contains maximum element of d.cc 3. if addmax=0, "a" was positive definite going into step 2c and return is made to calling program. otherwise,c the minimum number sdd which must be added to thec diagonal of a to make it safely strictly diagonally dominantc is calculated. since a+addmax*i and a+sdd*i are safelyc positive definite, choose mu=min(addmax,sdd) and decomposec a+mu*i to obtain l.ccstaticsubroutine chlhsn(nr,n,a,epsm,sx,udiag)implicit double precision (a-h,o-z)dimension a(nr,*),sx(n),udiag(n)cc scale hessianc pre- and post- multiply "a" by inv(sx)cdo 20 j=1,ndo 10 i=j,na(i,j)=a(i,j)/(sx(i)*sx(j))10 continue20 continuecc step1c -----c note: if a different tolerance is desired throughout thisc algorithm, change tolerance here:ctol=sqrt(epsm)cdiagmx=a(1,1)diagmn=a(1,1)if(n.eq.1) go to 35do 30 i=2,nif(a(i,i).lt.diagmn) diagmn=a(i,i)if(a(i,i).gt.diagmx) diagmx=a(i,i)30 continue35 posmax=max(diagmx,0.0d0)cc diagmn .le. 0cif(diagmn.gt.posmax*tol) go to 100c if(diagmn.le.posmax*tol)c thenamu=tol*(posmax-diagmn)-diagmnif(amu.ne.0.0d0) go to 60c if(amu.eq.0.0d0)c thencc find largest off-diagonal element of aoffmax=0.0d0if(n.eq.1) go to 50do 45 i=2,nim1=i-1do 40 j=1,im1if(abs(a(i,j)).gt.offmax) offmax=abs(a(i,j))40 continue45 continue50 amu=offmaxif(amu.ne.0.0d0) go to 55c if(amu.eq.0.0d0)c thenamu=1.0d0go to 60c else55 amu=amu*(1.0d0+tol)c endifc endifcc a=a + mu*ic60 do 65 i=1,na(i,i)=a(i,i)+amu65 continuediagmx=diagmx+amuc endifcc step2cc copy lower triangular part of "a" to upper triangular partc and diagonal of "a" to udiagc100 continuedo 110 j=1,nudiag(j)=a(j,j)if(j.eq.n) go to 110jp1=j+1do 105 i=jp1,na(j,i)=a(i,j)105 continue110 continueccall choldc(nr,n,a,diagmx,tol,addmax)ccc step3cc if addmax=0, "a" was positive definite going into step 2,c the ll+ decomposition has been done, and we return.c otherwise, addmax>0. perturb "a" so that it is safelyc diagonally dominant and find ll+ decompositioncif(addmax.le.0.0d0) go to 170c if(addmax.gt.0.0d0)c thencc restore original "a" (lower triangular part and diagonal)cdo 120 j=1,na(j,j)=udiag(j)if(j.eq.n) go to 120jp1=j+1do 115 i=jp1,na(i,j)=a(j,i)115 continue120 continuecc find sdd such that a+sdd*i is safely positive definitec note: evmin<0 since a is not positive definite;cevmin=0.0d0evmax=a(1,1)do 150 i=1,noffrow=0.0d0if(i.eq.1) go to 135im1=i-1do 130 j=1,im1offrow=offrow+abs(a(i,j))130 continue135 if(i.eq.n) go to 145ip1=i+1do 140 j=ip1,noffrow=offrow+abs(a(j,i))140 continue145 evmin=min(evmin,a(i,i)-offrow)evmax=max(evmax,a(i,i)+offrow)150 continuesdd=tol*(evmax-evmin)-evmincc perturb "a" and decompose againcamu=min(sdd,addmax)do 160 i=1,na(i,i)=a(i,i)+amuudiag(i)=a(i,i)160 continuecc "a" now guaranteed safely positive definiteccall choldc(nr,n,a,0.0d0,tol,addmax)c endifcc unscale hessian and cholesky decomposition matrixc170 do 190 j=1,ndo 175 i=j,na(i,j)=sx(i)*a(i,j)175 continueif(j.eq.1) go to 185jm1=j-1do 180 i=1,jm1a(i,j)=sx(i)*sx(j)*a(i,j)180 continue185 udiag(j)=udiag(j)*sx(j)*sx(j)190 continuereturnendc subroutine choldccc purposecc find the perturbed l(l-transpose) [written ll+] decompositionc of a+d, where d is a non-negative diagonal matrix added to a ifc necessary to allow the cholesky decomposition to continue.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) <--> on entry: matrix for which to find perturbedc cholesky decompositionc on exit: contains l of ll+ decompositionc in lower triangular part and diagonal of "a"c diagmx --> maximum diagonal element of "a"c tol --> tolerancec addmax <-- maximum amount implicitly added to diagonal of "a"c in forming the cholesky decomposition of a+dc internal variablescc aminl smallest element allowed on diagonal of lc amnlsq =aminl**2c offmax maximum off-diagonal element in column of accc descriptioncc the normal cholesky decomposition is performed. however, if at anyc point the algorithm would attempt to set l(i,i)=sqrt(temp)c with temp < tol*diagmx, then l(i,i) is set to sqrt(tol*diagmx)c instead. this is equivalent to adding tol*diagmx-temp to a(i,i)cccstaticsubroutine choldc(nr,n,a,diagmx,tol,addmax)implicit double precision (a-h,o-z)dimension a(nr,*)caddmax=0.0d0aminl=sqrt(diagmx*tol)amnlsq=aminl*aminlcc form column j of lcdo 100 j=1,ncc find diagonal elements of lcsum=0.0d0if(j.eq.1) go to 20jm1=j-1do 10 k=1,jm1sum=sum + a(j,k)*a(j,k)10 continue20 temp=a(j,j)-sumif(temp.lt.amnlsq) go to 30c if(temp.ge.aminl**2)c thena(j,j)=sqrt(temp)go to 40c elsecc find maximum off-diagonal element in columnc30 offmax=0.0d0if(j.eq.n) go to 37jp1=j+1do 35 i=jp1,nif(abs(a(i,j)).gt.offmax) offmax=abs(a(i,j))35 continue37 if(offmax.le.amnlsq) offmax=amnlsqcc add to diagonal element to allow cholesky decomposition to continueca(j,j)=sqrt(offmax)addmax=max(addmax,offmax-temp)c endifcc find i,j element of lower triangular matrix40 if(j.eq.n) go to 100jp1=j+1do 70 i=jp1,nsum=0.0d0if(j.eq.1) go to 60jm1=j-1do 50 k=1,jm1sum=sum+a(i,k)*a(j,k)50 continue60 a(i,j)=(a(i,j)-sum)/a(j,j)70 continue100 continuereturnendc subroutine d1fcncc purposecc dummy routine to prevent unsatisfied external diagnosticc when specific analytic gradient function not supplied.ccstaticsubroutine d1fcn(n,x,g)implicit double precision (a-h,o-z)dimension x(n),g(n)g(n)=g(n)x(n)=x(n)endc subroutine d2fcncc purposecc dummy routine to prevent unsatisfied external diagnosticc when specific analytic hessian function not supplied.ccstaticsubroutine d2fcn(nr,n,x,h)implicit double precision (a-h,o-z)dimension x(n),h(nr,*)h(nr,1)=h(nr,1)x(n)=x(n)endc subroutine dfaultcc purposecc set default values for each input variable toc minimization algorithm.cc parameterscc n --> dimension of problemc x(n) --> initial guess to solution (to compute max step size)c typsiz(n) <-- typical size for each component of xc fscale <-- estimate of scale of minimization functionc method <-- algorithm to use to solve minimization problemc iexp <-- =0 if minimization function not expensive to evaluatec msg <-- message to inhibit certain automatic checks + outputc ndigit <-- number of good digits in minimization functionc itnlim <-- maximum number of allowable iterationsc iagflg <-- =0 if analytic gradient not suppliedc iahflg <-- =0 if analytic hessian not suppliedc ipr <-- device to which to send outputc dlt <-- trust region radiusc gradtl <-- tolerance at which gradient considered close enoughc to zero to terminate algorithmc stepmx <-- value of zero to trip default maximum in optchkc steptl <-- tolerance at which successive iterates consideredc close enough to terminate algorithmccstaticsubroutine dfault(n,x,typsiz,fscale,method,iexp,msg,ndigit,+ itnlim,iagflg,iahflg,ipr,dlt,gradtl,stepmx,steptl)implicit double precision (a-h,o-z)dimension typsiz(n),x(n)x(n)=x(n)cc set typical size of x and minimization functiondo 10 i=1,ntypsiz(i)=1.0d010 continuefscale=1.0d0cc set tolerancescdlt=-1.0d0epsm=d1mach(4)gradtl=epsm**(1.0d0/3.0d0)stepmx=0.0d0steptl=sqrt(epsm)cc set flagscmethod=1iexp=1msg=0ndigit=-1itnlim=150iagflg=0iahflg=0ipr=i1mach(2)creturnendc subroutine dogdrvcc purposecc find a next newton iterate (xpls) by the double dogleg methodcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> old iterate x[k-1]c f --> function value at old iterate, f(x)c g(n) --> gradient at old iterate, g(x), or approximatec a(n,n) --> cholesky decomposition of hessianc in lower triangular part and diagonalc p(n) --> newton stepc xpls(n) <-- new iterate x[k]c fpls <-- function value at new iterate, f(xpls)c fcn --> name of subroutine to evaluate functionc sx(n) --> diagonal scaling matrix for xc stepmx --> maximum allowable step sizec steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc dlt <--> trust region radiusc [retain value between successive calls]c iretcd <-- return codec =0 satisfactory xpls foundc =1 failed to find satisfactory xpls sufficientlyc distinct from xc mxtake <-- boolean flag indicating step of maximum length usedc sc(n) --> workspace [current step]c wrk1(n) --> workspace (and place holding argument to tregup)c wrk2(n) --> workspacec wrk3(n) --> workspacec ipr --> device to which to send outputccstaticsubroutine dogdrv(nr,n,x,f,g,a,p,xpls,fpls,fcn,sx,stepmx,+ steptl,dlt,iretcd,mxtake,sc,wrk1,wrk2,wrk3,ipr,itncnt)implicit double precision (a-h,o-z)dimension x(n),xpls(n),g(n),p(n)dimension sx(n)dimension sc(n),wrk1(n),wrk2(n),wrk3(n)dimension a(nr,*)logical fstdog,nwtake,mxtakeinteger itncntexternal fcnciretcd=4fstdog=.true.tmp=0.0d0do 5 i=1,ntmp=tmp+sx(i)*sx(i)*p(i)*p(i)5 continuernwtln=sqrt(tmp)c$ write(ipr,954) rnwtlnc100 continuecc find new step by double dogleg algorithmccall dogstp(nr,n,g,a,p,sx,rnwtln,dlt,nwtake,fstdog,+ wrk1,wrk2,cln,eta,sc,ipr,stepmx)cc check new point and update trust regionccall tregup(nr,n,x,f,g,a,fcn,sc,sx,nwtake,stepmx,steptl,dlt,+ iretcd,wrk3,fplsp,xpls,fpls,mxtake,ipr,2,wrk1)if(iretcd.le.1) returngo to 100c%950 format(42h dogdrv initial trust region not given.,c% + 22h compute cauchy step.)c%951 format(18h dogdrv alpha =,e20.13/c% + 18h dogdrv beta =,e20.13/c% + 18h dogdrv dlt =,e20.13/c% + 18h dogdrv nwtake=,l1 )c%952 format(28h dogdrv current step (sc))c%954 format(18h0dogdrv rnwtln=,e20.13)c%955 format(14h dogdrv ,5(e20.13,3x))endc subroutine dogstpcc purposecc find new step by double dogleg algorithmcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc g(n) --> gradient at current iterate, g(x)c a(n,n) --> cholesky decomposition of hessian inc lower part and diagonalc p(n) --> newton stepc sx(n) --> diagonal scaling matrix for xc rnwtln --> newton step lengthc dlt <--> trust region radiusc nwtake <--> boolean, =.true. if newton step takenc fstdog <--> boolean, =.true. if on first leg of doglegc ssd(n) <--> workspace [cauchy step to the minimum of thec quadratic model in the scaled steepest descentc direction] [retain value between successive calls]c v(n) <--> workspace [retain value between successive calls]c cln <--> cauchy lengthc [retain value between successive calls]c eta [retain value between successive calls]c sc(n) <-- current stepc ipr --> device to which to send outputc stepmx --> maximum allowable step sizecc internal variablescc cln length of cauchy stepccstaticsubroutine dogstp(nr,n,g,a,p,sx,rnwtln,dlt,nwtake,fstdog,+ ssd,v,cln,eta,sc,ipr,stepmx)implicit double precision (a-h,o-z)dimension g(n),p(n)dimension sx(n)dimension sc(n),ssd(n),v(n)dimension a(nr,*)logical nwtake,fstdogipr=iprcc can we take newton stepcif(rnwtln.gt.dlt) go to 100c if(rnwtln.le.dlt)c thennwtake=.true.do 10 i=1,nsc(i)=p(i)10 continuedlt=rnwtlnc$ write(ipr,951)go to 700c elsecc newton step too longc cauchy step is on double dogleg curvec100 nwtake=.false.if(.not.fstdog) go to 200c if(fstdog)c thencc calculate double dogleg curve (ssd)fstdog=.false.alpha=0.0d0do 110 i=1,nalpha=alpha + (g(i)*g(i))/(sx(i)*sx(i))110 continuebeta=0.0d0do 130 i=1,ntmp=0.0d0do 120 j=i,ntmp=tmp + (a(j,i)*g(j))/(sx(j)*sx(j))120 continuebeta=beta+tmp*tmp130 continuedo 140 i=1,nssd(i)=-(alpha/beta)*g(i)/sx(i)140 continuecln=alpha*sqrt(alpha)/betaeta=.2 + (.8*alpha*alpha)/(-beta*ddot(n,g,1,p,1))do 150 i=1,nv(i)=eta*sx(i)*p(i) - ssd(i)150 continueif (dlt .eq. (-1.0d0)) dlt = min(cln, stepmx)c$ write(ipr,954) alpha,beta,cln,etac$ write(ipr,955)c$ write(ipr,960) (ssd(i),i=1,n)c$ write(ipr,956)c$ write(ipr,960) (v(i),i=1,n)c endif200 if(eta*rnwtln.gt.dlt) go to 220c if(eta*rnwtln .le. dlt)c thencc take partial step in newton directioncdo 210 i=1,nsc(i)=(dlt/rnwtln)*p(i)210 continuec$ write(ipr,957)go to 700c else220 if(cln.lt.dlt) go to 240c if(cln.ge.dlt)c thenc take step in steepest descent directioncdo 230 i=1,nsc(i)=(dlt/cln)*ssd(i)/sx(i)230 continuec$ write(ipr,958)go to 700c elsecc calculate convex combination of ssd and eta*pc which has scaled length dltc240 dot1=ddot(n,v,1,ssd,1)dot2=ddot(n,v,1,v,1)alam=(-dot1+sqrt((dot1*dot1)-dot2*(cln*cln-dlt*dlt)))/dot2do 250 i=1,nsc(i)=(ssd(i) + alam*v(i))/sx(i)250 continuec$ write(ipr,959)c endifc endifc endif700 continuec$ write(ipr,952) fstdog,nwtake,rnwtln,dltc$ write(ipr,953)c$ write(ipr,960) (sc(i),i=1,n)returncc%951 format(27h0dogstp take newton step)c%952 format(18h dogstp fstdog=,l1/c% + 18h dogstp nwtake=,l1/c% + 18h dogstp rnwtln=,e20.13/c% + 18h dogstp dlt =,e20.13)c%953 format(28h dogstp current step (sc))c%954 format(18h dogstp alpha =,e20.13/c% + 18h dogstp beta =,e20.13/c% + 18h dogstp cln =,e20.13/c% + 18h dogstp eta =,e20.13)c%955 format(28h dogstp cauchy step (ssd))c%956 format(12h dogstp v)c%957 format(48h0dogstp take partial step in newton direction)c%958 format(50h0dogstp take step in steepest descent direction)c%959 format(39h0dogstp take convex combination step)c%960 format(14h dogstp ,5(e20.13,3x))endc subroutine forslvcc purposecc solve ax=b where a is lower triangular matrixcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) --> lower triangular matrix (preserved)c x(n) <-- solution vectorc b(n) --> right-hand side vectorcc notecc if b is no longer required by calling routine,c then vectors b and x may share the same storage.ccstaticsubroutine forslv(nr,n,a,x,b)implicit double precision (a-h,o-z)dimension a(nr,*),x(n),b(n)cc solve lx=b. (foreward solve)cx(1)=b(1)/a(1,1)if(n.eq.1) returndo 20 i=2,nsum=0.0d0im1=i-1do 10 j=1,im1sum=sum+a(i,j)*x(j)10 continuex(i)=(b(i)-sum)/a(i,i)20 continuereturnendc subroutine fstocdcc purposecc find central difference approximation g to the first derivativec (gradient) of the function defined by fcn at the point x.cc parameterscc n --> dimension of problemc x --> point at which gradient is to be approximated.c fcn --> name of subroutine to evaluate function.c sx --> diagonal scaling matrix for x.c rnoise --> relative noise in fcn [f(x)].c g <-- central difference approximation to gradient.cccstaticsubroutine fstocd (n, x, fcn, sx, rnoise, g)implicit noneinteger nexternal fcndouble precision x(n), sx(n), g(n), rnoisecinteger idouble precision third, stepi,xtempi, fplus, fminuscc find i th stepsize, evaluate two neighbors in direction of i thc unit vector, and evaluate i th component of gradient.cthird = 1.0d0/3.0d0do 10 i = 1, nstepi = rnoise**third * max(abs(x(i)), 1.0d0/sx(i))xtempi = x(i)x(i) = xtempi + stepicall fcn (n, x, fplus)x(i) = xtempi - stepicall fcn (n, x, fminus)x(i) = xtempig(i) = (fplus - fminus)/(2.0d0*stepi)10 continuereturnendc subroutine fstofdcc purposecc find first order forward finite difference approximation "a" to thec first derivative of the function defined by the subprogram "fname"c evaluated at the new iterate "xpls".cc for optimization use this routine to estimate:c 1) the first derivative (gradient) of the optimization function "fcnc analytic user routine has been supplied;c 2) the second derivative (hessian) of the optimization functionc if no analytic user routine has been supplied for the hessian butc one has been supplied for the gradient ("fcn") and if thec optimization function is inexpensive to evaluatecc notecc _m=1 (optimization) algorithm estimates the gradient of the functionc (fcn). fcn(x) # f: r(n)-->r(1)c _m=n (systems) algorithm estimates the jacobian of the functionc fcn(x) # f: r(n)-->r(n).c _m=n (optimization) algorithm estimates the hessian of the optimizatioc function, where the hessian is the first derivative of "fcn"cc parameterscc nr --> row dimension of matrixc m --> number of rows in ac n --> number of columns in a; dimension of problemc xpls(n) --> new iterate: x[k]c fcn --> name of subroutine to evaluate functionc fpls(m) --> _m=1 (optimization) function value at new iterate:c fcn(xpls)c _m=n (optimization) value of first derivativec (gradient) given by user function fcnc _m=n (systems) function value of associatedc minimization functionc a(nr,n) <-- finite difference approximation (see note). onlyc lower triangular matrix and diagonal are returnedc sx(n) --> diagonal scaling matrix for xc rnoise --> relative noise in fcn [f(x)]c fhat(m) --> workspacec icase --> =1 optimization (gradient)c =2 systemsc =3 optimization (hessian)cc internal variablescc stepsz - stepsize in the j-th variable directionccstaticsubroutine fstofd(nr,m,n,xpls,fcn,fpls,a,sx,rnoise,fhat,icase)implicit double precision (a-h,o-z)dimension xpls(n),fpls(m)dimension fhat(m)dimension sx(n)dimension a(nr,*)cc find j-th column of ac each column is derivative of f(fcn) with respect to xpls(j)cdo 30 j=1,nstepsz=sqrt(rnoise)*max(abs(xpls(j)),1.0d0/sx(j))xtmpj=xpls(j)xpls(j)=xtmpj+stepszcall fcn(n,xpls,fhat)xpls(j)=xtmpjdo 20 i=1,ma(i,j)=(fhat(i)-fpls(i))/stepsz20 continue30 continueif(icase.ne.3) returncc if computing hessian, a must be symmetriccif(n.eq.1) returnnm1=n-1do 50 j=1,nm1jp1=j+1do 40 i=jp1,ma(i,j)=(a(i,j)+a(j,i))/2.0d040 continue50 continuereturnendc subroutine grdchkcc purposecc check analytic gradient against estimated gradientcc parameterscc n --> dimension of problemc x(n) --> estimate to a root of fcnc fcn --> name of subroutine to evaluate optimization functionc must be declared external in calling routinec fcn: r(n) --> r(1)c f --> function value: fcn(x)c g(n) --> gradient: g(x)c typsiz(n) --> typical size for each component of xc sx(n) --> diagonal scaling matrix: sx(i)=1./typsiz(i)c fscale --> estimate of scale of objective function fcnc rnf --> relative noise in optimization function fcnc analtl --> tolerance for comparison of estimated andc analytical gradientsc wrk1(n) --> workspacec msg <-- message or error codec on output: =-21, probable coding error of gradientc ipr --> device to which to send outputccstaticsubroutine grdchk(n,x,fcn,f,g,typsiz,sx,fscale,rnf,+ analtl,wrk1,msg,ipr)implicit double precision (a-h,o-z)dimension x(n),g(n)dimension sx(n),typsiz(n)dimension wrk1(n)external fcncc compute first order finite difference gradient and compare toc analytic gradient.ccall fstofd(1,1,n,x,fcn,f,wrk1,sx,rnf,wrk,1)ker=0do 5 i=1,ngs=max(abs(f),fscale)/max(abs(x(i)),typsiz(i))if(abs(g(i)-wrk1(i)).gt.max(abs(g(i)),gs)*analtl) ker=15 continueif(ker.eq.0) go to 20c% write(ipr,901)c% write(ipr,902) (i,g(i),wrk1(i),i=1,n)msg=-2120 continuereturnc%901 format(47h0grdchk probable error in coding of analytic,c% + 19h gradient function./c% + 16h grdchk comp,12x,8hanalytic,12x,8hestimate)c%902 format(11h grdchk ,i5,3x,e20.13,3x,e20.13)endc subroutine heschkcc purposecc check analytic hessian against estimated hessianc (this may be done only if the user supplied analytic hessianc d2fcn fills only the lower triangular part and diagonal of a)cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> estimate to a root of fcnc fcn --> name of subroutine to evaluate optimization functionc must be declared external in calling routinec fcn: r(n) --> r(1)c d1fcn --> name of subroutine to evaluate gradient of fcn.c must be declared external in calling routinec d2fcn --> name of subroutine to evaluate hessian of fcn.c must be declared external in calling routinec f --> function value: fcn(x)c g(n) <-- gradient: g(x)c a(n,n) <-- on exit: hessian in lower triangular part and diagc typsiz(n) --> typical size for each component of xc sx(n) --> diagonal scaling matrix: sx(i)=1./typsiz(i)c rnf --> relative noise in optimization function fcnc analtl --> tolerance for comparison of estimated andc analytical gradientsc iagflg --> =1 if analytic gradient suppliedc udiag(n) --> workspacec wrk1(n) --> workspacec wrk2(n) --> workspacec msg <--> message or error codec on input : if =1xx do not compare anal + est hessc on output: =-22, probable coding error of hessianc ipr --> device to which to send outputccstaticsubroutine heschk(nr,n,x,fcn,d1fcn,d2fcn,f,g,a,typsiz,sx,rnf,+ analtl,iagflg,udiag,wrk1,wrk2,msg,ipr)implicit double precision (a-h,o-z)dimension x(n),g(n),a(nr,*)dimension typsiz(n),sx(n)dimension udiag(n),wrk1(n),wrk2(n)external fcn,d1fcncc compute finite difference approximation a to the hessian.cif(iagflg.eq.1) call fstofd(nr,n,n,x,d1fcn,g,a,sx,rnf,wrk1,3)if(iagflg.ne.1) call sndofd(nr,n,x,fcn,f,a,sx,rnf,wrk1,wrk2)cker=0cc copy lower triangular part of "a" to upper triangular partc and diagonal of "a" to udiagcdo 30 j=1,nudiag(j)=a(j,j)if(j.eq.n) go to 30jp1=j+1do 25 i=jp1,na(j,i)=a(i,j)25 continue30 continuecc compute analytic hessian and compare to finite differencec approximation.ccall d2fcn(nr,n,x,a)do 40 j=1,nhs=max(abs(g(j)),1.0d0)/max(abs(x(j)),typsiz(j))if(abs(a(j,j)-udiag(j)).gt.max(abs(udiag(j)),hs)*analtl)+ ker=1if(j.eq.n) go to 40jp1=j+1do 35 i=jp1,nif(abs(a(i,j)-a(j,i)).gt.max(abs(a(i,j)),hs)*analtl) ker=135 continue40 continuecif(ker.eq.0) go to 90c% write(ipr,901)c% do 50 i=1,nc% if(i.eq.1) go to 45c% im1=i-1c% do 43 j=1,im1c% write(ipr,902) i,j,a(i,j),a(j,i)c% 43 continuec% 45 write(ipr,902) i,i,a(i,i),udiag(i)c% 50 continuemsg=-22c endif90 continuereturnc%901 format(47h heschk probable error in coding of analytic,c% + 18h hessian function./c% + 21h heschk row col,14x,8hanalytic,14x,10h(estimate))c%902 format(11h heschk ,2i5,2x,e20.13,2x,1h(,e20.13,1h))endc subroutine hookdrcc purposecc find a next newton iterate (xpls) by the more-hebdon methodcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> old iterate x[k-1]c f --> function value at old iterate, f(x)c g(n) --> gradient at old iterate, g(x), or approximatec a(n,n) --> cholesky decomposition of hessian in lowerc triangular part and diagonal.c hessian in upper triangular part and udiag.c udiag(n) --> diagonal of hessian in a(.,.)c p(n) --> newton stepc xpls(n) <-- new iterate x[k]c fpls <-- function value at new iterate, f(xpls)c fcn --> name of subroutine to evaluate functionc sx(n) --> diagonal scaling matrix for xc stepmx --> maximum allowable step sizec steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc dlt <--> trust region radiusc iretcd <-- return codec =0 satisfactory xpls foundc =1 failed to find satisfactory xpls sufficientlyc distinct from xc mxtake <-- boolean flag indicating step of maximum length usedc amu <--> [retain value between successive calls]c dltp <--> [retain value between successive calls]c phi <--> [retain value between successive calls]c phip0 <--> [retain value between successive calls]c sc(n) --> workspacec xplsp(n) --> workspacec wrk0(n) --> workspacec epsm --> machine epsilonc itncnt --> iteration countc ipr --> device to which to send outputccstaticsubroutine hookdr(nr,n,x,f,g,a,udiag,p,xpls,fpls,fcn,sx,stepmx,+ steptl,dlt,iretcd,mxtake,amu,dltp,phi,phip0,+ sc,xplsp,wrk0,epsm,itncnt,ipr)implicit double precision (a-h,o-z)dimension x(n),g(n),p(n),xpls(n),sx(n)dimension a(nr,*),udiag(n)dimension sc(n),xplsp(n),wrk0(n)logical mxtake,nwtakelogical fstimeexternal fcnciretcd=4fstime=.true.tmp=0.0d0do 5 i=1,ntmp=tmp+sx(i)*sx(i)*p(i)*p(i)5 continuernwtln=sqrt(tmp)c$ write(ipr,954) rnwtlncif(itncnt.gt.1) go to 100c if(itncnt.eq.1)c thenamu=0.0d0cc if first iteration and trust region not provided by user,c compute initial trust region.cif(dlt.ne. (-1.0d0)) go to 100c if(dlt.eq. (-1.0d0))c thenalpha=0.0d0do 10 i=1,nalpha=alpha+(g(i)*g(i))/(sx(i)*sx(i))10 continuebeta=0.0d0do 30 i=1,ntmp=0.0d0do 20 j=i,ntmp=tmp + (a(j,i)*g(j))/(sx(j)*sx(j))20 continuebeta=beta+tmp*tmp30 continuedlt=alpha*sqrt(alpha)/betadlt = min(dlt, stepmx)c$ write(ipr,950)c$ write(ipr,951) alpha,beta,dltc endifc endifc100 continuecc find new step by more-hebdon algorithmccall hookst(nr,n,g,a,udiag,p,sx,rnwtln,dlt,amu,+ dltp,phi,phip0,fstime,sc,nwtake,wrk0,epsm,ipr)dltp=dltcc check new point and update trust regionccall tregup(nr,n,x,f,g,a,fcn,sc,sx,nwtake,stepmx,steptl,+ dlt,iretcd,xplsp,fplsp,xpls,fpls,mxtake,ipr,3,udiag)if(iretcd.le.1) returngo to 100cc%950 format(43h hookdr initial trust region not given. ,c% + 21h compute cauchy step.)c%951 format(18h hookdr alpha =,e20.13/c% + 18h hookdr beta =,e20.13/c% + 18h hookdr dlt =,e20.13)c%952 format(28h hookdr current step (sc))c%954 format(18h0hookdr rnwtln=,e20.13)c%955 format(14h hookdr ,5(e20.13,3x))endc subroutine hookstcc purposecc find new step by more-hebdon algorithmcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc g(n) --> gradient at current iterate, g(x)c a(n,n) --> cholesky decomposition of hessian inc lower triangular part and diagonal.c hessian or approx in upper triangular partc udiag(n) --> diagonal of hessian in a(.,.)c p(n) --> newton stepc sx(n) --> diagonal scaling matrix for nc rnwtln --> newton step lengthc dlt <--> trust region radiusc amu <--> [retain value between successive calls]c dltp --> trust region radius at last exit from this routinec phi <--> [retain value between successive calls]c phip0 <--> [retain value between successive calls]c fstime <--> boolean. =.true. if first entry to this routinec during k-th iterationc sc(n) <-- current stepc nwtake <-- boolean, =.true. if newton step takenc wrk0 --> workspacec epsm --> machine epsilonc ipr --> device to which to send outputccstaticsubroutine hookst(nr,n,g,a,udiag,p,sx,rnwtln,dlt,amu,+ dltp,phi,phip0,fstime,sc,nwtake,wrk0,epsm,ipr)implicit double precision (a-h,o-z)dimension g(n),p(n),sx(n),sc(n),wrk0(n)dimension a(nr,*),udiag(n)logical nwtake,donelogical fstimecc hi and alo are constants used in this routine.c change here if other values are to be substituted.ipr=iprhi=1.5d0alo=0.75d0cif(rnwtln.gt.hi*dlt) go to 15c if(rnwtln.le.hi*dlt)c thencc take newton stepcnwtake=.true.do 10 i=1,nsc(i)=p(i)10 continuedlt=min(dlt,rnwtln)amu=0.0d0c$ write(ipr,951)returnc elsecc newton step not takenc15 continuec$ write(ipr,952)nwtake=.false.if(amu.le.0.0d0) go to 20c if(amu.gt.0.0d0)c thenamu=amu- (phi+dltp) *((dltp-dlt)+phi)/(dlt*phip)c$ write(ipr,956) amuc endif20 continuephi=rnwtln-dltif(.not.fstime) go to 28c if(fstime)c thendo 25 i=1,nwrk0(i)=sx(i)*sx(i)*p(i)25 continuecc solve l*y = (sx**2)*pccall forslv(nr,n,a,wrk0,wrk0)phip0=-dnrm2(n,wrk0,1)**2/rnwtlnfstime=.false.c endif28 phip=phip0amulo=-phi/phipamuup=0.0d0do 30 i=1,namuup=amuup+(g(i)*g(i))/(sx(i)*sx(i))30 continueamuup=sqrt(amuup)/dltdone=.false.c$ write(ipr,956) amuc$ write(ipr,959) phic$ write(ipr,960) phipc$ write(ipr,957) amuloc$ write(ipr,958) amuupcc test value of amu; generate next amu if necessaryc100 continueif(done) returnc$ write(ipr,962)if(amu.ge.amulo .and. amu.le.amuup) go to 110c if(amu.lt.amulo .or. amu.gt.amuup)c thenamu=max(sqrt(amulo*amuup),amuup*1.0d-3)c$ write(ipr,956) amuc endif110 continuecc copy (h,udiag) to lc where h <-- h+amu*(sx**2) [do not actually change (h,udiag)]do 130 j=1,na(j,j)=udiag(j) + amu*sx(j)*sx(j)if(j.eq.n) go to 130jp1=j+1do 120 i=jp1,na(i,j)=a(j,i)120 continue130 continuecc factor h=l(l+)ccall choldc(nr,n,a,0.0d0,sqrt(epsm),addmax)cc solve h*p = l(l+)*sc = -gcdo 140 i=1,nwrk0(i)=-g(i)140 continuecall lltslv(nr,n,a,sc,wrk0)c$ write(ipr,955)c$ write(ipr,963) (sc(i),i=1,n)cc reset h. note since udiag has not been destroyed we need doc nothing here. h is in the upper part and in udiag, still intactcstepln=0.0d0do 150 i=1,nstepln=stepln + sx(i)*sx(i)*sc(i)*sc(i)150 continuestepln=sqrt(stepln)phi=stepln-dltdo 160 i=1,nwrk0(i)=sx(i)*sx(i)*sc(i)160 continuecall forslv(nr,n,a,wrk0,wrk0)phip=-dnrm2(n,wrk0,1)**2/steplnc$ write(ipr,961) dlt,steplnc$ write(ipr,959) phic$ write(ipr,960) phipif((alo*dlt.gt.stepln .or. stepln.gt.hi*dlt) .and.+ (amuup-amulo.gt.0.0d0)) go to 170c if((alo*dlt.le.stepln .and. stepln.le.hi*dlt) .or.c (amuup-amulo.le.0.0d0))c thencc sc is acceptable hookstepcc$ write(ipr,954)done=.true.go to 100c elsecc sc not acceptable hookstep. select new amuc170 continuec$ write(ipr,953)amulo=max(amulo,amu-(phi/phip))if(phi.lt.0.0d0) amuup=min(amuup,amu)amu=amu-(stepln*phi)/(dlt*phip)c$ write(ipr,956) amuc$ write(ipr,957) amuloc$ write(ipr,958) amuupgo to 100c endifc endifcc%951 format(27h0hookst take newton step)c%952 format(32h0hookst newton step not taken)c%953 format(31h hookst sc is not acceptable)c%954 format(27h hookst sc is acceptable)c%955 format(28h hookst current step (sc))c%956 format(18h hookst amu =,e20.13)c%957 format(18h hookst amulo =,e20.13)c%958 format(18h hookst amuup =,e20.13)c%959 format(18h hookst phi =,e20.13)c%960 format(18h hookst phip =,e20.13)c%961 format(18h hookst dlt =,e20.13/c% + 18h hookst stepln=,e20.13)c%962 format(23h0hookst find new amu)c%963 format(14h hookst ,5(e20.13,3x))endc subroutine hsnintcc purposecc provide initial hessian when using secant updatescc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) <-- initial hessian (lower triangular matrix)c sx(n) --> diagonal scaling matrix for xc method --> algorithm to use to solve minimization problemc =1,2 factored secant method usedc =3 unfactored secant method usedccstaticsubroutine hsnint(nr,n,a,sx,method)implicit double precision (a-h,o-z)dimension a(nr,*),sx(n)cdo 100 j=1,nif(method.eq.3) a(j,j)=sx(j)*sx(j)if(method.ne.3) a(j,j)=sx(j)if(j.eq.n) go to 100jp1=j+1do 90 i=jp1,na(i,j)=0.0d090 continue100 continuereturnendc subroutine lltslvcc purposecc solve ax=b where a has the form l(l-transpose)c but only the lower triangular part, l, is stored.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) --> matrix of form l(l-transpose).c on return a is unchanged.c x(n) <-- solution vectorc b(n) --> right-hand side vectorcc notecc if b is not required by calling program, thenc b and x may share the same storage.ccstaticsubroutine lltslv(nr,n,a,x,b)implicit double precision (a-h,o-z)dimension a(nr,*),x(n),b(n)cc forward solve, result in xccall forslv(nr,n,a,x,b)cc back solve, result in xccall baksol(nr,n,a,x,x)returnendc subroutine lnsrchcc purposecc find a next newton iterate by line search.cc parameterscc n --> dimension of problemc x(n) --> old iterate: x[k-1]c f --> function value at old iterate, f(x)c g(n) --> gradient at old iterate, g(x), or approximatec p(n) --> non-zero newton stepc xpls(n) <-- new iterate x[k]c fpls <-- function value at new iterate, f(xpls)c fcn --> name of subroutine to evaluate functionc iretcd <-- return codec mxtake <-- boolean flag indicating step of maximum length usedc stepmx --> maximum allowable step sizec steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc sx(n) --> diagonal scaling matrix for xc ipr --> device to which to send outputcc internal variablescc sln newton lengthc rln relative length of newton stepccstaticsubroutine lnsrch(n,x,f,g,p,xpls,fpls,fcn,mxtake,+ iretcd,stepmx,steptl,sx,ipr)implicit double precision (a-h,o-z)integer n,iretcddimension sx(n)dimension x(n),g(n),p(n)dimension xpls(n)logical mxtakecipr=iprmxtake=.false.iretcd=2c$ write(ipr,954)c$ write(ipr,955) (p(i),i=1,n)tmp=0.0d0do 5 i=1,ntmp=tmp+sx(i)*sx(i)*p(i)*p(i)5 continuesln=sqrt(tmp)if(sln.le.stepmx) go to 10cc newton step longer than maximum allowedscl=stepmx/slncall sclmul(n,scl,p,p)sln=stepmxc$ write(ipr,954)c$ write(ipr,955) (p(i),i=1,n)10 continueslp=ddot(n,g,1,p,1)rln=0.0d0do 15 i=1,nrln=max(rln,abs(p(i))/max(abs(x(i)),1.0d0/sx(i)))15 continuermnlmb=steptl/rlnalmbda=1.0d0c$ write(ipr,952) sln,slp,rmnlmb,stepmx,steptlcc loopc check if new iterate satisfactory. generate new lambda if necessary.c100 continueif(iretcd.lt.2) returndo 105 i=1,nxpls(i)=x(i) + almbda*p(i)105 continuecall fcn(n,xpls,fpls)c$ write(ipr,950) almbdac$ write(ipr,951)c$ write(ipr,955) (xpls(i),i=1,n)c$ write(ipr,953) fplsif(fpls.gt. f+slp*1.d-4*almbda) go to 130c if(fpls.le. f+slp*1.d-4*almbda)c thencc solution foundciretcd=0if(almbda.eq.1.0d0 .and. sln.gt. 0.99d0*stepmx) mxtake=.true.go to 100cc solution not (yet) foundcc else130 if(almbda .ge. rmnlmb) go to 140c if(almbda .lt. rmnlmb)c thencc no satisfactory xpls found sufficiently distinct from xciretcd=1go to 100c elsecc calculate new lambdac140 if(almbda.ne.1.0d0) go to 150c if(almbda.eq.1.0d0)c thencc first backtrack: quadratic fitctlmbda=-slp/(2.0d0*(fpls-f-slp))go to 170c elsecc all subsequent backtracks: cubic fitc150 t1=fpls-f-almbda*slpt2=pfpls-f-plmbda*slpt3=1.0d0/(almbda-plmbda)a=t3*(t1/(almbda*almbda) - t2/(plmbda*plmbda))b=t3*(t2*almbda/(plmbda*plmbda)+ - t1*plmbda/(almbda*almbda) )disc=b*b-3.0d0*a*slpif(disc.le. b*b) go to 160c if(disc.gt. b*b)c thencc only one positive critical point, must be minimumctlmbda=(-b+sign(1.0d0,a)*sqrt(disc))/(3.0d0*a)go to 165c elsecc both critical points positive, first is minimumc160 tlmbda=(-b-sign(1.0d0,a)*sqrt(disc))/(3.0d0*a)c endif165 if(tlmbda.gt. .5*almbda) tlmbda=.5*almbdac endif170 plmbda=almbdapfpls=fplsif(tlmbda.ge. almbda*.1) go to 180c if(tlmbda.lt.almbda/10.0d0)c thenalmbda=almbda*.1go to 190c else180 almbda=tlmbdac endifc endifc endif190 go to 100c%950 format(18h lnsrch almbda=,e20.13)c%951 format(29h lnsrch new iterate (xpls))c%952 format(18h lnsrch sln =,e20.13/c% + 18h lnsrch slp =,e20.13/c% + 18h lnsrch rmnlmb=,e20.13/c% + 18h lnsrch stepmx=,e20.13/c% + 18h lnsrch steptl=,e20.13)c%953 format(19h lnsrch f(xpls)=,e20.13)c%954 format(26h0lnsrch newton step (p))c%955 format(14h lnsrch ,5(e20.13,3x))endc subroutine mvmltlcc purposecc compute y=lxc where l is a lower triangular matrix stored in acc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) --> lower triangular (n*n) matrixc x(n) --> operand vectorc y(n) <-- result vectorcc notecc x and y cannot share storageccstaticsubroutine mvmltl(nr,n,a,x,y)implicit double precision (a-h,o-z)dimension a(nr,*),x(n),y(n)do 30 i=1,nsum=0.0d0do 10 j=1,isum=sum+a(i,j)*x(j)10 continuey(i)=sum30 continuereturnendc subroutine mvmltscc purposecc compute y=axc where "a" is a symmetric (n*n) matrix stored in its lowerc triangular part and x,y are n-vectorscc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) --> symmetric (n*n) matrix stored inc lower triangular part and diagonalc x(n) --> operand vectorc y(n) <-- result vectorcc notecc x and y cannot share storage.ccstaticsubroutine mvmlts(nr,n,a,x,y)implicit double precision (a-h,o-z)dimension a(nr,*),x(n),y(n)do 30 i=1,nsum=0.0d0do 10 j=1,isum=sum+a(i,j)*x(j)10 continueif(i.eq.n) go to 25ip1=i+1do 20 j=ip1,nsum=sum+a(j,i)*x(j)20 continue25 y(i)=sum30 continuereturnendc subroutine mvmltucc purposecc compute y=(l+)xc where l is a lower triangular matrix stored in ac (l-transpose (l+) is taken implicitly)cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(nr,1) --> lower triangular (n*n) matrixc x(n) --> operand vectorc y(n) <-- result vectorcc notecc x and y cannot share storageccstaticsubroutine mvmltu(nr,n,a,x,y)implicit double precision (a-h,o-z)dimension a(nr,*),x(n),y(n)do 30 i=1,nsum=0.0d0do 10 j=i,nsum=sum+a(j,i)*x(j)10 continuey(i)=sum30 continuereturnendc subroutine optchkcc purposecc check input for reasonablenesscc parameterscc n --> dimension of problemc x(n) --> on entry, estimate to root of fcnc typsiz(n) <--> typical size of each component of xc sx(n) <-- diagonal scaling matrix for xc fscale <--> estimate of scale of objective function fcnc gradtl --> tolerance at which gradient considered closec enough to zero to terminate algorithmc itnlim <--> maximum number of allowable iterationsc ndigit <--> number of good digits in optimization function fcnc epsm --> machine epsilonc dlt <--> trust region radiusc method <--> algorithm indicatorc iexp <--> expense flagc iagflg <--> =1 if analytic gradient suppliedc iahflg <--> =1 if analytic hessian suppliedc stepmx <--> maximum step sizec msg <--> message and error codec ipr --> device to which to send outputccstaticsubroutine optchk(n,x,typsiz,sx,fscale,gradtl,itnlim,ndigit,epsm,+ dlt,method,iexp,iagflg,iahflg,stepmx,msg,ipr)implicit double precision (a-h,o-z)dimension x(n),typsiz(n),sx(n)cc check that parameters only take on acceptable values.c if not, set them to default values.if(method.lt.1 .or. method.gt.3) method=1if(iagflg.ne.1) iagflg=0if(iahflg.ne.1) iahflg=0if(iexp.ne.0) iexp=1if(mod(msg/2,2).eq.1 .and. iagflg.eq.0) go to 830if(mod(msg/4,2).eq.1 .and. iahflg.eq.0) go to 835cc check dimension of problemcif(n.le.0) go to 805if(n.eq.1 .and. mod(msg,2).eq.0) go to 810cc compute scale matrixcdo 10 i=1,nif(typsiz(i).eq.0.0d0) typsiz(i)=1.0if(typsiz(i).lt.0.0d0) typsiz(i)=-typsiz(i)sx(i)=1.0d0/typsiz(i)10 continuecc check maximum step sizecif (stepmx .gt. 0.0d0) go to 20stpsiz = 0.0d0do 15 i = 1, nstpsiz = stpsiz + x(i)*x(i)*sx(i)*sx(i)15 continuestpsiz = sqrt(stpsiz)stepmx = max(1.0d3*stpsiz, 1.0d3)20 continuec check function scaleif(fscale.eq.0.0d0) fscale=1.0d0if(fscale.lt.0.0d0) fscale=-fscalecc check gradient toleranceif(gradtl.lt.0.0d0) go to 815cc check iteration limitif(itnlim.le.0) go to 820cc check number of digits of accuracy in function fcnif(ndigit.eq.0) go to 825if(ndigit.lt.0) ndigit=-log10(epsm)cc check trust region radiusif(dlt.le.0.0d0) dlt=-1.0d0if (dlt .gt. stepmx) dlt = stepmxreturncc error exitscc%805 write(ipr,901) nc% msg=-1805 msg=-1go to 895c%810 write(ipr,902)c% msg=-2810 msg=-2go to 895c%815 write(ipr,903) gradtlc% msg=-3815 msg=-3go to 895c%820 write(ipr,904) itnlimc% msg=-4820 msg=-4go to 895c%825 write(ipr,905) ndigitc% msg=-5825 msg=-5go to 895c%830 write(ipr,906) msg,iagflgc% msg=-6830 msg=-6go to 895c%835 write(ipr,907) msg,iahflgc% msg=-7835 msg=-7895 returnc%901 format(32h0optchk illegal dimension, n=,i5)c%902 format(55h0optchk +++ warning +++ this package is inefficient,c% + 26h for problems of size n=1./c% + 48h optchk check installation libraries for more,c% + 22h appropriate routines./c% + 41h optchk if none, set msg and resubmit.)c%903 format(38h0optchk illegal tolerance. gradtl=,e20.13)c%904 format(44h0optchk illegal iteration limit. itnlim=,i5)c%905 format(52h0optchk minimization function has no good digits.,c% + 9h ndigit=,i5)c%906 format(50h0optchk user requests that analytic gradient be,c% + 33h accepted as properly coded (msg=,i5, 2h),/c% + 45h optchk but analytic gradient not supplied,c% + 9h (iagflg=,i5, 2h).)c%907 format(49h0optchk user requests that analytic hessian be,c% + 33h accepted as properly coded (msg=,i5, 2h),/c% + 44h optchk but analytic hessian not supplied,c% + 9h (iahflg=,i5, 2h).)endc subroutine optdrvcc purposecc driver for non-linear optimization problemcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> on entry: estimate to a root of fcnc fcn --> name of subroutine to evaluate optimization functionc must be declared external in calling routinec fcn: r(n) --> r(1)c d1fcn --> (optional) name of subroutine to evaluate gradientc of fcn. must be declared external in calling routinec d2fcn --> (optional) name of subroutine to evaluate hessian ofc of fcn. must be declared external in calling routinec typsiz(n) --> typical size for each component of xc fscale --> estimate of scale of objective functionc method --> algorithm to use to solve minimization problemc =1 line searchc =2 double doglegc =3 more-hebdonc iexp --> =1 if optimization function fcn is expensive toc evaluate, =0 otherwise. if set then hessian willc be evaluated by secant update instead ofc analytically or by finite differencesc msg <--> on input: (.gt.0) message to inhibit certainc automatic checksc on output: (.lt.0) error code; =0 no errorc ndigit --> number of good digits in optimization function fcnc itnlim --> maximum number of allowable iterationsc iagflg --> =1 if analytic gradient suppliedc iahflg --> =1 if analytic hessian suppliedc ipr --> device to which to send outputc dlt --> trust region radiusc gradtl --> tolerance at which gradient considered closec enough to zero to terminate algorithmc stepmx --> maximum allowable step sizec steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc xpls(n) <--> on exit: xpls is local minimumc fpls <--> on exit: function value at solution, xplsc gpls(n) <--> on exit: gradient at solution xplsc itrmcd <-- termination codec a(n,n) --> workspace for hessian (or estimate)c and its cholesky decompositionc udiag(n) --> workspace [for diagonal of hessian]c g(n) --> workspace (for gradient at current iterate)c p(n) --> workspace for stepc sx(n) --> workspace (for diagonal scaling matrix)c wrk0(n) --> workspacec wrk1(n) --> workspacec wrk2(n) --> workspacec wrk3(n) --> workspacec itncnt current iteration, k {{was `internal'}}ccc internal variablescc analtl tolerance for comparison of estimated andc analytical gradients and hessiansc epsm machine epsilonc f function value: fcn(x)c rnf relative noise in optimization function fcn.c noise=10.**(-ndigit)ccstaticsubroutine optdrv(nr,n,x,fcn,d1fcn,d2fcn,typsiz,fscale,+ method,iexp,msg,ndigit,itnlim,iagflg,iahflg,ipr,+ dlt,gradtl,stepmx,steptl,+ xpls,fpls,gpls,itrmcd,+ a,udiag,g,p,sx,wrk0,wrk1,wrk2,wrk3,itncnt)implicit double precision (a-h,o-z)dimension x(n),xpls(n),g(n),gpls(n),p(n)dimension typsiz(n),sx(n)dimension a(nr,*),udiag(n)dimension wrk0(n),wrk1(n),wrk2(n),wrk3(n)logical mxtake,noupdtinteger itncntexternal fcn,d1fcn,d2fcnexternal resultc for iteration tracing [defined in ../main/optimize.c]cc initializationcdo 10 i=1,np(i)=0.0d010 continueitncnt=0iretcd=-1epsm=d1mach(4)call optchk(n,x,typsiz,sx,fscale,gradtl,itnlim,ndigit,epsm,+ dlt,method,iexp,iagflg,iahflg,stepmx,msg,ipr)if(msg.lt.0) returnrnf=max(10.0d0**(-ndigit),epsm)analtl=max(1.0d-2,sqrt(rnf))cc% if(mod(msg/8,2).eq.1) go to 15c% write(ipr,901)c% write(ipr,900) (typsiz(i),i=1,n)c% write(ipr,902)c% write(ipr,900) (sx(i),i=1,n)c% write(ipr,903) fscalec% write(ipr,904) ndigit,iagflg,iahflg,iexp,method,itnlim,epsmc% write(ipr,905) stepmx,steptl,gradtl,dlt,rnf,analtlc% 15 continuecc evaluate fcn(x)ccall fcn(n,x,f)cc evaluate analytic or finite difference gradient and check analyticc gradient, if requested.cif (iagflg .eq. 1) go to 20c if (iagflg .eq. 0)c thencall fstofd (1, 1, n, x, fcn, f, g, sx, rnf, wrk, 1)go to 25c20 call d1fcn (n, x, g)if (mod(msg/2,2) .eq. 1) go to 25c if (mod(msg/2,2).eq.0)c thencall grdchk (n, x, fcn, f, g, typsiz, sx, fscale,1 rnf, analtl, wrk1, msg, ipr)if (msg .lt. 0) return25 continueccall optstp(n,x,f,g,wrk1,itncnt,icscmx,+ itrmcd,gradtl,steptl,sx,fscale,itnlim,iretcd,mxtake,+ ipr,msg)if(itrmcd.ne.0) go to 700cif(iexp.ne.1) go to 80cc if optimization function expensive to evaluate (iexp=1), thenc hessian will be obtained by secant updates. get initial hessian.ccall hsnint(nr,n,a,sx,method)go to 9080 continuecc evaluate analytic or finite difference hessian and check analyticc hessian if requested (only if user-supplied analytic hessianc routine d2fcn fills only lower triangular part and diagonal of a).cif (iahflg .eq. 1) go to 82c if (iahflg .eq. 0)c thenif (iagflg .eq. 1) call fstofd (nr, n, n, x, d1fcn, g, a, sx,1 rnf, wrk1, 3)if (iagflg .ne. 1) call sndofd (nr, n, x, fcn, f, a, sx, rnf,1 wrk1, wrk2)go to 88cc else82 if (mod(msg/4,2).eq.0) go to 85c if (mod(msg/4, 2) .eq. 1)c thencall d2fcn (nr, n, x, a)go to 88cc else85 call heschk (nr, n, x, fcn, d1fcn, d2fcn, f, g, a, typsiz,1 sx, rnf, analtl, iagflg, udiag, wrk1, wrk2, msg, ipr)cc heschk evaluates d2fcn and checks it against the finitec difference hessian which it calculates by calling fstofdc (if iagflg .eq. 1) or sndofd (otherwise).cif (msg .lt. 0) return88 continuec90 if(mod(msg/8,2).eq.0)+ call result(nr,n,x,f,g,a,p,itncnt,1,ipr)ccc iterationc100 itncnt=itncnt+1cc find perturbed local model hessian and its ll+ decompositionc (skip this step if line search or dogstep techniques being used withc secant updates. cholesky decomposition l already obtained fromc secfac.)cif(iexp.eq.1 .and. method.ne.3) go to 105103 call chlhsn(nr,n,a,epsm,sx,udiag)105 continuecc solve for newton step: ap=-gcdo 110 i=1,nwrk1(i)=-g(i)110 continuecall lltslv(nr,n,a,p,wrk1)cc decide whether to accept newton step xpls=x + pc or to choose xpls by a global strategy.cif (iagflg .ne. 0 .or. method .eq. 1) go to 111dltsav = dltif (method .eq. 2) go to 111amusav = amudlpsav = dltpphisav = phiphpsav = phip0111 if(method.eq.1)+ call lnsrch(n,x,f,g,p,xpls,fpls,fcn,mxtake,iretcd,+ stepmx,steptl,sx,ipr)if(method.eq.2)+ call dogdrv(nr,n,x,f,g,a,p,xpls,fpls,fcn,sx,stepmx,+ steptl,dlt,iretcd,mxtake,wrk0,wrk1,wrk2,wrk3,ipr,itncnt)if(method.eq.3)+ call hookdr(nr,n,x,f,g,a,udiag,p,xpls,fpls,fcn,sx,stepmx,+ steptl,dlt,iretcd,mxtake,amu,dltp,phi,phip0,wrk0,+ wrk1,wrk2,epsm,itncnt,ipr)cc if could not find satisfactory step and forward differencec gradient was used, retry using central difference gradient.cif (iretcd .ne. 1 .or. iagflg .ne. 0) go to 112c if (iretcd .eq. 1 .and. iagflg .eq. 0)c thencc set iagflg for central differencesciagflg = -1c% write(ipr,906) itncntccall fstocd (n, x, fcn, sx, rnf, g)if (method .eq. 1) go to 105dlt = dltsavif (method .eq. 2) go to 105amu = amusavdltp = dlpsavphi = phisavphip0 = phpsavgo to 103c endifcc calculate step for outputc112 continuedo 114 i = 1, np(i) = xpls(i) - x(i)114 continuecc calculate gradient at xplscif (iagflg .eq. (-1)) go to 116if (iagflg .eq. 0) go to 118cc analytic gradientcall d1fcn (n, xpls, gpls)go to 120cc central difference gradient116 call fstocd (n, xpls, fcn, sx, rnf, gpls)go to 120cc forward difference gradient118 call fstofd (1, 1, n, xpls, fcn, fpls, gpls, sx, rnf, wrk, 1)120 continuecc check whether stopping criteria satisfiedccall optstp(n,xpls,fpls,gpls,x,itncnt,icscmx,+ itrmcd,gradtl,steptl,sx,fscale,itnlim,iretcd,mxtake,+ ipr,msg)if(itrmcd.ne.0) go to 690cc evaluate hessian at xplscif(iexp.eq.0) go to 130if(method.eq.3)+ call secunf(nr,n,x,g,a,udiag,xpls,gpls,epsm,itncnt,rnf,+ iagflg,noupdt,wrk1,wrk2,wrk3)if(method.ne.3)+ call secfac(nr,n,x,g,a,xpls,gpls,epsm,itncnt,rnf,iagflg,+ noupdt,wrk0,wrk1,wrk2,wrk3)go to 150130 if(iahflg.eq.1) go to 140if(iagflg.eq.1)+ call fstofd(nr,n,n,xpls,d1fcn,gpls,a,sx,rnf,wrk1,3)if(iagflg.ne.1) call sndofd(nr,n,xpls,fcn,fpls,a,sx,rnf,wrk1,wrk2)go to 150140 call d2fcn(nr,n,xpls,a)150 continueif(mod(msg/16,2).eq.1)+ call result(nr,n,xpls,fpls,gpls,a,p,itncnt,1,ipr)cc x <-- xpls and g <-- gpls and f <-- fplscf=fplsdo 160 i=1,nx(i)=xpls(i)g(i)=gpls(i)160 continuego to 100cc terminationcc reset xpls,fpls,gpls, if previous iterate solutionc690 if(itrmcd.ne.3) go to 710700 continuefpls=fdo 705 i=1,nxpls(i)=x(i)gpls(i)=g(i)705 continuecc print resultsc710 continueif(mod(msg/8,2).eq.0)+ call result(nr,n,xpls,fpls,gpls,a,p,itncnt,0,ipr)msg=0returncc%900 format(14h optdrv ,5(e20.13,3x))c%901 format(20h0optdrv typical x)c%902 format(40h optdrv diagonal scaling matrix for x)c%903 format(22h optdrv typical f =,e20.13)c%904 format(40h0optdrv number of good digits in fcn=,i5/c% + 27h optdrv gradient flag =,i5,18h (=1 if analytic,c% + 19h gradient supplied)/c% + 27h optdrv hessian flag =,i5,18h (=1 if analytic,c% + 18h hessian supplied)/c% + 27h optdrv expense flag =,i5, 9h (=1 if,c% + 45h minimization function expensive to evaluate)/c% + 27h optdrv method to use =,i5,19h (=1,2,3 for line,c% + 49h search, double dogleg, more-hebdon respectively)/c% + 27h optdrv iteration limit=,i5/c% + 27h optdrv machine epsilon=,e20.13)c%905 format(30h0optdrv maximum step size =,e20.13/c% + 30h optdrv step tolerance =,e20.13/c% + 30h optdrv gradient tolerance=,e20.13/c% + 30h optdrv trust reg radius =,e20.13/c% + 30h optdrv rel noise in fcn =,e20.13/c% + 30h optdrv anal-fd tolerance =,e20.13)c%906 format(52h optdrv shift from forward to central differences,c% 1 14h in iteration , i5)endc subroutine optif0cc purposecc provide simplest interface to minimization package.c user has no control over options.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> initial estimate of minimumc fcn --> name of routine to evaluate minimization function.c must be declared external in calling routine.c xpls(n) <-- local minimumc fpls <-- function value at local minimum xplsc gpls(n) <-- gradient at local minimum xplsc itrmcd <-- termination codec a(n,n) --> workspacec wrk(n,9) --> workspacecsubroutine optif0(nr,n,x,fcn,xpls,fpls,gpls,itrmcd,a,wrk)implicit double precision (a-h,o-z)dimension x(n),xpls(n),gpls(n)dimension a(nr,*),wrk(nr,9)external fcn,d1fcn,d2fcninteger itncntcc equivalence wrk(n,1) = udiag(n)c wrk(n,2) = g(n)c wrk(n,3) = p(n)c wrk(n,4) = typsiz(n)c wrk(n,5) = sx(n)c wrk(n,6) = wrk0(n)c wrk(n,7) = wrk1(n)c wrk(n,8) = wrk2(n)c wrk(n,9) = wrk3(n)ccall dfault(n,x,wrk(1,4),fscale,method,iexp,msg,ndigit,+ itnlim,iagflg,iahflg,ipr,dlt,gradtl,stepmx,steptl)call optdrv(nr,n,x,fcn,d1fcn,d2fcn,wrk(1,4),fscale,+ method,iexp,msg,ndigit,itnlim,iagflg,iahflg,ipr,+ dlt,gradtl,stepmx,steptl,+ xpls,fpls,gpls,itrmcd,+ a,wrk(1,1),wrk(1,2),wrk(1,3),wrk(1,5),wrk(1,6),+ wrk(1,7),wrk(1,8),wrk(1,9),itncnt)returnendC---- this one is called from ../main/optimize.c : ---------------c subroutine optif9cc purposecc provide complete interface to minimization package.c user has full control over options.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> on entry: estimate to a root of fcnc fcn --> name of subroutine to evaluate optimization functionc must be declared external in calling routinec fcn: r(n) --> r(1)c d1fcn --> (optional) name of subroutine to evaluate gradientc of fcn. must be declared external in calling routinec d2fcn --> (optional) name of subroutine to evaluate hessian ofc of fcn. must be declared external in calling routinec typsiz(n) --> typical size for each component of xc fscale --> estimate of scale of objective functionc method --> algorithm to use to solve minimization problemc =1 line searchc =2 double doglegc =3 more-hebdonc iexp --> =1 if optimization function fcn is expensive toc evaluate, =0 otherwise. if set then hessian willc be evaluated by secant update instead ofc analytically or by finite differencesc msg <--> on input: (.gt.0) message to inhibit certainc automatic checksc on output: (.lt.0) error code; =0 no errorc ndigit --> number of good digits in optimization function fcnc itnlim --> maximum number of allowable iterationsc iagflg --> =1 if analytic gradient suppliedc iahflg --> =1 if analytic hessian suppliedc ipr --> device to which to send outputc dlt --> trust region radiusc gradtl --> tolerance at which gradient considered closec enough to zero to terminate algorithmc stepmx --> maximum allowable step sizec steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc xpls(n) <--> on exit: xpls is local minimumc fpls <--> on exit: function value at solution, xplsc gpls(n) <--> on exit: gradient at solution xplsc itrmcd <-- termination codec a(n,n) --> workspace for hessian (or estimate)c and its cholesky decompositionc wrk(n,8) --> workspacec itncnt --> iteration countcsubroutine optif9(nr,n,x,fcn,d1fcn,d2fcn,typsiz,fscale,+ method,iexp,msg,ndigit,itnlim,iagflg,iahflg,ipr,+ dlt,gradtl,stepmx,steptl,+ xpls,fpls,gpls,itrmcd,a,wrk, itncnt)implicit double precision (a-h,o-z)dimension x(n),xpls(n),gpls(n),typsiz(n)dimension a(nr,*),wrk(nr,8)external fcn,d1fcn,d2fcninteger itncntcc equivalence wrk(n,1) = udiag(n)c wrk(n,2) = g(n)c wrk(n,3) = p(n)c wrk(n,4) = sx(n)c wrk(n,5) = wrk0(n)c wrk(n,6) = wrk1(n)c wrk(n,7) = wrk2(n)c wrk(n,8) = wrk3(n)ccall optdrv(nr,n,x,fcn,d1fcn,d2fcn,typsiz,fscale,+ method,iexp,msg,ndigit,itnlim,iagflg,iahflg,ipr,+ dlt,gradtl,stepmx,steptl,+ xpls,fpls,gpls,itrmcd,+ a,wrk(1,1),wrk(1,2),wrk(1,3),wrk(1,4),wrk(1,5),+ wrk(1,6),wrk(1,7),wrk(1,8),itncnt)returnendc subroutine optstpcc unconstrained minimization stopping criteriacc find whether the algorithm should terminate, due to anyc of the following:c 1) problem solved within user tolerancec 2) convergence within user tolerancec 3) iteration limit reachedc 4) divergence or too restrictive maximum step (stepmx) suspectedcc parameterscc n --> dimension of problemc xpls(n) --> new iterate x[k]c fpls --> function value at new iterate f(xpls)c gpls(n) --> gradient at new iterate, g(xpls), or approximatec x(n) --> old iterate x[k-1]c itncnt --> current iteration kc icscmx <--> number consecutive steps .ge. stepmxc [retain value between successive calls]c itrmcd <-- termination codec gradtl --> tolerance at which relative gradient considered closec enough to zero to terminate algorithmc steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc sx(n) --> diagonal scaling matrix for xc fscale --> estimate of scale of objective functionc itnlim --> maximum number of allowable iterationsc iretcd --> return codec mxtake --> boolean flag indicating step of maximum length usedc ipr --> device to which to send outputc msg --> if msg includes a term 8, suppress outputcccstaticsubroutine optstp(n,xpls,fpls,gpls,x,itncnt,icscmx,+ itrmcd,gradtl,steptl,sx,fscale,itnlim,iretcd,mxtake,ipr,msg)implicit double precision (a-h,o-z)integer n,itncnt,icscmx,itrmcd,itnlimdimension sx(n)dimension xpls(n),gpls(n),x(n)logical mxtakecitrmcd=0cc last global step failed to locate a point lower than xcif(iretcd.ne.1) go to 50c if(iretcd.eq.1)c thenjtrmcd=3go to 600c endif50 continuecc find direction in which relative gradient maximum.c check whether within tolerancecd=max(abs(fpls),fscale)rgx=0.0d0do 100 i=1,nrelgrd=abs(gpls(i))*max(abs(xpls(i)),1.0d0/sx(i))/drgx=max(rgx,relgrd)100 continuejtrmcd=1if(rgx.le.gradtl) go to 600cif(itncnt.eq.0) returncc find direction in which relative stepsize maximumc check whether within tolerance.crsx=0.0d0do 120 i=1,nrelstp=abs(xpls(i)-x(i))/max(abs(xpls(i)),1.0d0/sx(i))rsx=max(rsx,relstp)120 continuejtrmcd=2if(rsx.le.steptl) go to 600cc check iteration limitcjtrmcd=4if(itncnt.ge.itnlim) go to 600cc check number of consecutive steps \ stepmxcif(mxtake) go to 140c if(.not.mxtake)c thenicscmx=0returnc else140 continuec% if (mod(msg/8,2) .eq. 0) write(ipr,900)icscmx=icscmx+1if(icscmx.lt.5) returnjtrmcd=5c endifccc print termination codec600 itrmcd=jtrmcdc% if (mod(msg/8,2) .eq. 0) go to(601,602,603,604,605), itrmcdc% go to 700c%601 write(ipr,901)c% go to 700c%602 write(ipr,902)c% go to 700c%603 write(ipr,903)c% go to 700c%604 write(ipr,904)c% go to 700c%605 write(ipr,905)c700 returncc%900 format(48h0optstp step of maximum length (stepmx) taken)c%901 format(43h0optstp relative gradient close to zero./c% + 48h optstp current iterate is probably solution.)c%902 format(48h0optstp successive iterates within tolerance./c% + 48h optstp current iterate is probably solution.)c%903 format(52h0optstp last global step failed to locate a point,c% + 14h lower than x./c% + 51h optstp either x is an approximate local minimum,c% + 17h of the function,/c% + 50h optstp the function is too non-linear for this,c% + 11h algorithm,/c% + 34h optstp or steptl is too large.)c%904 format(36h0optstp iteration limit exceeded./c% + 28h optstp algorithm failed.)c%905 format(39h0optstp maximum step size exceeded 5,c% + 19h consecutive times./c% + 50h optstp either the function is unbounded below,/c% + 47h optstp becomes asymptotic to a finite value,c% + 30h from above in some direction,/c% + 33h optstp or stepmx is too small)endc subroutine qraux1cc purposecc interchange rows i,i+1 of the upper hessenberg matrix r,c columns i to ncc parameterscc nr --> row dimension of matrixc n --> dimension of matrixc r(n,n) <--> upper hessenberg matrixc i --> index of row to interchange (i.lt.n)ccstaticsubroutine qraux1(nr,n,r,i)implicit double precision (a-h,o-z)dimension r(nr,*)do 10 j=i,ntmp=r(i,j)r(i,j)=r(i+1,j)r(i+1,j)=tmp10 continuereturnendc subroutine qraux2cc purposecc pre-multiply r by the jacobi rotation j(i,i+1,a,b)cc parameterscc nr --> row dimension of matrixc n --> dimension of matrixc r(n,n) <--> upper hessenberg matrixc i --> index of rowc a --> scalarc b --> scalarccstaticsubroutine qraux2(nr,n,r,i,a,b)implicit double precision (a-h,o-z)dimension r(nr,*)den=sqrt(a*a + b*b)c=a/dens=b/dendo 10 j=i,ny=r(i,j)z=r(i+1,j)r(i,j)=c*y - s*zr(i+1,j)=s*y + c*z10 continuereturnendc subroutine qrupdtcc purposecc find an orthogonal (n*n) matrix (q*) and an upper triangular (n*n)c matrix (r*) such that (q*)(r*)=r+u(v+)cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc a(n,n) <--> on input: contains rc on output: contains (r*)c u(n) --> vectorc v(n) --> vectorccstaticsubroutine qrupdt(nr,n,a,u,v)implicit double precision (a-h,o-z)dimension a(nr,*)dimension u(n),v(n)cc determine last non-zero in u(.)ck=n10 if(u(k).ne.0.0d0 .or. k.eq.1) go to 20c if(u(k).eq.0.0d0 .and. k.gt.1)c thenk=k-1go to 10c endifcc (k-1) jacobi rotations transformc r + u(v+) --> (r*) + (u(1)*e1)(v+)c which is upper hessenbergc20 if(k.le.1) go to 40km1=k-1do 30 ii=1,km1i=km1-ii+1if(u(i).ne.0.0d0) go to 25c if(u(i).eq.0.0d0)c thencall qraux1(nr,n,a,i)u(i)=u(i+1)go to 30c else25 call qraux2(nr,n,a,i,u(i),-u(i+1))u(i)=sqrt(u(i)*u(i) + u(i+1)*u(i+1))c endif30 continuec endifcc r <-- r + (u(1)*e1)(v+)c40 do 50 j=1,na(1,j)=a(1,j) +u(1)*v(j)50 continuecc (k-1) jacobi rotations transform upper hessenberg rc to upper triangular (r*)cif(k.le.1) go to 100km1=k-1do 80 i=1,km1if(a(i,i).ne.0.0d0) go to 70c if(a(i,i).eq.0.0d0)c thencall qraux1(nr,n,a,i)go to 80c else70 t1=a(i,i)t2=-a(i+1,i)call qraux2(nr,n,a,i,t1,t2)c endif80 continuec endif100 returnendc subroutine sclmulcc purposecc multiply vector by scalarc result vector may be operand vectorcc parameterscc n --> dimension of vectorsc s --> scalarc v(n) --> operand vectorc z(n) <-- result vectorcstaticsubroutine sclmul(n,s,v,z)implicit double precision (a-h,o-z)dimension v(n),z(n)do 100 i=1,nz(i)=s*v(i)100 continuereturnendc subroutine secfaccc purposecc update hessian by the bfgs factored methodcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> old iterate, x[k-1]c g(n) --> gradient or approximate at old iteratec a(n,n) <--> on entry: cholesky decomposition of hessian inc lower part and diagonal.c on exit: updated cholesky decomposition of hessianc in lower triangular part and diagonalc xpls(n) --> new iterate, x[k]c gpls(n) --> gradient or approximate at new iteratec epsm --> machine epsilonc itncnt --> iteration countc rnf --> relative noise in optimization function fcnc iagflg --> =1 if analytic gradient supplied, =0 itherwisec noupdt <--> boolean: no update yetc [retain value between successive calls]c s(n) --> workspacec y(n) --> workspacec u(n) --> workspacec w(n) --> workspaceccstaticsubroutine secfac(nr,n,x,g,a,xpls,gpls,epsm,itncnt,rnf,+ iagflg,noupdt,s,y,u,w)implicit double precision (a-h,o-z)dimension x(n),xpls(n),g(n),gpls(n)dimension a(nr,*)dimension s(n),y(n),u(n),w(n)logical noupdt,skpupdcif(itncnt.eq.1) noupdt=.true.do 10 i=1,ns(i)=xpls(i)-x(i)y(i)=gpls(i)-g(i)10 continueden1=ddot(n,s,1,y,1)snorm2=dnrm2(n,s,1)ynrm2=dnrm2(n,y,1)if(den1.lt.sqrt(epsm)*snorm2*ynrm2) go to 110c if(den1.ge.sqrt(epsm)*snorm2*ynrm2)c thencall mvmltu(nr,n,a,s,u)den2=ddot(n,u,1,u,1)cc l <-- sqrt(den1/den2)*lcalp=sqrt(den1/den2)if(.not.noupdt) go to 50c if(noupdt)c thendo 30 j=1,nu(j)=alp*u(j)do 20 i=j,na(i,j)=alp*a(i,j)20 continue30 continuenoupdt=.false.den2=den1alp=1.0d0c endif50 skpupd=.true.cc w = l(l+)s = hsccall mvmltl(nr,n,a,u,w)i=1if(iagflg.ne.0) go to 55c if(iagflg.eq.0)c thenreltol=sqrt(rnf)go to 60c else55 reltol=rnfc endif60 if(i.gt.n .or. .not.skpupd) go to 70c if(i.le.n .and. skpupd)c thenif(abs(y(i)-w(i)) .lt. reltol*max(abs(g(i)),abs(gpls(i))))+ go to 65c if(abs(y(i)-w(i)) .ge. reltol*dmax1(abs(g(i)),abs(gpls(i))))c thenskpupd=.false.go to 60c else65 i=i+1go to 60c endifc endif70 if(skpupd) go to 110c if(.not.skpupd)c thencc w=y-alp*l(l+)scdo 75 i=1,nw(i)=y(i)-alp*w(i)75 continuecc alp=1/sqrt(den1*den2)calp=alp/den1cc u=(l+)/sqrt(den1*den2) = (l+)s/sqrt((y+)s * (s+)l(l+)s)cdo 80 i=1,nu(i)=alp*u(i)80 continuecc copy l into upper triangular part. zero l.cif(n.eq.1) go to 93do 90 i=2,nim1=i-1do 85 j=1,im1a(j,i)=a(i,j)a(i,j)=0.0d085 continue90 continuecc find q, (l+) such that q(l+) = (l+) + u(w+)c93 call qrupdt(nr,n,a,u,w)cc upper triangular part and diagonal of a now contain updatedc cholesky decomposition of hessian. copy back to lowerc triangular part.cif(n.eq.1) go to 110do 100 i=2,nim1=i-1do 95 j=1,im1a(i,j)=a(j,i)95 continue100 continuec endifc endif110 returnendc subroutine secunfcc purposecc update hessian by the bfgs unfactored methodcc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> old iterate, x[k-1]c g(n) --> gradient or approximate at old iteratec a(n,n) <--> on entry: approximate hessian at old iteratec in upper triangular part (and udiag)c on exit: updated approx hessian at new iteratec in lower triangular part and diagonalc [lower triangular part of symmetric matrix]c udiag --> on entry: diagonal of hessianc xpls(n) --> new iterate, x[k]c gpls(n) --> gradient or approximate at new iteratec epsm --> machine epsilonc itncnt --> iteration countc rnf --> relative noise in optimization function fcnc iagflg --> =1 if analytic gradient supplied, =0 otherwisec noupdt <--> boolean: no update yetc [retain value between successive calls]c s(n) --> workspacec y(n) --> workspacec t(n) --> workspaceccstaticsubroutine secunf(nr,n,x,g,a,udiag,xpls,gpls,epsm,itncnt,+ rnf,iagflg,noupdt,s,y,t)implicit double precision (a-h,o-z)dimension x(n),g(n),xpls(n),gpls(n)dimension a(nr,*)dimension udiag(n)dimension s(n),y(n),t(n)logical noupdt,skpupdcc copy hessian in upper triangular part and udiag toc lower triangular part and diagonalcdo 5 j=1,na(j,j)=udiag(j)if(j.eq.n) go to 5jp1=j+1do 4 i=jp1,na(i,j)=a(j,i)4 continue5 continuecif(itncnt.eq.1) noupdt=.true.do 10 i=1,ns(i)=xpls(i)-x(i)y(i)=gpls(i)-g(i)10 continueden1=ddot(n,s,1,y,1)snorm2=dnrm2(n,s,1)ynrm2=dnrm2(n,y,1)if(den1.lt.sqrt(epsm)*snorm2*ynrm2) go to 100c if(den1.ge.sqrt(epsm)*snorm2*ynrm2)c thencall mvmlts(nr,n,a,s,t)den2=ddot(n,s,1,t,1)if(.not. noupdt) go to 50c if(noupdt)c thencc h <-- [(s+)y/(s+)hs]hcgam=den1/den2den2=gam*den2do 30 j=1,nt(j)=gam*t(j)do 20 i=j,na(i,j)=gam*a(i,j)20 continue30 continuenoupdt=.false.c endif50 skpupd=.true.cc check update condition on row icdo 60 i=1,ntol=rnf*max(abs(g(i)),abs(gpls(i)))if(iagflg.eq.0) tol=tol/sqrt(rnf)if(abs(y(i)-t(i)).lt.tol) go to 60c if(abs(y(i)-t(i)).ge.tol)c thenskpupd=.false.go to 70c endif60 continue70 if(skpupd) go to 100c if(.not.skpupd)c thencc bfgs updatecdo 90 j=1,ndo 80 i=j,na(i,j)=a(i,j)+y(i)*y(j)/den1-t(i)*t(j)/den280 continue90 continuec endifc endif100 returnendc subroutine sndofdcc purposecc find second order forward finite difference approximation "a"c to the second derivative (hessian) of the function defined by the subpc "fcn" evaluated at the new iterate "xpls"cc for optimization use this routine to estimatec 1) the second derivative (hessian) of the optimization functionc if no analytical user function has been supplied for eitherc the gradient or the hessian and if the optimization functionc "fcn" is inexpensive to evaluate.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc xpls(n) --> new iterate: x[k]c fcn --> name of subroutine to evaluate functionc fpls --> function value at new iterate, f(xpls)c a(n,n) <-- finite difference approximation to hessianc only lower triangular matrix and diagonalc are returnedc sx(n) --> diagonal scaling matrix for xc rnoise --> relative noise in fname [f(x)]c stepsz(n) --> workspace (stepsize in i-th component direction)c anbr(n) --> workspace (neighbor in i-th direction)cccstaticsubroutine sndofd(nr,n,xpls,fcn,fpls,a,sx,rnoise,stepsz,anbr)implicit double precision (a-h,o-z)dimension xpls(n)dimension sx(n)dimension stepsz(n),anbr(n)dimension a(nr,*)cc find i-th stepsize and evaluate neighbor in directionc of i-th unit vector.cov3 = 1.0d0/3.0d0do 10 i=1,nstepsz(i)=rnoise**ov3 * max(abs(xpls(i)),1.0d0/sx(i))xtmpi=xpls(i)xpls(i)=xtmpi+stepsz(i)call fcn(n,xpls,anbr(i))xpls(i)=xtmpi10 continuecc calculate column i of acdo 30 i=1,nxtmpi=xpls(i)xpls(i)=xtmpi+2.0d0*stepsz(i)call fcn(n,xpls,fhat)a(i,i)=((fpls-anbr(i))+(fhat-anbr(i)))/(stepsz(i)*stepsz(i))cc calculate sub-diagonal elements of columnif(i.eq.n) go to 25xpls(i)=xtmpi+stepsz(i)ip1=i+1do 20 j=ip1,nxtmpj=xpls(j)xpls(j)=xtmpj+stepsz(j)call fcn(n,xpls,fhat)a(j,i)=((fpls-anbr(i))+(fhat-anbr(j)))/(stepsz(i)*stepsz(j))xpls(j)=xtmpj20 continue25 xpls(i)=xtmpi30 continuereturnendc subroutine tregupcc purposecc decide whether to accept xpls=x+sc as the next iterate and update thec trust region dlt.cc parameterscc nr --> row dimension of matrixc n --> dimension of problemc x(n) --> old iterate x[k-1]c f --> function value at old iterate, f(x)c g(n) --> gradient at old iterate, g(x), or approximatec a(n,n) --> cholesky decomposition of hessian inc lower triangular part and diagonal.c hessian or approx in upper triangular partc fcn --> name of subroutine to evaluate functionc sc(n) --> current stepc sx(n) --> diagonal scaling matrix for xc nwtake --> boolean, =.true. if newton step takenc stepmx --> maximum allowable step sizec steptl --> relative step size at which successive iteratesc considered close enough to terminate algorithmc dlt <--> trust region radiusc iretcd <--> return codec =0 xpls accepted as next iterate;c dlt trust region for next iteration.c =1 xpls unsatisfactory but accepted as next iteratec because xpls-x .lt. smallest allowablec step length.c =2 f(xpls) too large. continue current iterationc with new reduced dlt.c =3 f(xpls) sufficiently small, but quadratic modelc predicts f(xpls) sufficiently well to continuec current iteration with new doubled dlt.c xplsp(n) <--> workspace [value needs to be retained betweenc succesive calls of k-th global step]c fplsp <--> [retain value between successive calls]c xpls(n) <-- new iterate x[k]c fpls <-- function value at new iterate, f(xpls)c mxtake <-- boolean flag indicating step of maximum length usedc ipr --> device to which to send outputc method --> algorithm to use to solve minimization problemc =1 line searchc =2 double doglegc =3 more-hebdonc udiag(n) --> diagonal of hessian in a(.,.)ccstaticsubroutine tregup(nr,n,x,f,g,a,fcn,sc,sx,nwtake,stepmx,steptl,+ dlt,iretcd,xplsp,fplsp,xpls,fpls,mxtake,ipr,method,udiag)implicit double precision (a-h,o-z)dimension x(n),xpls(n),g(n)dimension sx(n),sc(n),xplsp(n)dimension a(nr,*)logical nwtake,mxtakedimension udiag(n)cipr=iprmxtake=.false.do 100 i=1,nxpls(i)=x(i)+sc(i)100 continuecall fcn(n,xpls,fpls)dltf=fpls-fslp=ddot(n,g,1,sc,1)cc next statement added for case of compilers which do not optimizec evaluation of next "if" statement (in which case fplsp could bec undefined).cif(iretcd.eq.4) fplsp=0.0d0c$ write(ipr,961) iretcd,fpls,fplsp,dltf,slpif(iretcd.ne.3 .or. (fpls.lt.fplsp .and. dltf.le. 1.d-4*slp))+ go to 130c if(iretcd.eq.3 .and. (fpls.ge.fplsp .or. dltf.gt. 1.d-4*slp))c thencc reset xpls to xplsp and terminate global stepciretcd=0do 110 i=1,nxpls(i)=xplsp(i)110 continuefpls=fplspdlt=.5*dltc$ write(ipr,951)go to 230c elsecc fpls too largec130 if(dltf.le. 1.d-4*slp) go to 170c if(dltf.gt. 1.d-4*slp)c thenc$ write(ipr,952)rln=0.0d0do 140 i=1,nrln=max(rln,abs(sc(i))/max(abs(xpls(i)),1.0d0/sx(i)))140 continuec$ write(ipr,962) rlnif(rln.ge.steptl) go to 150c if(rln.lt.steptl)c thencc cannot find satisfactory xpls sufficiently distinct from xciretcd=1c$ write(ipr,954)go to 230c elsecc reduce trust region and continue global stepc150 iretcd=2dltmp=-slp*dlt/(2.0d0*(dltf-slp))c$ write(ipr,963) dltmpif(dltmp.ge. .1*dlt) go to 155c if(dltmp.lt. .1*dlt)c thendlt=.1*dltgo to 160c else155 dlt=dltmpc endif160 continuec$ write(ipr,955)go to 230c endifc elsecc fpls sufficiently smallc170 continuec$ write(ipr,958)dltfp=0.0d0if (method .eq. 3) go to 180cc if (method .eq. 2)c thencdo 177 i = 1, ntemp = 0.0d0do 173 j = i, ntemp = temp + (a(j, i)*sc(j))173 continuedltfp = dltfp + temp*temp177 continuego to 190cc elsec180 do 187 i = 1, ndltfp = dltfp + udiag(i)*sc(i)*sc(i)if (i .eq. n) go to 187temp = 0ip1 = i + 1do 183 j = ip1, ntemp = temp + a(i, j)*sc(i)*sc(j)183 continuedltfp = dltfp + 2.0d0*temp187 continuecc end ifc190 dltfp = slp + dltfp/2.0d0c$ write(ipr,964) dltfp,nwtakeif(iretcd.eq.2 .or. (abs(dltfp-dltf).gt. .1*abs(dltf))+ .or. nwtake .or. (dlt.gt. .99*stepmx)) go to 210c if(iretcd.ne.2 .and. (abs(dltfp-dltf) .le. .1*abs(dltf))c + .and. (.not.nwtake) .and. (dlt.le. .99*stepmx))c thencc double trust region and continue global stepciretcd=3do 200 i=1,nxplsp(i)=xpls(i)200 continuefplsp=fplsdlt=min(2.0d0*dlt,stepmx)c$ write(ipr,959)go to 230c elsecc accept xpls as next iterate. choose new trust region.c210 continuec$ write(ipr,960)iretcd=0if(dlt.gt. .99*stepmx) mxtake=.true.if(dltf.lt. .1*dltfp) go to 220c if(dltf.ge. .1*dltfp)c thencc decrease trust region for next iterationcdlt=.5*dltgo to 230c elsecc check whether to increase trust region for next iterationc220 if(dltf.le. .75*dltfp) dlt=min(2.0d0*dlt,stepmx)c endifc endifc endifc endif230 continuec$ write(ipr,953)c$ write(ipr,956) iretcd,mxtake,dlt,fplsc$ write(ipr,957)c$ write(ipr,965) (xpls(i),i=1,n)returncc%951 format(55h tregup reset xpls to xplsp. termination global step)c%952 format(26h tregup fpls too large.)c%953 format(38h0tregup values after call to tregup)c%954 format(54h tregup cannot find satisfactory xpls distinct from,c% + 27h x. terminate global step.)c%955 format(53h tregup reduce trust region. continue global step.)c%956 format(21h tregup iretcd=,i3/c% + 21h tregup mxtake=,l1/c% + 21h tregup dlt =,e20.13/c% + 21h tregup fpls =,e20.13)c%957 format(32h tregup new iterate (xpls))c%958 format(35h tregup fpls sufficiently small.)c%959 format(54h tregup double trust region. continue global step.)c%960 format(50h tregup accept xpls as new iterate. choose new,c% + 38h trust region. terminate global step.)c%961 format(18h tregup iretcd=,i5/c% + 18h tregup fpls =,e20.13/c% + 18h tregup fplsp =,e20.13/c% + 18h tregup dltf =,e20.13/c% + 18h tregup slp =,e20.13)c%962 format(18h tregup rln =,e20.13)c%963 format(18h tregup dltmp =,e20.13)c%964 format(18h tregup dltfp =,e20.13/c% + 18h tregup nwtake=,l1)c%965 format(14h tregup ,5(e20.13,3x))end