!Christen this file qlcpd.f !ut here >>>>>>>>>>>>>>>>> ! Copyright (C) 2010 Roger Fletcher ! Current version dated 18 April 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 qlcpd(n,m,k,kmax,maxg,a,la,x,bl,bu,f,fmin,g,r,w,e,ls, & alp,lp,mlp,peq,ws,lws,v,nv,linear,rgtol,m0de,ifail,mxgr,iprint, & nout) implicit double precision (a-h,r-z), integer (i-q) logical linear ! This routine finds a KT point for the Quadratic LCP (QP) problem ! minimize f(x) = ct.x + xt.G.x/2 ! subject to l <= [I : A]t.x <= u (t = transpose) ! where x and c are n-vectors, G is a symmetric n*n matrix, and A is an ! n*m matrix. If G is also positive semi-definite then the KT point is a ! global solution, else usually a local solution. The method may also be ! used efficiently to solve an LP problem (G=0). A recursive form of an ! active set method is used, using Wolfe's method to resolve degeneracy. ! A limited memory sweep method is used for minimization in the null space. ! 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), typically maxg = min(6,kmax+1) ! a(*) storage of reals associated with c and 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(*). ! 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 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=20 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 stmapq below ! v(maxg) set nv estimates of the eigenvalues of the reduced Hessian of f(x) ! (for example from a previous run of qlcpd). 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 ! linear (logical) set linear = .true. iff the problem is an LP ! 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 A is unchanged so ! that factors of the basis matrix stored in ws and lws are valid ! (changes in the vectors c, l, u and the matrix G are allowed) ! A local copy (mode) of m0de is made and may be changed by qlcpd ! ifail outcome of the process ! 0 = solution obtained ! 1 = unbounded problem detected (f(x)<=fmin would occur) ! 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, mode 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 = crash in pivot call ! mxgr maximum number of gradient evaluations ! iprint switch for diagnostic printing (0 = off, 1 = summary, ! 2 = scalar information, 3 = verbose) ! nout channel number for output ! Common ! ****** ! User information about the lengths of ws and lws is supplied to qlcpd in ! common/wsc/kk,ll,kkk,lll,mxws,mxlws ! kk and ll refer to the length of ws and lws needed by gdotx. ! kkk and lll are the numbers of locations used by qlcpd and are set by qlcpd. ! 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 length of ws and lws available: a ! message will be given if more storage is needed. ! User subroutine ! *************** ! The user must provide a subroutine to calculate the vector v := G.x from a ! given vector x. The header of the routine is ! subroutine gdotx(n,x,ws,lws,v) ! implicit double precision(a-h,o-z) ! dimension x(*),ws(*),lws(*),v(*) ! In the case that linear is .true. the subroutine is not called by qlcpd and ! a dummy routine may be supplied. Otherwise the user may use the parameters ! ws and lws (see above) for passing real or integer arrays relating to G. ! Locations ws(1),...,ws(kk) are available to the user for storing any real ! information to be used by gdotx. Likewise locations lws(1),...,lws(ll) are ! available for storing any integer information. Default values are kk=ll=0. ! Any other setting is made by changing common/wsc/kk,ll,kkk,lll,mxws,mxlws ! Tolerances and accuracy ! *********************** ! qlcpd 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,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 and a pre-scaling routine cscale is supplied in ! denseA.f or sparseA.f. 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, usually in mode 2. ! 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, and ngr is the number of calls of gdotx. parameter (ainfty=1.D100) dimension a(*),x(*),bl(*),bu(*),g(*),r(*),w(*),e(*),alp(*),ws(*), & la(*),ls(*),lp(*),lws(*),v(*) 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/infoc/rgnorm,vstep,iter,npv,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<=0 .or. mlp<2 .or. mode<0 .or. mode>4 .or. & kmax<0 .or. (kmax>0 .and. maxg<=1) .or. tol<=0.0D0) then ifail=6 return end if rgt0l=rgtol n1=n+1 nm=n+m nmi=nm 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 mres=0 bestf=ainfty do i=1,nm t=bu(i)-bl(i) if (t<-tol) then ifail=2 return end if if (t<=tol .and. t>0.D0) 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<=2) then call stmapq(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<=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<=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 setfg2(n,linear,a,la,x,f,g,ws,lws) fbase=f f=0.D0 ngr=ngr+1 ! 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) ig=0 if (iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,fbase 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 df ='',E16.8,'' k ='',I4)')npv,f,k write(nout,'(''pivots ='',I5, '' level = 1 df ='',E16.8,'' rg ='',E12.4, '' k ='',I4)')npv,f,rgnorm,k else write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,fbase+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 do i=1,nm w(i)=0.D0 end do ! write(nout,4)'g =',(g(i),i=1,n) 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 ! if (iphase<=1)fbase=0.D0 ! call checkq(n,lp(1),nmi,kmax,g,a,la,x,bl,bu,r,ls,ws(nb1),fbase+f, ! * ws,lws,ninf,peq,k,1,p,rp,linear) 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<=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)<=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<=rgtol .and. abs(rp)<=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 ((rgnorm<=rgtol .and. abs(rp)<=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<=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)==0.D0 .and. i<=n) then if (ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if end do if (ngr>mxgr) then f=fbase+f 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<=nrep .and. iter>mpiv) then if (iprint>=1) write(nout,1)'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 f=fbase+f 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 (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)<=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 f=fbase+f 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) ! print *,'plus =',plus ! 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 ! read *,i 40 continue ! level 1 ratio tests amax=ainfty qj=0 qj1=0 do 41 j=n-k+1,n i=ls(j) if (i<=0) print *,'i<=0' if (i<=0) stop si=ws(na+i) if (si==0.D0) goto 41 t=abs(si) 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<=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<=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<=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 else if (linear) then alpha=amax ff=f+alpha*rp if (ff<fmin) goto 75 f=ff goto 60 end if call gdotx(n,ws(na1),ws,lws,ws(nb1)) ngr=ngr+1 sgs=scpr(0.D0,ws(na1),ws(nb1),n) ! print 2,'rp,sgs',rp,sgs ggo=gg if (p==0) then t=v(nv) if (t<=0.D0) goto 52 alpha=1.D0/t if (alpha>=amax) goto 52 nv=nv-1 ff=f+alpha*(rp+5.D-1*alpha*sgs) if (ff>=f0) goto 52 ! print 2,'alphar =',alpha ! need to set f0 somewhere if (iprint>=2) write(nout,*)'Ritz value step: alpha =', & alpha,' p =',p goto 54 end if 52 continue if (sgs>0.D0) then alpha=-rp/sgs if (alpha<amax) then ! accept Cauchy step if (iprint>=2) write(nout,*)'Cauchy step: alpha =', & alpha,' p =',p ff=f+alpha*(rp+5.D-1*alpha*sgs) nv=0 ! print 2,'alphac =',alpha goto 54 end if end if ! Cauchy step infeasible alpha=amax ff=f+alpha*(rp+5.D-1*alpha*sgs) if (ff<fmin) goto 75 if (ff>=f) then if (ires<nres) goto 98 f=fbase+f if (iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,f ifail=4 return end if f=ff if (plus) then call mysaxpy(alpha,ws(nb1),g,n) else call mysaxpy(-alpha,ws(nb1),g,n) end if ! print 4,'new g =',(g(i),i=1,n) call newg goto 60 54 continue if (ff<fmin) goto 75 if (ff>=f) then if (ires<nres) goto 98 f=fbase+f if (iprint>=1) write(nout,'(''pivots ='',I5, '' level = 1 f ='',E16.8)')npv,f ifail=4 return end if f=ff if (plus) then call mysaxpy(alpha,ws(nb1),g,n) else call mysaxpy(-alpha,ws(nb1),g,n) end if ! print 4,'new g =',(g(i),i=1,n) call newg 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 f=fbase+f 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==2) then nv=1 v(1)=1.D0/alpha else nv=min(ngv-1,k) if (nv<=0) print 1,'ngv,k,ig,nv =',ngv,k,ig,nv if (nv<=0) stop ! 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(1),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 x if (plus) then call mysaxpy(alpha,ws(na1),x,n) else call mysaxpy(-alpha,ws(na1),x,n) end if ! 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)<=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)<=tol)ro=0.D0 if (ro<ri) then ri=ro ls(j)=-ls(j) end if end if if (ri==0.D0 .and. i<=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=max(ro,0.D0) w(i)=-w(i) ls(j)=-ls(j) end if end if if (ri<=tol) then ri=0.D0 if (i<=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 df ='',E16.8,'' rg ='',E12.4, '' k ='',I4)')npv,f,rgnorm,k if (alpha>0.D0) goto 20 print *,'alpha<=0' goto 98 end if ! Cauchy step with SE iteration k=k+1 if (p<=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<=n) then ti=abs(ws(na+i)) if (ti>t) then t=ti qj=j end if end if end do if (t<=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<=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<=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) then ifail=11 return end if 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 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<=tol)ri=0.D0 r(p)=ri ig=0 else rpu=max(bu(p)-bl(p)-alpha,0.D0) if (alpha<=rpu) then rpu=alpha else ls(pj)=-ls(pj) end if if (abs(rpu)<=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,fbase+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 .and. .not.linear) goto 16 if (ninf>0 .and. ninf/=n_inf) goto 16 r(p)=-rp goto 20 ! unbounded solution case 75 continue irep=irep+1 if (irep<=nrep .and. iter>mpiv) then mode=4 if (iprint>=1) write(nout,1) & '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<=n) then if (ls(j)>=0) then x(i)=bl(i) else x(i)=bu(i) end if end if end do nv=nv0 f=fbase+f 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<=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)<=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<=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 checkq(n,lp(1),nmi,kmax,g,a,la,x,bl,bu,r,ls,ws(nb1), ! f,ws,lws,ninf,peq,k,1,p,rp,linear) 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) then ifail=11 return end if ! call iexch(ls(pj),ls(qj)) if (iprint>=1) write(nout,*)'failure detected in pivot (4)' ! 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)<=tol)ri=0.D0 r(i)=ri end do f=ff ! exchange a constraint r(p)=alpha if (r(p)<=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<=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 subroutine stmapq(n,nm,kmax,maxg) ! set storage map for workspace in qlcpd 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 gdotx ! 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 qlcpd kkk=nm+n+maxg*(maxg+1)/2+maxg*(kmax+5) ! integer storage (lws) ! locations 1:ll are user workspace for gdotx ! number of integer locations required by qlcpd lll=0 ! remaining space for use by denseL.f or schurQR.f ll1=ll+1 return end subroutine setfg2(n,linear,a,la,x,f,g,ws,lws) implicit double precision (a-h,o-z) logical linear dimension a(*),la(*),x(*),g(*),ws(*),lws(*) common/noutc/nout if (linear) then do i=1,n g(i)=0.D0 end do call saipy(1.D0,a,la,0,g,n) f=scpr(0.D0,x,g,n) else call gdotx(n,x,ws,lws,g) call saipy(1.D0,a,la,0,g,n) f=5.D-1*scpr(aiscpr(n,a,la,0,x,0.D0),g,x,n) end if 1 format(A,15I4) 2 format(A,5E15.7) 3 format(A/(20I4)) 4 format(A/(5E15.7)) return end subroutine checkq(n,nm,nmi,kmax,g,a,la,x,bl,bu,r,ls,an,f, & ws,lws,ninf,peq,k,lev,p,alp2,linear) implicit double precision (a-h,r-z), integer (i-q) dimension g(*),a(*),la(*),x(*),bl(*),bu(*),r(*),ls(*), & an(*),ws(*),lws(*) common/noutc/nout common/epsc/eps,tol,emin logical linear ! 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<=n) then ! an(i)=an(i)-e ! else ! call saipy(-e,a,la,i-n,an,n) ! end if ! goto 10 ! 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 write(nout,*)'j,peq =',j,peq stop end if end do do j=n-k+1,n i=ls(j) if (i<=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<=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)<=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 (ninf==0) then call setfg2(n,linear,a,la,x,ff,an,ws,lws) 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 10 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<=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 ! write(nout,*)'KT condition error = ',e,je,ie,gnm 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 1 format(A,15I4) 2 format(A,5E15.7) 3 format(A/(20I4)) 4 format(A/(5E15.7)) return end