subroutine dysave (n,y,s,ys,m,nys,jmin,jmax,ybar,sbar,select, 2 & iiter,ol,jol,nu,size,mode,plev,io,izs, & rzs,dzs) c integer n,m,select,nys,jmin,jmax,iiter,jol(m),mode,plev,io,izs(1) real rzs(1) double precision y(n),s(n),ys,ybar(n,m),sbar(n,m),ol(m),nu, & size,dzs(1) c c---- c c Save a pair (y,s)/sqrt(ys) in YBAR and SBAR and update the c Oren-Luenberger factor OLFACT. c c Input: c c ys: Euclidean scalar product (y,s). Must be positive. c nys: number of (y,s) pairs having been received. Must be c initialized to 0 before calling dysave for the first time. c select monitors the selection of the pairs (y,s) to build the c l-BFGS preconditioning matrix, with the following meanings: c =0: no particular selection, FIFO policy c =1: mexican selection (the pairs are distributed uniformely c on the iteration counter iiter for a particular CG run, c at each new run the previous pairs are discarded and a c new l-bfgs matrix is build from scratch) c =2: selection by the Rayleigh quotient; the aim is to obtain c uniformely distributed OL factors in the logarithmic c scale c iiter: integer giving the index of the current inner iteration c when dysave is called. c jol(m): jol(i) is the index of the pair (y,s) with the i-th c smallest OL factor. c nu = epsilon for detecting negative curvature directions, c whose square root is used for selecting good pairs. c size: scalar preconditioner. c c Output: c c mode: output mode c =-1: the (y,s) pair is not selected c =0 : good call, c =1 : the number m of pairs that can be stored in (ybar,sbar) c is <= 0. c =2 : ys <= 0. c =3 : unknown value of select c c---- c c --- local variables c integer i,i2,j,jcour,odiff double precision rmin,r,olf,olmed,oldq,newq,ol0,ol1,ol2, & ol3,olx,olvar,olvar1,olvar2 c c --- check the input c if (m.le.0) then mode=1 if (plev.ge.1) write (io,900) m return endif 900 format (/" dysave-ERROR: non positive number of updates m = ",i5) c if (ys.le.0.d0) then mode=2 if (plev.ge.1) write (io,901) ys 901 format (/" dysave-ERROR: non positive scalar product", & " (y,s) = ",1pd12.5) return endif c c --- initialization c mode=0 rmin=1.d-20 c c --- Oren-Luenberger factor c c call deuclid (n,y,y,olf,izs,rzs,dzs) c olf=ys/olf c c for a quadratic function, I prefer c call deuclid (n,s,s,olf,izs,rzs,dzs) olf=olf/ys c> print *,"olf=",olf if (plev.ge.5) write (io,902) olf 902 format (/4x,"dysave: inverse Oren-Luenberger factor: ", & "|s|^2/(y,s) = ",1pd10.3) c c --- select the pair to discard if any and update the pointers c c --- is this a good pair to save ? c if (select.ge.0 .and. olf.lt.sqrt(nu)) then mode=-1 return endif c c --- accept any pair, discard the oldest one c if (select.eq.0) then if (nys.eq.0) then jmin=1 jmax=0 endif nys=nys+1 jmax=jmax+1 if (jmax.gt.m) jmax=jmax-m if (nys.gt.m) then jmin=jmin+1 if (jmin.gt.m) jmin=jmin-m endif jcour=jmax ol(jcour)=olf c c --- mexican selection c elseif (select.eq.1) then if (iiter.eq.1) nys=0 if (nys.eq.0) then jmin=1 jmax=0 do i=1,m jol(i)=0 enddo endif nys=nys+1 if (nys.le.m) then jmax=jmax+1 jol(jmax)=iiter jcour=jmax elseif (m.eq.2) then jol(2)=iiter jcour=2 elseif (m.gt.2) then c c --- reject current pair if iiter is too close to jol(m-1) c jol gives the iteration number of the selected pairs c they are supposed to be in order of iteration c here jmin=1 and jmax=m (always) c odiff=jol(m)-jol(m-1) if (iiter-jol(m) .lt. odiff) then mode=-1 return endif c c --- select the pair jcour to discard c do j=1,m-1 jcour=j+1 if (jol(jcour)-jol(j) .eq. odiff) goto 10 enddo 10 continue c c --- shift the other (ybar,sbar) and jol c>>>>>>>>>>>> playing with pointers instead of with the actual pairs c would yield a saving in time (TO DO if the selection is c efficient) c do j=jcour+1,m jol(j-1)=jol(j) do i=1,n ybar(i,j-1)=ybar(i,j) sbar(i,j-1)=sbar(i,j) enddo enddo jol(m)=iiter jcour=m endif ol(jcour)=olf c print *,"jol=",(jol(i),i=1,m) c c --- selection by the Rayleigh quotient c elseif (select.eq.2) then c c>>>>>>>> the following should be changed in the futur so that a c matrix build in a previous CG run could be updated (TO DO) c if (iiter.eq.1) nys=0 if (nys.eq.0) then jmin=1 jmax=0 do i=1,m jol(i)=0 enddo endif c c --- it remains to set nys, jmax, jcour, ol(), and jol() c if (m.eq.1) then nys=1 jmax=1 jcour=1 ol(1)=olf jol(1)=1 elseif (nys.lt.m) then c c --- select the current pair, since there is enough space c to save it c jmax=jmax+1 jcour=jmax ol(jcour)=olf c c --- it remains to set jol(); for this, sort the saved c pairs according to their OL factor c if (nys.eq.0) then jol(1)=1 else c c --- find the smallest index i2 such that c ol(jol(i2)) >= olf, this is the position of the c current OLF c i2=1 101 continue if (ol(jol(i2)).ge.olf) goto 102 i2=i2+1 if (i2.le.nys) goto 101 102 continue c c --- shift jol(i), for i>=i2 c if (i2.le.nys) then do i=nys,i2,-1 jol(i+1)=jol(i) enddo endif jol(i2)=jcour endif nys=nys+1 c else c c --- here, if the current (y,s) is selected, an older one c must be discarded; c c here, nys>=m (updated at the end of the ELSE), jmax=m c (no longer udated); it remains to set jcour (inside c the long if-then-else below and ol(jcour)=olf (at the c end of the ELSE); c c start by finding the smallest index i2 such that c ol(jol(i2)) >= olf, this is the position of the c current OLF c i2=1 103 continue if (ol(jol(i2)).ge.olf) goto 104 i2=i2+1 if (i2.le.m) goto 103 104 continue if (i2.eq.1) then c c --- olf is smaller than all the other OL factors c ==> save the (y,s) pair c jcour=jol(1) elseif (i2.gt.m) then c c --- olf is greater than all the other OL factors c ==> save the (y,s) pair c jcour=jol(m) elseif (m.eq.2) then c c --- reject the (y,s) pair, since when m=2, we want to c save the pairs with the extreme OL factors c mode=-1 return elseif (i2.eq.2) then c c --- check whether to replace the pair jol(2), by c looking at jol(1), jol(2), and jol(3) c olmed=sqrt(ol(jol(1))*ol(jol(3))) oldq=ol(jol(2))/olmed if (oldq.lt.1.d0) oldq=1.d0/oldq newq=olf/olmed if (newq.lt.1.d0) newq=1.d0/newq if (newq.ge.oldq) then mode=-1 return endif jcour=jol(2) elseif (i2.eq.m) then c c --- check whether to replace the pair jol(m-1), by c looking at jol(m-2), jol(m-1), and jol(m) c olmed=sqrt(ol(jol(m-2))*ol(jol(m))) oldq=ol(jol(m-1))/olmed if (oldq.lt.1.d0) oldq=1.d0/oldq newq=olf/olmed if (newq.lt.1.d0) newq=1.d0/newq if (newq.ge.oldq) then mode=-1 return endif jcour=jol(m-1) else c c --- here m>=4; c check whether to replace the pair jol(i2-1) or c jol(i2), by looking at jol(i2-2), jol(i2-1), c jol(i2), and jol(i2+1) c ol0=log(ol(jol(i2-2))) ol1=log(ol(jol(i2-1))) ol2=log(ol(jol(i2))) ol3=log(ol(jol(i2+1))) olx=log(olf) olvar =max(ol1-ol0,ol2-ol1,ol3-ol2) olvar1=max(olx-ol0,ol2-olx,ol3-ol2) olvar2=max(ol1-ol0,olx-ol1,ol3-olx) if (olvar.le.min(olvar1,olvar2)) then mode=-1 return elseif (olvar1.lt.olvar2) then jcour=jol(i2-1) else jcour=jol(i2) endif endif c c --- save the pair c nys=nys+1 ol(jcour)=olf endif c> print *," " c> print *,(ol(i),i=1,min(nys,m)) c> print *,"jol=",(jol(i),i=1,min(nys,m)) c> write(6,999) (ol(jol(i)),i=1,min(nys,m)) c> 999 format (1pe12.6,2x,50(e12.6,2x)) else c c --- unknown value of select c mode=3 if (plev.ge.1) write (io,903) select 903 format (/" dysave-ERROR: unknown selection procedure," & ," select = ",i5) return endif c c --- store ybar et sbar c r=sqrt(1.d0/ys) do i=1,n ybar(i,jcour)=r*y(i) sbar(i,jcour)=r*s(i) enddo c c --- save the OL factor c c --- the simplest strategy is to take the OL factor at the c first CG iteration (the function is supposed to be c quadratic) c if (nys.eq.1) size=olf c c --- another strategy is to take the geometric means of the c previous OL factors (taking the d'OL factor, the closest c in the logarithmic scale to this geometric means give c approximately the same results) c olmed=1.d0 do j=1,min(nys,m) olmed=olmed*ol(j) enddo olmed=olmed**(1.d0/dble(min(nys,m))) size=olmed c print *,"ol=",(ol(j),j=1,min(nys,m)) c print *,"olmed=",olmed c 1000 return end c c--------0---------0---------0---------0---------0---------0---------0-- c