!Christen this file glcpd.f !ut here >>>>>>>>>>>>>>>>> ! Copyright (C) 2010 Roger Fletcher ! Current version dated 27 March 2013 ! THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC ! LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM ! CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT subroutine glcpd(n,m,k,kmax,maxg,a,la,x,bl,bu,f,fmin,g,r,w,e,ls, & alp,lp,mlp,peq,ws,lws,cws,v,nv,rgtol,m0de,ifail,mxgr,iprint,nout) implicit double precision (a-h,r-z), integer (i-q) ! This routine finds a KT point for the General LCP (Linearly Constrained ! Problem) ! minimize f(x) ! subject to l <= [I : A]t.x <= u (t = transpose) ! where f(x) is a given function of n variables x, to be determined. ! Lower and upper bound constraints on the variables x and the linear ! functions At.x may be supplied, where A is an n*m matrix. ! A recursive form of an active set method is used, using Wolfe's method to ! resolve degeneracy. A limited memory reduced gradient sweep method is used ! for minimization in the null space, so usually the KT point is a local ! minimizer. Matrix information is made available and processed by calls to ! external subroutines. Details of these are given in an auxiliary file ! named either 'denseL.f' or 'schurQR.f'. (schurQR.f is a more recent ! replacement for the file sparseL.f) ! parameter list (variables in a line starting with C must be set on entry) ! ************** ! n number of variables ! m number of general constraints (columns of A) ! k dimension of the null space obtained by eliminating the active ! constraints (only to be set if mode>=2). The number of constraints in ! the active set is n-k ! kmax maximum value of k (kmax <= n) ! maxg max number of reduced gradient vectors stored in sweep method: ! (1 < maxg <= kmax+1 when kmax>0), typically maxg = min(6,kmax+1) ! a(*) storage of reals associated with A. This storage may be provided ! in either dense or sparse format. Refer to either denseA.f or sparseA.f ! for information on how to set a(*) and la(*). The vector c referred to ! in these files should be set to the zero vector. ! la(*) storage of integers associated with c and A ! x(n) contains the vector of variables. Initially an estimate of the solution ! must be set, replaced by the solution (if it exists) on exit. ! bl(n+m) vector of lower bounds for variables and general constraints ! bu(n+m) vector of upper bounds (use numbers less than about 1.e30, and ! where possible supply realistic bounds on the x variables) ! f returns the value of f(x) when x is a feasible solution ! Otherwise f stores the sum of constraint infeasibilities ! fmin set a strict lower bound on f(x) (used to identify an unbounded LCP) ! g(n) returns the gradient vector of f(x) when x is feasible ! r(n+m) workspace: stores constraint residuals (or multipliers if the ! constraint is active). The sign convention is such that these are ! nonnegative at a solution (except multipliers of equality constraints) ! w(n+m) workspace: stores denominators for ratio tests ! e(n+m) stores steepest-edge normalization coefficients: if mode>2 then ! information in this vector from a previous call should not be changed. ! (In mode 3 these values provide approximate coefficients) ! ls(n+m) stores indices of the active constraints in locations 1:n and of ! the inactive constraints in locations n+1:n+m. The simple bounds ! on the variables are indexed by 1:n and the general constraints by ! n+1:n+m. The sign of ls(j) indicates whether the lower bound (+) or ! the upper bound (-) of constraint ls(j) is currently significant. ! Within the set of active constraints, locations 1:peq store the indices ! of any equality constraints, locations peq+1:n-k store the indices of ! any inequality constraints, and locations n-k+1:n store the indices of ! any free variables (variables not on a bound, which are used to ! parametrise the null space: ls(j) is always positive in this range) ! If mode>=2, the first n-k elements of ls must be set on entry ! alp(mlp) workspace associated with recursion ! lp(mlp) list of pointers to recursion information in ls ! mlp maximum number of levels of recursion allowed (mlp>2: typically ! mlp=50 would usually be adequate but mlp=m is an upper bound) ! peq pointer to the end of equality constraint indices in ls ! ws(*) real workspace for gdotx (see below), qlcpd and denseL.f (or schurQR.f) ! Set the total number in mxws (see "Common" below). ! lws(*) integer workspace for gdotx, qlcpd and denseL.f (or schurQR.f). ! Set the total number in mxlws (see "Common" below). ! The storage maps for ws and lws are set by the routine stmap below ! cws(*) character workspace (if any) needed by funct ! v(maxg) set nv estimates of the eigenvalues of the reduced Hessian of f(x) ! (for example from a previous run of glcpd). Set nv=1 and v(1)=1.D0 ! in absence of other information. New values of v are left on exit ! nv Number of estimates in v ! rgtol required accuracy in the reduced gradient l2 norm: it is advisable not ! to seek too high accuracy - rgtol may be increased by the code if it ! is deemed to be too small, see the definition of sgnf below ! m0de mode of operation (larger numbers imply extra information): ! 0 = cold start (no other information available, takes simple ! bounds for the initial active set) ! 1 = as 0 but includes all equality constraints in initial active set ! 2 = user sets n-k active constraint indices in ls(j), j=1,..,n-k. ! For a general constraint the sign of ls(j) indicates which ! bound to use. For a simple bound the current value of x is used ! 3 = takes active set and other information from a previous call. ! Steepest edge weights are approximated using previous values. ! 4 = as 3 but it is also assumed that columns of A are unchanged ! so that factors of the basis matrix stored in ws and lws are ! valid (changes in f(x) and the vectors l and u are allowed) ! A local copy (mode) of m0de is made and may be changed by glcpd ! ifail outcome of the process ! 0 = solution obtained ! 1 = unbounded problem (f(x)<fmin has occurred: note grad is not ! evaluated in this case) ! 2 = bl(i) > bu(i) for some i ! 3 = infeasible problem detected in Phase 1 ! 4 = line search cannot improve f (possibly increase rgtol) ! 5 = mxgr gradient calls exceeded (this test is only carried ! out at the start of each iteration) ! 6 = incorrect setting of m, n, kmax, maxg, mlp, m0de or tol ! 7 = not enough space in ws or lws ! 8 = not enough space in lp (increase mlp) ! 9 = dimension of reduced space too large (increase kmax) ! 10 = maximum number of unsuccessful restarts taken ! >10= possible use by later sparse matrix codes ! mxgr maximum number of gradient calls ! iprint switch for diagnostic printing (0 = off, 1 = summary, ! 2 = scalar information, 3 = verbose) ! nout channel number for output ! Storage Allocation ! ****************** ! User information about the lengths of ws and lws is supplied to glcpd in ! common/wsc/kk,ll,kkk,lll,mxws,mxlws ! kk and ll refer to the lengths of ws and lws needed by the user subroutines. ! kkk and lll are the numbers of locations used by glcpd and are set by glcpd. ! The rest of ws and lws is used by the files denseL.f or schurQR.f ! mxws and mxlws must be set to the total lengths of ws and lws available: a ! message will be given if more storage is needed. ! User subroutines ! **************** ! The user must provide two subroutines as follows ! subroutine funct(n,x,f,ws,lws,cws) ! implicit double precision (a-h,o-z) ! dimension x(*),ws(*),lws(*) ! character cws(*) ! ... ! statements to compute f(x) from x ! ... ! return ! end ! subroutine grad(n,x,g,ws,lws,cws) ! implicit double precision (a-h,o-z) ! dimension x(*),ws(*),lws(*) ! character cws(*) ! ... ! statements to compute grad.f(x) in g from x (the user ! may assume that a call of grad immediately follows one ! of funct with the same vector x.) ! ... ! return ! end ! The parameters ws, lws and cws in the above subroutines enables data to be ! passed from the user's calling program to these subroutines ! Tolerances, accuracy and diagnostics ! ************************************ ! glcpd uses tolerance and accuracy information stored in ! common/epsc/eps,tol,emin ! common/repc/sgnf,nrep,npiv,nres ! common/refactorc/mc,mxmc ! common/infoc/rgnorm,vstep,iter,npv,nfn,ngr ! eps must be set to the machine precision (unit round-off) and tol is a ! tolerance such that numbers whose absolute value is less than tol are ! truncated to zero. This tolerance strategy in the code assumes that the ! problem is well-scaled. The parameter sgnf is used to measure the maximum ! allowable relative error in gradient values. If at any stage the accuracy ! requirement rgtol < sgnf*rgnorm then rgtol is increased to sgnf*rgnorm ! The code allows one or more refinement steps after the ! calculation has terminated, to improve the accuracy of the solution, ! and a fixed number nrep of such repeats is allowed. However the code ! terminates without further repeats if no more than npiv pivots are taken. ! In case of any breakdown, the code is restarted in mode 0. ! The maximum number of unsuccessful restarts allowed is set in nres. ! The basis matrix may be refactorised on occasions, for example to prevent ! build-up of round-off in the factors or (when using schurQR.f) to limit ! the growth in the Schur complement. The maximum interval between ! refactorizations (or size of Schur complement) is set in mxmc. ! Default values are set in block data but can be reset by the user. ! infoc returns information about the progress of the method: rgnorm is the ! norm of the reduced gradient on exit, and vstep is the length of the vertical ! step in the warm start process. iter is the total number of iterations taken, ! npv is the number of pivots, nfn is the number of function evaluations, and ! ngr is the number of gradient evaluations. parameter (ainfty=1.D100) dimension a(*),la(*),x(*),bl(*),bu(*),g(*),r(*),w(*),e(*),ls(*), & alp(*),lp(*),ws(*),lws(*),v(*) character cws(*) character(len=32) spaces common/lcpdc/na,na1,nb,nb1,krg,krg1,kr,kr1, & ka,ka1,kb,kb1,kc,kc1,kd,kd1,ke,ke1,lu1,ll1 common/epsc/eps,t0l,emin ! common/epsc/eps,tol,emin common/infoc/rgnorm,vstep,iter,npv,nfn,ngr common/repc/sgnf,nrep,npiv,nres common/wsc/kk,ll,kkk,lll,mxws,mxlws common/refactorc/mc,mxmc common/alphac/alpha,rp,pj,qqj,qqj1 logical plus 1 format(A,15I5) 2 format(A,6E15.7) 3 format(A/(15I5)) 4 format(A/(5E15.7)) 5 format((6E15.7)) 6 format(A,I5,2E15.7) spaces=' ' mode=m0de tol=t0l iter=0 npv=0 if(m<0 .or. n.le.0 .or. mlp<2 .or. mode<0 .or. mode>4 .or. & kmax<0 .or. (kmax>0 .and. maxg.le.1) .or. tol.le.0.D0) then ifail=6 return end if rgt0l=rgtol n1=n+1 nm=n+m nmi=nm nfn=0 ngr=0 nv0=nv if(iprint>=3) then write(nout,1000)'lower bounds',(bl(i),i=1,nm) write(nout,1000)'upper bounds',(bu(i),i=1,nm) end if irep=0 ires=0 do i=1,nm t=bu(i)-bl(i) if(t<-tol) then print *,'i,bl(i),bu(i)',i,bl(i),bu(i) ifail=2 return else if(t.le.tol) then bl(i)=5.D-1*(bl(i)+bu(i)) bu(i)=bl(i) end if end do vmax=0.D0 do i=1,n x(i)=min(bu(i),max(bl(i),x(i))) vmax=max(vmax,bu(i)-bl(i)) end do if(mode.le.2) then call stmap(n,nm,kmax,maxg) if(mode==0) then nk=0 else if(mode==1) then ! collect equality c/s nk=0 do i=1,nm if(bu(i)==bl(i)) then nk=nk+1 ls(nk)=i end if end do ! write(nout,*)'number of eqty c/s =',nk else nk=n-k end if end if ! restarts loop 7 continue lp(1)=nm lev=1 if(mode.le.3) then ! set up factors of basis matrix and permutation vectors ifail=mode call start_up(n,nm,nmi,a,la,nk,e,ls,ws(lu1),lws(ll1),mode,ifail) if(ifail>0) return end if 8 continue peq=0 ig=0 ! refinement step loop mpiv=iter+npiv ninf=0 do i=1,n g(i)=0.D0 end do if(mode>0) then call warm_start(n,nm,a,la,x,bl,bu,r,ls,ws(lu1), & lws(ll1),ws(na1),vstep) ! print *,'vstep,vmax',vstep,vmax if(vstep>2.D0*vmax) then mpiv=0 mode=0 nk=0 do i=1,n x(i)=min(bu(i),max(bl(i),x(i))) end do goto 7 end if if(vstep>tol)mpiv=0 end if k=0 ! collect free variables do j=n,1,-1 i=abs(ls(j)) if(i.le.n .and. x(i)>bl(i) .and. x(i)<bu(i)) then call iexch(ls(j),ls(n-k)) k=k+1 end if end do if(mode==0) then do j=1,n-k i=ls(j) if(x(i)==bu(i))ls(j)=-i end do lp(1)=n goto 9 end if phase=0 ! move inactive general c/s to the end do j=nm,n1,-1 i=abs(ls(j)) if(i>n) then call iexch(ls(j),ls(lp(1))) lp(1)=lp(1)-1 end if end do call residuals(n,n1,lp(1),a,la,x,bl,bu,r,ls,f,g,ninf) if(ninf>0) then gnorm=sqrt(dble(ninf)) gtol=sgnf*gnorm rgtol=max(rgt0l,gtol) goto 15 end if 9 continue ! enter phase 1 phase=1 ! collect active equality c/s do j=1,n-k i=abs(ls(j)) if(bu(i)==bl(i)) then peq=peq+1 call iexch(ls(j),ls(peq)) end if end do call residuals(n,lp(1)+1,nm,a,la,x,bl,bu,r,ls,f,g,ninf) lp(1)=nm if(ninf>0) then gnorm=sqrt(scpr(0.D0,g,g,n)) gtol=sgnf*gnorm rgtol=max(rgt0l,gtol) goto 15 end if 10 continue phase=2 if(iprint>=1) write(nout,*)'FEASIBILITY OBTAINED at level 1' n_inf=0 call funct(n,x,f,ws,lws,cws) nfn=nfn+1 if(f<fmin) goto 75 call grad(n,x,g,ws,lws,cws) ngr=ngr+1 ! write(nout,4)'x =',(x(i),i=1,n) ! write(nout,4)'g =',(g(i),i=1,n) call newg gnorm=sqrt(scpr(0.D0,g,g,n)) gtol=sgnf*gnorm rgtol=max(rgt0l,gtol) alpha=1.D0 ig=0 if(iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,f goto 16 ! start of major iteration 15 continue if(iprint>=1) then if(ninf==0) then if(k>0) then ! write(nout,'(''pivots ='',I5, ! * '' level = 1 f ='',E16.8,'' k ='',I4)')npv,f,k write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8,'' rg ='',E12.4, '' k ='',I4)')npv,f,rgnorm,k else write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,f end if else if(phase==0) then write(nout,'(''pivots ='',I5,'' level = 1 f ='', E16.8,'' ninfb ='',I4)')npv,f,ninf else write(nout,'(''pivots ='',I5,'' level = 1 f ='', E16.8,'' ninf ='',I4)')npv,f,ninf end if end if 16 continue ! calculate multipliers ! print 4,'gradient =',(g(i),i=1,n) do i=1,nm w(i)=0.D0 end do call fbsub(n,1,n,a,la,0,g,w,ls,ws(lu1),lws(ll1),.true.) call signst(n,r,w,ls) ! opposite bound or reset multiplier loop 20 continue if(iprint>=3) then write(nout,1001)'costs vector and indices', & (ls(j),r(abs(ls(j))),j=1,n) ! write(nout,1000)'steepest edge coefficients', ! * (e(abs(ls(j))),j=1,n) if(peq>0 .or. k>0) write(nout,1) & '# active equality c/s and free variables = ',peq,k end if ! call check(n,lp(1),nmi,kmax,g,a,la,x,bl,bu,r,ls,ws(nb1),f, ! * ws,lws,cws,ninf,peq,k,1,p,rp) 21 continue call optest(peq+1,n-k,r,e,ls,rp,pj) if(phase==0) then ! possibly choose an active general c/s to relax (marked by rp>0) t=-1.D1*rp do 13 j=1,n i=abs(ls(j)) if(i.le.n) goto 13 if(bu(i)==bl(i) .and. r(i)<0.D0) then r(i)=-r(i) ls(j)=-ls(j) end if if(r(i)/e(i).le.t) goto 13 rp=r(i) t=rp/e(i) pj=j 13 continue end if if(ig==0) then gg=0.D0 do j=n-k+1,n i=ls(j) gg=gg+r(i)**2 end do rgnorm=sqrt(gg) end if ! print 2,'rgtol,rgnorm,rp',rgtol,rgnorm,rp 25 continue if(rgnorm.le.rgtol .and. abs(rp).le.gtol) then ! allow for changes to norm(g) gnorm=sqrt(scpr(0.D0,g,g,n)) gtol=sgnf*gnorm rgtol=max(rgt0l,gtol) end if if(iprint==3) print 2,'gtol,rgtol,rgnorm,rp',gtol,rgtol,rgnorm,rp if((rgnorm.le.rgtol .and. abs(rp).le.gtol) .or. ngr>mxgr) then ! optimal at current level: first tidy up x do j=peq+1,n-k i=abs(ls(j)) if(i.le.n) then if(ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if end do do i=1,n x(i)=max(min(x(i),bu(i)),bl(i)) end do do j=n1,nm i=abs(ls(j)) if(r(i).le.tol .and. i.le.n) then r(i)=0.D0 if(ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if end do if(ngr>mxgr) then ifail=5 return end if if(iprint>=2) then write(nout,*)'OPTIMAL at level 1' if(iprint>=3) then ! write(nout,1000)'x variables',(x(i),i=1,n) write(nout,1001)'residual vector and indices', & (ls(j),r(abs(ls(j))),j=n1,nm) end if end if irep=irep+1 if(irep.le.nrep .and. iter>mpiv) then if(iprint>=1) write(nout,*)'refinement step #',irep mode=4 goto 8 end if if(iprint>=2 .and. nrep>0) & write(nout,*)'total number of restarts =',ires if(ninf>0) then ifail=3 return end if nv=nv0 ifail=0 return end if if(rgnorm>=abs(rp)) then ! ignore the multiplier of c/s p and set up or continue SD steps p=0 else p=abs(ls(pj)) if(iprint>=2) print 1,'CHOOSE p =',p rp=r(p) call iexch(ls(pj),ls(n-k)) pj=n-k ig=0 end if ! if(k==0 .or. p>n) then if(p>0) then ! compute +/- Steepest Edge (SE) search direction s in an(.) call tfbsub(n,a,la,p,ws(na1),ws(na1),ws(lu1),lws(ll1), & e(p),.true.) rp=scpr(0.D0,ws(na1),g,n) if(ls(pj)<0)rp=-rp if(rp*r(p).le.0.D0) then r(p)=0.D0 goto 21 end if if(abs(rp-r(p))>5.D-1*max(abs(rp),abs(r(p)))) then ! if(abs(rp-r(p))>1.D-1*gnorm) then print 2,'1rp,r(p),rp-r(p)',rp,r(p),rp-r(p) goto 98 end if snorm=e(p) plus=ls(pj)>=0.eqv.rp<0.D0 f0=f ig=0 else if(ig==0) then ! start up the limited memory sweep method ! if(p>0) then ! transfer c/s p into Z ! if(ls(pj)<0) then ! r(p)=-r(p) ! ls(pj)=-ls(pj) ! end if ! k=k+1 ! gg=gg+r(p)**2 ! end if ig=1 ngv=1 f0=f ws(kb1)=gg rgnorm=sqrt(gg) ! print 2,'initial rg =',(r(ls(j)),j=n-k+1,n) if(k*ngv>kmax*maxg) then ifail=9 return end if call store_rg(k,ig,ws(krg1),r,ls(n-k+1)) end if ! compute Steepest Descent (SD) search direction s = -Z.rg in an(.) call zprod(k,n,a,la,ws(na1),r,w,ls,ws(lu1),lws(ll1)) rp=scpr(0.D0,ws(na1),g,n) if(abs(gg+rp)>5.D-1*max(gg,abs(rp))) then ! if(abs(gg+rp)>1.D-2*max(gg,abs(rp))) then print 2,'gg,rp,gg+rp',gg,rp,gg+rp goto 98 end if snorm=sqrt(scpr(0.D0,ws(na1),ws(na1),n)) plus=.true. end if ! print 4,'s (or -s if .not.plus) =',(ws(i),i=na1,na+n) ! form At.s and denominators call form_Ats(n1,lp(1),n,plus,a,la,ws(na1),w,ls,snorm*tol) ! return from degeneracy code 30 continue if(iprint>=3) then write(nout,1000)'x variables',(x(i),i=1,n) write(nout,1001)'residual vector and indices', & (ls(j),r(abs(ls(j))),j=n1,lp(1)) write(nout,1000)'denominators',(w(abs(ls(j))),j=n1,lp(1)) end if 40 continue ! level 1 ratio tests amax=ainfty qj=0 qj1=0 do 41 j=n-k+1,n i=ls(j) if(i.le.0) print *,'i.le.0' if(i.le.0) goto 98 si=ws(na+i) if(si==0.D0) goto 41 t=abs(si) ! if(t.le.tol) goto 41 if(si>0.D0.eqv.plus) then z=bu(i)-x(i) if(abs(z)<tol) then z=0.D0 x(i)=bu(i) else z=z/t end if else z=x(i)-bl(i) if(abs(z)<tol) then z=0.D0 x(i)=bl(i) else z=z/t end if end if if(z>amax) goto 41 amax=z qj=j 41 continue if(ig==0 .and. rp<0.D0 .and. bu(p)-bl(p)<amax) then amax=bu(p)-bl(p) qj=pj end if if(ninf>0) then alpha1=ainfty do 42 j=n1,lp(1) i=abs(ls(j)) wi=w(i) if(wi==0.D0) goto 42 ri=r(i) if(wi>0.D0) then if(ri<0.D0) goto 42 z=(ri+tol)/wi else if(ri<0.D0) then z=ri/wi if(z<alpha1) then alpha1=z qj1=j end if end if z=(bl(i)-bu(i)+ri-tol)/wi end if if(z>=amax) goto 42 amax=z qj=j 42 continue if(qj1>0 .and. alpha1.le.amax) then ! find feasible step that zeros most infeasible c/s do 43 j=n1,lp(1) i=abs(ls(j)) wi=w(i) if(wi>=0.D0) goto 43 ri=r(i) if(ri<0.D0) then z=ri/wi if(z>alpha1 .and. z.le.amax) then alpha1=z qj1=j end if end if 43 continue amax=alpha1 qj=qj1 else qj1=0 end if else do 44 j=n1,lp(1) i=abs(ls(j)) wi=w(i) if(wi==0.D0) goto 44 ri=r(i) if(wi>0.D0) then z=(ri+tol)/wi else z=(bl(i)-bu(i)+ri-tol)/wi end if if(z>=amax) goto 44 amax=z qj=j 44 continue end if q=abs(ls(qj)) if(iprint>=2 .and. q/=p .and. qj>n) & write(nout,*)'q,r(q),w(q) =',q,r(q),w(q) if(qj>n .and. qj1==0) then if(w(q)>0.D0) then amax=r(q)/w(q) else amax=(bl(q)-bu(q)+r(q))/w(q) end if end if if(amax==0.D0 .and. rp.le.0.D0) then alpha=0.D0 ! potential degeneracy block at level 1 if(p==0) goto 65 if(bu(q)==bl(q)) goto 70 plev=n do j=n1,lp(1) i=abs(ls(j)) if(r(i)==0.D0) then plev=plev+1 call iexch(ls(j),ls(plev)) if(bu(i)>bl(i))r(i)=1.D0 end if end do if(plev>n1) then lp(2)=plev lev=2 alp(1)=f f=0.D0 qj=pj q=p if(iprint>=1) write(nout,'(''pivots ='',I5,'' level = 2'', '' f ='',E16.8)')npv,f goto 86 end if qj=n1 r(q)=0.D0 ! print *,'only one degenerate c/s' goto 70 end if if(ninf>0) then alpha=amax if(plus) then call mysaxpy(alpha,ws(na1),x,n) else call mysaxpy(-alpha,ws(na1),x,n) end if else ! take a Ritz value off the stack ! print 4,'Ritz values =',(v(i),i=1,nv) if(nv>0 .and. v(nv)>0.D0) then alpha=min(1.D0/v(nv),amax) nv=nv-1 else alpha=amax nv=0 end if ! line search alphar=amax alphal=0.D0 dalpha=alpha fi=f fr=ainfty ggo=gg gs=rp gsi=gs ! print 2,'f0,fi,gsi,amax =',f0,fi,gsi,amax 51 continue ! calculate new x if(plus) then call saxpyz(alpha,ws(na1),x,ws(nb1),n) else call saxpyz(-alpha,ws(na1),x,ws(nb1),n) end if call funct(n,ws(nb1),fp,ws,lws,cws) if(fp<fmin) goto 75 nfn=nfn+1 df=f-fp ! check for lack of improvement if(fp>=f0) then ! print 2,'alphal,alpha,fp =',alphal,alpha,fp if(dalpha<1.D-10 .and. df<-dalpha*gs) then ! print *,'alpha too small' if(alphal>0.D0) goto 52 ifail=4 return end if fr=fp alphar=alpha z=5.D-1/(1.D0+df/(gs*dalpha)) ! print 2,'df,z =',df,z dalpha=dalpha*max(1.D-1,z) alpha=alphal+dalpha nv=0 goto 51 end if f=fp call grad(n,ws(nb1),g,ws,lws,cws) ngr=ngr+1 ! print 4,'new g =',(g(i),i=1,n) call newg gps=scpr(0.D0,g,ws(na1),n) if(.not.plus)gps=-gps ! print 2,'fp,gps',fp,gps ! print 2,'alphal,alpha,alphar',alphal,alpha,alphar ! check for non-positive curvature if(alpha<amax .and. (gps.le.gsi .or. (gps<25.D-2*gsi .and. & (alphal>0.D0 .or. fr<ainfty)))) then ! if(alpha<amax .and. gps.le.gsi) then alphal=alpha if(fr==ainfty) then alpha=min(alpha*5.D0,amax) dalpha=alpha-alphal else dalpha=alphar-alpha z=max(2.D-1,5.D-1/(1.D0+(f-fr)/(gps*dalpha))) dalpha=dalpha*z alpha=min(alpha+dalpha,amax) end if gs=gps nv=0 goto 51 end if ! end of line search 52 continue do i=1,n x(i)=ws(nb+i) end do if(ig==0) goto 60 ig1=ig+1 if(ig1>maxg)ig1=1 call fbsub(n,1,n,a,la,0,g,w,ls,ws(lu1),lws(ll1),.true.) ! print 4,'new rg =',(w(ls(j)),j=n-k+1,n) if(ngv<maxg)ngv=ngv+1 if(k*ngv>kmax*maxg) then ifail=9 return end if call store_rg(k,ig1,ws(krg1),w,ls(n-k+1)) gpg=0.D0 gg=0.D0 do j=n-k+1,n i=ls(j) gpg=gpg+r(i)*w(i) gg=gg+w(i)**2 end do rgnorm=sqrt(gg) ! print 2,'gpg,gg',gpg,gg ! print 2,'f =',f call signst(n,r,w,ls) ws(ka+ig)=1.D0/alpha ws(kb+ig1)=gg ws(kc+ig)=gpg if(nv==0 .or. gg>ggo) then ! compute new Ritz values if(ngv==0) then nv=1 v(1)=1.D0/alpha else nv=min(ngv-1,k) if(nv.le.0) print 1,'ngv,k,ig,nv =',ngv,k,ig,nv if(nv.le.0) goto 98 ! print 1,'ngv,k,ig,nv =',ngv,k,ig,nv ! print 4,'G =',(ws(krg+i),i=1,k*ngv) ! print 4,'a =',(ws(ka+i),i=1,ngv) ! print 4,'b =',(ws(kb+i),i=1,ngv+1) ! print 4,'c =',(ws(kc+i),i=1,ngv) call formR(nv,k,ig,maxg,ws(ka1),ws(kb1),ws(kc1),ws(kd1), & ws(ke1),ws(krg1),ws(kr1)) ! call checkT(nv,maxg,ws(kr1),ws(ke1),ws(kd1)) call formT(nv,maxg,ws(kr1),v,ws(ke1)) ! print 4,'T matrix',(v(i),i=1,nv) ! if(nv>1) print 5,(ws(ke+i),i=1,nv-1) call trid(v,ws(ke1),nv) ! print 4,'eigenvalues of T',(v(i),i=1,nv) call insort(nv,v) ! print 4,'sorted eigenvalues of T',(v(i),i=1,nv) end if nv0=nv f0=f end if ig=ig1 end if 60 continue if(alpha>0.D0) then ! update r for inactive c/s iter=iter+1 if(ninf>0) then n_inf=0 ff=f f=0.D0 do 61 j=n1,lp(1) i=abs(ls(j)) if(w(i)==0.D0) then if(r(i)>=0.D0) goto 61 n_inf=n_inf+1 f=f-r(i) goto 61 end if ri=r(i)-alpha*w(i) if(abs(ri).le.tol)ri=0.D0 if(r(i)<0.D0) then if(ri>=0.D0) then ! remove contribution to gradient if(i>n) then call saipy(sign(1.D0,dble(ls(j))),a,la,i-n,g,n) else g(i)=0.D0 end if else n_inf=n_inf+1 f=f-ri end if end if if(w(i)<0.D0) then ro=(bu(i)-bl(i))-ri if(abs(ro).le.tol)ro=0.D0 if(ro<ri) then ri=ro ls(j)=-ls(j) end if end if if(ri==0.D0 .and. i.le.n) then if(ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if r(i)=ri 61 continue if(n_inf/=ninf) then call iexch(ninf,n_inf) call newg ! else if(f>=ff) then else if(f>=eps*ff+ff) then goto 98 end if else n_inf=0 do 62 j=n1,lp(1) i=abs(ls(j)) if(w(i)==0.D0) goto 62 ri=r(i)-alpha*w(i) if(w(i)<0.D0) then ro=(bu(i)-bl(i))-ri if(ro<ri) then ri=ro w(i)=-w(i) ls(j)=-ls(j) end if end if if(ri.le.tol) then ri=0.D0 if(i.le.n) then if(ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if end if r(i)=ri 62 continue end if end if if(alpha<amax) then if(ig>0) then ! continue limited memory SD iterations if(iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8,'' rg ='',E12.4, '' k ='',I4)')npv,f,rgnorm,k if(alpha>0.D0) goto 20 print *,'alpha.le.0' goto 98 end if ! Cauchy step with SE iteration k=k+1 if(p.le.n) then ls(pj)=p goto 15 end if ! case p>n: find best inactive simple bound to replace p in ls(pj) t=0.D0 do j=n1,lp(1) i=abs(ls(j)) if(i.le.n) then ti=abs(ws(na+i)) if(ti>t) then t=ti qj=j end if end if end do if(t.le.snorm*tol) then print *,'no suitable simple bound available' goto 98 end if q=abs(ls(qj)) ls(qj)=q if(iprint>=2) write(nout,1)'New free variable',q goto 70 end if 65 continue if(iprint>=2) & write(nout,*)'New active c/s: alpha =',alpha,' q =',q if(ig>0) then ! case alpha=amax and SD step: find best free variable to relax k=k-1 if(qj.le.n) then ! case: q is a free variable if(ws(na+q)>0.D0)ls(qj)=-q call iexch(ls(qj),ls(n-k)) ig=0 if(n_inf>0 .and. ninf==0) goto 10 goto 15 end if call fbsub(n,n-k,n,a,la,q,w,w,ls,ws(lu1),lws(ll1),.false.) ! print 4,'w(n-k:n) =',(w(ls(j)),j=n-k,n) t=0.D0 do j=n-k,n i=ls(j) ti=abs(w(i))/e(i) if(ti>t) then t=ti pj=j end if end do if(t.le.tol) then print *,'no suitable free variable to relax' goto 98 end if p=ls(pj) call iexch(ls(pj),ls(n-k)) pj=n-k if(iprint>=2) write(nout,*)'relax free variable',p end if ! return from degeneracy with an equality c/s 70 continue if(qj/=pj) then ! pivot interchange if(iprint>=2) write(nout,*)'replace',p,' by',q if(p==0) print *,'p==0' if(p==0) goto 98 call pivot(p,q,n,nmi,a,la,e,ws(lu1),lws(ll1),ifail,npv) if(ifail>=1) then ! if(ifail>=2) return if(ifail==7) return if(iprint>=1) write(nout,*)'failure detected in pivot (1)' ! print *,'r(q),w(q),q',r(q),w(q),q goto 98 end if if(rp>0.D0) then if(phase>0) print *,'phase =',phase call iexch(ls(pj),ls(qj)) call iexch(ls(lp(1)),ls(qj)) lp(1)=lp(1)-1 if(ninf>0) goto 15 goto 9 end if if(ig>0) then ri=x(p)-bl(p) ro=bu(p)-x(p) if(ro<ri) then ri=ro ls(pj)=-p end if if(ri.le.tol)ri=0.D0 r(p)=ri ig=0 else rpu=max(bu(p)-bl(p)-alpha,0.D0) if(alpha.le.rpu) then rpu=alpha else ls(pj)=-ls(pj) end if if(abs(rpu).le.tol)rpu=0.D0 r(p)=rpu end if ! print 2,'r(p)',r(p) call iexch(ls(pj),ls(qj)) if(phase>0 .and. bu(q)==bl(q)) then peq=peq+1 call iexch(ls(pj),ls(peq)) end if if(ninf==0) then if(phase==0) goto 9 if(phase==1) goto 10 end if goto 15 end if ! opposite bound comes active if(ninf==0) then if(iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,f else if(phase==0) then if(iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8,'' ninfb ='',I4)') & npv,f,ninf else if(iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8,'' ninf ='',I4)') & npv,f,ninf end if ls(pj)=-ls(pj) if(ninf==0 .or. ninf/=n_inf) goto 16 r(p)=-rp goto 20 ! unbounded solution case 75 continue irep=irep+1 if(irep.le.nrep .and. iter>mpiv) then mode=4 if(iprint>=1) write(nout,*) & 'unbounded solution identified: refinement step #',irep goto 8 end if ifail=1 ! tidy up x do i=1,n x(i)=max(min(x(i),bu(i)),bl(i)) end do do j=n1,nm i=abs(ls(j)) if(r(i)==0.D0 .and. i.le.n) then if(ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if end do nv=nv0 return ! recursive code for resolving degeneracy (Wolfe's method) 80 continue ! calculate multipliers call fbsub(n,1,n,a,la,0,g,w,ls,ws(lu1),lws(ll1),.true.) call signst(n,r,w,ls) ! reset multiplier loop 82 continue if(iprint>=3) then write(nout,1001)'costs vector and indices', & (ls(j),r(abs(ls(j))),j=1,n) ! write(nout,1000)'steepest edge coefficients', ! * (e(abs(ls(j))),j=1,n) if(peq>0 .or. k>0) write(nout,1) & '# active equality c/s and free variables = ',peq,k end if 84 continue call optest(peq+1,n-k,r,e,ls,rp,pj) if(-rp.le.gtol) then if(iprint>=2) write(nout,*)'return to level 1' lev=1 f=alp(1) do j=n1,lp(2) r(abs(ls(j)))=0.D0 end do lev=1 if(rp==0.D0 .and. phase>0) goto 25 goto 20 end if call iexch(ls(pj),ls(n-k)) pj=n-k plus=ls(pj)>=0 p=abs(ls(pj)) rp=r(p) ! compute search direction s in an(.) call tfbsub(n,a,la,p,ws(na1),ws(na1),ws(lu1),lws(ll1), & e(p),.true.) rp=scpr(0.D0,ws(na1),g,n) if(ls(pj)<0)rp=-rp if(rp*r(p).le.0.D0) then r(p)=0.D0 goto 84 end if if(abs(rp-r(p))>5.D-1*max(abs(rp),abs(r(p)))) then ! if(abs(rp-r(p))>1.D-1*gnorm) then print 2,'2rp,r(p),rp-r(p)',rp,r(p),rp-r(p) goto 98 end if snorm=e(p) ! form At.s and denominators call form_Ats(n1,lp(lev),n,plus,a,la,ws(na1),w,ls,snorm*tol) 86 continue if(iprint>=3) then write(nout,1001)'residual vector and indices', & (ls(j),r(abs(ls(j))),j=n1,lp(lev)) write(nout,1000)'denominators',(w(abs(ls(j))),j=n1,lp(lev)) end if 88 continue ! ratio test at higher levels alpha=ainfty qj=0 do 90 j=n1,lp(lev) i=abs(ls(j)) wi=w(i) if(wi.le.0.D0) goto 90 if(r(i)<0.D0) goto 90 z=(r(i)+tol)/wi if(z>=alpha) goto 90 alpha=z qj=j 90 continue if(qj==0) then do j=n1,lp(lev) i=abs(ls(j)) w(i)=min(w(i),0.D0) r(i)=0.D0 end do call form_Ats(lp(lev)+1,lp(lev-1),n,plus,a,la,ws(na1), & w,ls,snorm*tol) lev=lev-1 f=alp(lev) if(iprint>=2) write(nout,*)'UNBOUNDED: p =',p, & ' return to level',lev if(lev>1) goto 86 if(iprint>=3) then write(nout,1001)'costs vector and indices', & (ls(j),r(abs(ls(j))),j=1,n) if(peq>0 .or. k>0) print 1, & '# active equality c/s and free variables = ',peq,k end if ! call check(n,lp(1),nmi,kmax,g,a,la,x,bl,bu,r,ls,ws(nb1),f, ! * ws,lws,cws,ninf,peq,k,1,p,rp) goto 30 end if q=abs(ls(qj)) alpha=r(q)/w(q) ff=f+alpha*rp if(iprint>=2) then write(nout,*)'alpha =',alpha,' p =',p,' q =',q write(nout,2)'r(p),r(q),w(q) =',r(p),r(q),w(q) end if ! test for equality c/s if(bu(q)==bl(q)) then do j=n1,lp(2) r(abs(ls(j)))=0.D0 end do lev=1 f=alp(1) alpha=0.D0 if(iprint>=2) write(nout,*)'EQTY: p =',p,' q =',q, & ' return to level 1' goto 70 end if if(alpha==0.D0) then ! potential degeneracy block at level lev if(lev+2>mlp) then ifail=8 return end if r(q)=0.D0 plev=n do j=n1,lp(lev) i=abs(ls(j)) if(r(i)==0.D0) then plev=plev+1 call iexch(ls(j),ls(plev)) if(bu(i)>bl(i))r(i)=1.D0 end if end do if(plev>n1) then lev=lev+1 lp(lev)=plev alp(lev)=f f=0.D0 if(iprint>=2) write(nout,*) 'degeneracy: increase level to ',lev if(iprint>=1) write(nout,'(''pivots ='',I5,A,''level ='',I2, '' f ='',E16.8)')npv,spaces(:3*lev-1),lev,f goto 86 end if qj=n1 end if iter=iter+1 if(iprint>=2) write(nout,*)'replace',p,' by',q call pivot(p,q,n,nmi,a,la,e,ws(lu1),lws(ll1),ifail,npv) if(ifail>=1) then ! if(ifail>=2) return if(ifail==7) return ! call iexch(ls(pj),ls(qj)) if(iprint>=1) write(nout,*)'failure detected in pivot (2)' ! print *,'r(q),w(q),q',r(q),w(q),q goto 98 end if ! update r and f do j=n1,lp(lev) i=abs(ls(j)) ri=r(i)-alpha*w(i) if(abs(ri).le.tol)ri=0.D0 r(i)=ri end do f=ff ! exchange a constraint r(p)=alpha if(r(p).le.tol)r(p)=0.D0 call iexch(ls(pj),ls(qj)) if(iprint>=1) write(nout,'(''pivots ='',I5,A,''level ='',I2, '' f ='',E16.8)')npv,spaces(:3*lev-1),lev,f goto 80 ! restart sequence 98 continue do i=1,n x(i)=min(bu(i),max(bl(i),x(i))) end do nk=peq do j=peq+1,n-k i=abs(ls(j)) if(i>n) then nk=nk+1 ls(nk)=ls(j) end if end do k=n-nk mode=2 ires=ires+1 if(iprint>=1) write(nout,*)'major restart #',ires tol=1.D1*tol if(ires.le.nres) goto 7 ifail=10 return 1000 format(a/(e16.5,4e16.5)) 1001 format(a/(i4,1x,e12.5,4(i4,1x,e12.5))) !1000 format(a/(e18.8,3e19.8)) !1001 format(a/(i3,1x,e14.8,3(i4,1x,e14.8))) end ! block data defaults ! implicit double precision (a-h,o-z) ! common/epsc/eps,tol,emin ! common/repc/sgnf,nrep,npiv,nres ! common/refactorc/mc,mxmc ! common/wsc/kk,ll,kkk,lll,mxws,mxlws ! data eps, tol, emin, sgnf, nrep, npiv, nres, mxmc, kk, ll ! * /1111.D-19, 1.D-12, 0.D0, 1.D-8, 2, 3, 2, 500, 0, 0/ ! end subroutine stmap(n,nm,kmax,maxg) ! set storage map for workspace in glcpd and auxiliary routines implicit double precision (a-h,r-z), integer (i-q) common/wsc/kk,ll,kkk,lll,mxws,mxlws common/lcpdc/na,na1,nb,nb1,krg,krg1,kr,kr1, & ka,ka1,kb,kb1,kc,kc1,kd,kd1,ke,ke1,lu1,ll1 ! double precision storage (ws) ! locations 1:kk are user workspace for funct and grad ! scratch slots of length n+m and n na=kk na1=kk+1 nb=na+nm nb1=nb+1 ! workspace of length kmax*maxg for reduced gradient vectors krg=nb+n krg1=krg+1 ! a slot of length maxg*(maxg+1)/2 and 5 slots of length maxg for sweep method kr=krg+kmax*maxg kr1=kr+1 ka=kr+maxg*(maxg+1)/2 ka1=ka+1 kb=ka+maxg kb1=kb+1 kc=kb+maxg kc1=kc+1 kd=kc+maxg kd1=kd+1 ke=kd+maxg ke1=ke+1 ! remaining space for use by denseL.f or schurQR.f lu1=ke1+maxg ! total number of double precision locations required by glcpd kkk=nm+n+maxg*(maxg+1)/2+maxg*(kmax+5) ! integer storage (lws) ! locations 1:ll are user workspace for funct and grad ! number of integer locations required by glcpd lll=0 ! remaining space for use by denseL.f or schurQR.f ll1=ll+1 return end subroutine check(n,nm,nmi,kmax,g,a,la,x,bl,bu,r,ls,an,f, & ws,lws,cws,ninf,peq,k,lev,p,alp2) implicit double precision (a-h,r-z), integer (i-q) dimension g(*),a(*),la(*),x(*),bl(*),bu(*),r(*),ls(*), & an(*),ws(*),lws(*) character cws(*) common/noutc/nout common/epsc/eps,tol,emin ! if(lev==2) then ! do i=1,n ! an(i)=g(i) ! end do ! e=alp2*sign(1.D0,dble(p)) ! i=abs(p) ! if(i.le.n) then ! an(i)=an(i)-e ! else ! call saipy(-e,a,la,i-n,an,n) ! end if ! goto 1 ! end if j=nmi*(nmi+1)/2 do i=1,nmi j=j-abs(ls(i)) end do if(j/=0) write(nout,*)'indexing error' if(j/=0) stop do j=1,peq i=abs(ls(j)) if(bu(i)>bl(i)) then write(nout,*)'non-equality constraint i =',i stop end if end do do j=n-k+1,n i=ls(j) if(i.le.0 .or. i>n) then write(nout,*)'faulty free variable: i, j =',i,j stop end if end do e=0.D0 do j=n+1,nm i=abs(ls(j)) if(i.le.n) then s=x(i) else s=aiscpr(n,a,la,i-n,x,0.D0) end if if(ls(j)>0) then ! print *,'i,s,r(i),bl(i)',i,s,r(i),bl(i) s=r(i)-s+bl(i) else s=r(i)+s-bu(i) end if if(abs(s).le.tol*max(1.D0,abs(r(i))))s=0.D0 if(abs(s)>e) then e=abs(s) ie=i end if end do if(e>tol) write(nout,*)'residual error at level 1 = ',e,ie ! if(e>tol) stop if(e>1.D-6) stop if(ninf==0) then call funct(n,x,ff,ws,lws,cws) call grad(n,x,an,ws,lws,cws) else do i=1,n an(i)=0.D0 end do ff=0.D0 do j=n+1,nm i=abs(ls(j)) if(r(i)<0.D0) then ff=ff-r(i) if(i>n) then call saipy(-sign(1.D0,dble(ls(j))),a,la,i-n,an,n) else an(i)=an(i)-sign(1.D0,dble(ls(j))) end if end if end do end if gnm=sqrt(scpr(0.D0,an,an,n)) if(lev==1 .and. max(abs(f),abs(ff))<1.D20) then e=abs(ff-f) if(e>tol*max(1.D0,abs(f))) write(nout,*)'function error = ',e, & ' f(x) =',ff ! if(e>tol) stop ! if(e>tol*max(1.D0,abs(f))) print 4,'x =',(x(j),j=1,n) if(e>tol*max(1.D0,abs(f))) stop end if 1 continue e=0.D0 do j=1,n ! write(nout,*)'an =',(an(i),i=1,n) i=abs(ls(j)) s=sign(1.D0,dble(ls(j))) if(i.le.n) then ! print *,'i,s,r(i)',i,s,r(i) an(i)=an(i)-s*r(i) if(j>n-k) then s=max(0.D0,bl(i)-x(i),x(i)-bu(i)) else if(ls(j)>0) then s=x(i)-bl(i) else s=bu(i)-x(i) end if else ! print *,'i,s,r(i)',i,s,r(i) call saipy(-s*r(i),a,la,i-n,an,n) if(ls(j)>0) then s=aiscpr(n,a,la,i-n,x,-bl(i)) else s=-aiscpr(n,a,la,i-n,x,-bu(i)) end if end if if(abs(s)>e) then e=abs(s) ie=i end if end do if(e>tol) write(nout,*)'residual error at level 2 = ',e,ie ! if(e>tol) stop ! if(e>1.D-6) print 4,'x =',(x(i),i=1,n) if(e>1.D-6) stop e=0.D0 do j=1,n if(abs(an(j))>e) then e=abs(an(j)) ie=ls(j) je=j end if end do if(e>gnm*tol) write(nout,*)'KT condition error = ',e,je,ie,gnm ! if(e>gnm*tol) write(nout,4)'KT cond_n errors = ',(an(i),i=1,n) ! if(e>gnm*tol) stop if(e>1.D-4) stop 2 format(A,5E15.7) 4 format(A/(5E15.6)) return end