MODULE ldgbm_mod ! Limited memory discrete gradient bundle method USE r_precision, ONLY : prec ! Precision for reals. IMPLICIT NONE ! MODULE ldgbm_mod includes the following subroutines (S) and functions (F). PUBLIC :: & init_ldgbm, & ! S Initialization for LDGBM subroutine. ldgbm ! S LDGBM subroutine for nonsmooth moderate and large- ! scale optimization. Contains: ! S restar Initialization and reinitialization. ! S dobun Bundle construction. PRIVATE :: & indic1, & ! S Initialization of indices. tinit, & ! S Calculation of initial step size. Contains: ! S destep Stepsize selection using polyhedral ! approximation for descent steps. ! S nulstep Stepsize selection using polyhedral ! approximation for null steps. ldgbm_lls, & ! S Line search. Contains: ! F qint Quadratic interpolation. ldgbm_dlbfgs, & ! S Computing the search direction by limited memory ! BFGS update. Contains: ! F ldgbm_sclpar Selection of scaling parameter. dlsr1, & ! S Computing the search direction by limited ! memory SR1 update. agbfgs, & ! S Simplified subgradient aggregation. aggsr1, & ! S Subgradient aggregation. ldgbm_wprint, & ! S Printout the error and warning messages. ldgbm_rprint ! S Printout the results. CONTAINS !*********************************************************************** !* * !* * SUBROUTINE init_ldgbm * * !* * !* Initialization for limited memory discrete gradient bundle * !* subroutine for unconstrained nonsmooth optimization. * !* * !*********************************************************************** SUBROUTINE init_ldgbm(mc,iterm) USE param, ONLY : zero,half,small,large USE initializat, ONLY : & n, & ! Number of variables. na, & ! Maximum bundle dimension, na >= 2. mcu, & ! Upper limit for maximum number of stored corrections, mcu >= 3. iprint, & ! Printout specification (see initializat for more details). iscale, & ! Selection of the scaling (see initializat for more details). tolf, & ! Tolerance for change of function values. tolf2, & ! Second tolerance for change of function values. tolb, & ! Tolerance for the function value. tolg, & ! Tolerance for the first termination criterion. tolg2, & ! Tolerance for the second termination criterion. xmax, & ! Maximum stepsize, 1 < XMAX. eta, & ! Distance measure parameter, eta >= 0. epsl, & ! Line search parameter, 0 < epsl < 0.25. mtesf, & ! Maximum number of iterations with changes of ! function values smaller than tolf. mit, & ! Maximun number of iterations. mfe ! Maximun number of function evaluations. IMPLICIT NONE ! Scalar Arguments INTEGER, INTENT(INOUT) :: mc ! Initial maximum number of stored corrections. INTEGER, INTENT(OUT) :: iterm ! Cause of termination: ! 0 - Everything is ok. ! -5 - Invalid input parameters. ! Initialization and error checking IF (iprint < -1) iprint = 1 ! Printout specification. iterm = 0 IF (n <= 0) THEN iterm = -5 CALL ldgbm_wprint(iterm,iprint,1) RETURN END IF IF (na < 2) THEN iterm = -5 CALL ldgbm_wprint(iterm,iprint,3) RETURN END IF IF (epsl >= 0.25_prec) THEN iterm = -5 CALL ldgbm_wprint(iterm,iprint,4) RETURN END IF IF (mcu <= 3) THEN iterm = -5 CALL ldgbm_wprint(iterm,iprint,2) RETURN END IF IF (mc > mcu) THEN mc = mcu CALL ldgbm_wprint(iterm,iprint,-1) END IF ! Default values IF (mc <= 0) mc = 3 ! Initial maximum number of corrections. IF (mit <= 0) mit = 10000 ! Maximum number of iterations. IF (mfe <= 0) mfe = mit*n ! Maximum number of function evaluations. IF (tolf <= zero) tolf = 1.0E-08_prec ! Tolerance for change of function values. IF (tolf2 == zero) tolf2 = 1.0E+04_prec ! Second tolerance for change of function values. IF (tolb == zero) tolb = -large + small ! Tolerance for the function value. IF (tolg <= zero) tolg = 1.0E-06_prec ! Tolerance for the first termination criterion. IF (tolg2 <= zero) tolg2 = tolg ! Tolerance for the second termination criterion. IF (xmax <= zero) xmax = 1.5_prec ! Maximum stepsize. IF (eta < zero) eta = half ! Distance measure parameter IF (epsl <= zero) epsl = 1.0E-04_prec ! Line search parameter, IF (mtesf <= 0) mtesf = 10 ! Maximum number of iterations with changes ! of function values smaller than tolf. IF (iscale > 6 .OR. iscale < 0) iscale = 0 ! Selection of the scaling. END SUBROUTINE init_ldgbm !*********************************************************************** !* * !* * SUBROUTINE ldgbm * * !* * !* Limited memory discrete gradient bundle subroutine * !* for nonsmooth optimization. * !* * !*********************************************************************** SUBROUTINE ldgbm(mc,f,noutit,nit,nfe,iterm,strtim) USE param, ONLY : small,large,zero,half,one USE exe_time, ONLY : getime ! Execution time. USE initializat, ONLY : & n, & ! Number of variables. x, & ! Vector of variables na, & ! Maximum bundle dimension, na >= 2. mcu, & ! Upper limit for maximum number of stored corrections, mcu >= 3. iprint, & ! Printout specification (see initializat for more details). iscale, & ! Selection of the scaling (see initializat for more details). tolf, & ! Tolerance for change of function values. tolf2, & ! Second tolerance for change of function values. tolb, & ! Tolerance for the function value. tolg, & ! Tolerance for the first termination criterion. tolg2, & ! Tolerance for the second termination criterion. xmax, & ! Maximum stepsize, 1 < XMAX. eta, & ! Distance measure parameter, eta >= 0. epsl, & ! Line search parameter, 0 < epsl < 0.25. mtesf, & ! Maximum number of iterations with changes of ! function values smaller than tolf. mit, & ! Maximun number of iterations. mfe, & ! Maximun number of function evaluations. time ! Maximum time USE obj_fun, ONLY : & myf ! Computation of the value of the objective function. USE lmbm_sub, ONLY : & vdot, & ! Dot product. vneg, & ! Copying of a vector with change of the sign. xdiffy, & ! Difference of two vectors. copy, & ! Copying of a vector. copy2 ! Copying of two vectors. IMPLICIT NONE ! Scalar Arguments REAL(KIND=prec), INTENT(OUT) :: & f ! Value of the objective function. INTEGER, INTENT(OUT) :: & noutit, & ! Number of outer iterations. nit,nfe ! Number of iterations and function evaluations. INTEGER, INTENT(INOUT) :: & mc ! Maximum number of stored corrections. INTEGER, INTENT(OUT) :: & iterm ! Cause of termination: ! 1 - The problem has been solved with desired accuracy. ! 2 - Changes in function values < tolf in mtesf ! subsequent iterations. ! 3 - Changes in function value < tolf*small*MAX(|f_k|,|f_(k-1)|,1), ! where small is the smallest positive number such that ! 1.0 + small > 1.0. ! 4 - Number of function calls > mfe. ! 5 - Number of iterations > mit. ! 6 - Time limit exceeded. ! 7 - f < tolb. ! -1 - Two consecutive restarts. ! -2 - Number of restarts > maximum number of restarts. ! -3 - Failure in function or subgradient calculations ! (assigned by the user). ! -4 - Failure in attaining the demanded accuracy. ! -5 - Invalid input parameters. ! -6 - Unspecified error. ! Local Arrays REAL(KIND=prec), DIMENSION(n) :: & xo, & ! Previous vector of variables. dg, & ! discrete gradient of the objective function. dgp, & ! Previous discrete gradient of the ohjective function. dga, & ! Aggregate discrete gradient. s, & ! Difference of current and previous variables. u, & ! Difference of current and previous discrete gradients. d, & ! Direction vector. tmpn1 ! Auxiliary array. REAL(KIND=prec), DIMENSION(n*(mcu+1)) :: & sm,um ! Matrises whose columns are stored differences of ! variables (sm) and discrete gradients (um). REAL(KIND=prec), DIMENSION((mcu+2)*(mcu+1)/2) :: & rm, & ! pper triangular matrix stored columnwise in the ! one-dimensional array. umtum ! Matrix whose columns are stored discrete gradient differences. REAL(KIND=prec), DIMENSION(mcu+1) :: & cm, & ! Diagonal matrix. smtgp, & ! smtgp = trans(sm)*dgp. umtgp, & ! umtgp = trans(um)*dgp. tmpmc1, & ! Auxiliary array. tmpmc2 ! Auxiliary array. REAL(KIND=prec), DIMENSION(n*na) :: & ax,ag ! Matrix whose columns are bundle points and discrete gradients. REAL(KIND=prec), DIMENSION(na) :: & af ! Vector of bundle values. ! Local Scalars REAL(KIND=prec) :: & delta, & ! Outer iteration parameter. sl, & ! Size parameter for discrete gradient. pwt, & ! Parameter for discrete gradient. sigma, & ! Acceleration multiplier for outer iteration parameter. alfn, & ! Locality measure. alfv, & ! Aggregate locality measure. epsr, & ! Line search parameter. dnorm, & ! Euclidean norm of the direction vector. gnorm, & ! Euclidean norm of the aggregate subgradient. xnorm, & ! Stopping criterion. pxnorm, & ! Previous stopping criterion. p, & ! Directional derivative. tmax, & ! Maximum stepsize. t, & ! Stepsize. theta, & ! Correction parameter for stepsize. fo, & ! Previous value of the objective. gamma, & ! Scaling parameter. slout, & ! tmp ! Auxiliary value. INTEGER :: i, & mcinit, & ! Initial maximum number of stored corrections. mcc, & ! Current number of stored corrections. inew, & ! Index for the circular arrays. ibfgs, & ! Index of the type of BFGS update. isr1, & ! Index of the type of SR1 update. iters, & ! Null step indicator. ! 0 - Null step. ! 1 - Serious step. nnk, & ! Consecutive null steps counter. ibun, & ! Index for the circular arrays in bundle updating. mal, & ! Current size of the bundle. ic, & ! Correction indicator. icn, & ! Correction indicator for null steps. iflag, & ! Index for adaptive version. neps, & ! Number of consecutive equal stopping criterions. ntesf, & ! Number of tests on function decrease. ncres, & ! Number of restarts. nres, & ! Number of consecutive restarts. nress, & ! Number of consecutive restarts in case of tmax < tmin. nout, & ! Auxilary printout specification. ngrad ! Number of discrete gradient calls. ! Intrinsic Functions INTRINSIC ABS,MAX,SQRT ! Computational Time REAL strtim,elapstim ! Parameters REAL(KIND=prec), PARAMETER :: & fmin = -large, & ! Smallest acceptable value of the function. tmin = 1.0E-12_prec, & ! Minimum stepsize. slmin = 1.0E-6_prec, & ! Minimum size parameter for the discrete gradient. lengthd = 1.0E+20_prec, & ! Direction vector length. rho = 1.0E-12_prec ! Correction parameter. INTEGER, PARAMETER :: & maxeps = 10, & ! Maximum number of consecutive equal stopping criterions. maxnrs = 2000 ! Maximum number of restarts. IF (iprint > 3) WRITE (6,FMT='(1X,''Entry to LDGBM:'')') ! Initialization nout = 0 nit = 0 nfe = 0 ntesf = 0 nres = 1 ncres = -1 nress = 0 neps = 0 iterm = 0 iters = 1 nnk = 0 isr1 = 0 alfn = zero alfv = zero mcinit = mc tmax = xmax xnorm = large epsr = 0.25_prec+small IF (epsl+epsl >= epsr) THEN epsr = epsl+epsl + small IF (epsr >= half) THEN CALL ldgbm_wprint(iterm,iprint,-2) END IF END IF ! Outer iteration tmp = one/SQRT(REAL(n, kind=prec)) ! ngrad = 0 noutit = 0 pwt = 1.0E-08_prec ! slout = 1.25E+0_prec sigma = 1.0E-1_prec ! ! sigma = 2.0E-1_prec ! delta = 1.0E+6_prec ! ! delta = n*n outer_iteration: DO WHILE (delta > tolg*sigma) ! iterm is the latest cause of stopping ! ! if it is positive everything is ok. sl = max(2.0E-1_prec * slout,slmin) ! slout = sl noutit = noutit + 1 iterm = 0 iters = 1 ntesf = 0 neps = 0 nres = 1 nress = 0 ! First direction for the discrete gradient DO i=1,n tmpn1(i)=tmp END DO ! Computation of the value and the discrete gradient of the objective ! function and the search direction for the first iteration CALL myf(n,x,f,iterm) nfe = nfe + 1 CALL dgrad(n,x,sl,tmpn1,dg,f,ngrad,nfe,pwt,iterm) IF (iterm /= 0) EXIT outer_iteration CALL restar(n,mc,mcc,mcinit,inew,ibun,ibfgs,iters,dgp,dg,nnk, & alfv,alfn,gamma,d,ic,icn,mal,ncres,iflag) CALL dobun(n,na,mal,x,dg,f,ax,ag,af,iters,ibun) ! Start of the inner iteration inner_iteration: DO ! Computational time IF (time > 0.0E+00) THEN CALL getime(elapstim) IF (elapstim-strtim > time) THEN iterm = 6 EXIT outer_iteration ! Time limit exeeded, real exit END IF END IF ! Computation of norms IF (iters > 0) THEN gnorm = vdot(n,dg,dg) dnorm = SQRT(vdot(n,d,d)) p = vdot(n,dg,d) ELSE gnorm = vdot(n,dga,dga) dnorm = SQRT(vdot(n,d,d)) p = vdot(n,dga,d) END IF ! Test on descent direction IF (p+small*SQRT(gnorm)*dnorm <= zero) THEN nres = 0 ELSE nres = nres + 1 IF (nres == 1) THEN CALL ldgbm_wprint(iterm,iprint,-3) CALL restar(n,mc,mcc,mcinit,inew,ibun,ibfgs,iters,dgp,dg,nnk, & alfv,alfn,gamma,d,ic,icn,mal,ncres,iflag) IF (ncres > maxnrs) THEN nout = maxnrs iterm = -2 EXIT outer_iteration ! real exit END IF CALL dobun(n,na,mal,x,dg,f,ax,ag,af,iters,ibun) CYCLE inner_iteration END IF nout = -1 iterm = -1 EXIT outer_iteration ! real exit END IF ! Stopping criterion nit = nit + 1 pxnorm = xnorm xnorm = -p + alfv + alfv ! Tests for termination IF (xnorm <= 1.0E+03_prec*delta .AND. (mcc > 0 .OR. ibfgs == 2)) THEN IF(xnorm <= delta) THEN ! IF(half*gnorm + alfv <= delta .AND. xnorm <= delta) THEN ! More accurate results iterm = 1 EXIT inner_iteration END IF IF (mc < mcu .AND. iflag == 0) THEN mc = mc+1 iflag = 1 END IF END IF IF (nfe >= mfe) THEN nout = mfe iterm = 4 EXIT outer_iteration ! real exit END IF IF (nit >= mit) THEN nout = mit iterm = 5 EXIT outer_iteration ! Real exit END IF IF (f <= tolb) THEN iterm = 7 EXIT outer_iteration ! Unbounded minima, real exit END IF IF (iters == 0) THEN IF (ABS(xnorm - pxnorm) <= small) THEN neps = neps + 1 IF (neps > maxeps) THEN iterm = -4 EXIT inner_iteration ! try again with different delta END IF ELSE neps = 0 END IF ELSE neps = 0 END IF ! Correction IF (-p < rho*gnorm .OR. icn == 1) THEN xnorm = xnorm + rho*gnorm dnorm = SQRT(dnorm*dnorm-2.0_prec*rho*p+rho*rho*gnorm) IF (iters > 0) THEN DO i=1,n d(i) = d(i)-rho*dg(i) END DO ELSE DO i=1,n d(i) = d(i)-rho*dga(i) END DO icn = 1 END IF ic = 1 ELSE ic = 0 END IF IF (pxnorm < xnorm .AND. nnk > 2) THEN CALL ldgbm_wprint(iterm,iprint,-4) END IF CALL ldgbm_rprint(n,noutit,nit,nfe,ngrad,x,f,xnorm,half*gnorm+alfv,iterm,iprint) ! Preparation of line search fo = f IF (iters > 0) THEN CALL copy2(n,x,xo,dg,dgp) END IF IF (dnorm > zero) tmax = MAX(xmax/dnorm,sl) ! Initial step size CALL tinit(n,na,mal,x,af,ag,ax,ibun,d,f,p,t,tmax,tmin, & eta,iters,iterm) IF (iterm /= 0) EXIT outer_iteration ! Real exit ! Line search with directional derivatives which allows null steps theta = one IF (dnorm > lengthd) THEN theta=lengthd/dnorm END IF CALL ldgbm_lls(n,x,dg,d,xo,t,fo,f,p,alfn,sl,pwt,tmin,dnorm,xnorm, & theta,epsl,epsr,eta,iters,nfe,ngrad,nnk,iterm) IF (iterm /= 0) EXIT outer_iteration ! Real exit IF (tolf2 >= 0) THEN IF (ABS(fo-f) <= tolf2*small*MAX(ABS(f),ABS(fo),one) & .AND. iters == 1) THEN iterm = 3 EXIT inner_iteration END IF END IF IF (ABS(fo-f) <= tolf) THEN ntesf = ntesf + 1 if (ntesf >= mtesf .AND. iters == 1) THEN iterm = 2 EXIT inner_iteration END IF ELSE ntesf = 0 END IF ! Bundle updating CALL dobun(n,na,mal,x,dg,f,ax,ag,af,iters,ibun) ! Computation of variables difference CALL xdiffy(n,x,xo,s) ! Computation of aggregate values and gradients difference IF (iters == 0) THEN nnk = nnk + 1 IF (nnk == 1) THEN CALL copy(n,dgp,tmpn1) CALL xdiffy(n,dg,dgp,u) CALL agbfgs(n,mc,mcc,inew,ibfgs,iflag,dg,dgp,dga,u,d,sm,um, & rm,cm,umtum,alfn,alfv,gamma,ic,rho) ELSE CALL copy(n,dga,tmpn1) CALL aggsr1(n,mc,mcc,inew,iflag,dg,dgp,dga,d,alfn,alfv & ,umtum,rm,gamma,smtgp,umtgp,tmpmc1,tmpmc2,sm & ,um,icn,rho) CALL xdiffy(n,dg,dgp,u) END IF CALL copy(n,xo,x) f = fo ELSE IF (nnk /= 0) THEN CALL copy(n,dga,tmpn1) ELSE CALL copy(n,dgp,tmpn1) END IF nnk = 0 CALL xdiffy(n,dg,dgp,u) END IF ! Serious step initialization IF (iters > 0) THEN sl = MAX(slmin,half*sl) ! icn = 0 alfn = zero alfv = zero END IF ! Direction finding IF (iters > 0) THEN ! BFGS update and direction determination CALL ldgbm_dlbfgs(n,mc,mcc,inew,ibfgs,iflag,d,dg,dgp,s,u,sm,um,rm, & umtum,cm,smtgp,umtgp,gamma,tmpn1,iscale) ELSE ! SR1 update and direction determination CALL dlsr1(n,mc,mcc,inew,isr1,iflag,d,dgp,dga,s,u,sm,um,rm, & umtum,cm,smtgp,umtgp,gamma,tmpmc1,tmpmc2,tmpn1,nnk,iprint) ibfgs=0 END IF END DO inner_iteration delta = MIN(delta*sigma,xnorm) END DO outer_iteration ! Printout the final results IF (iprint > 3) THEN WRITE (6,FMT='(1X,''Exit from LDGBM:'')') END IF CALL ldgbm_wprint(iterm,iprint,nout) CALL ldgbm_rprint(n,noutit,nit,nfe,ngrad,x,f,xnorm,half*gnorm+alfv,iterm,iprint) CONTAINS SUBROUTINE restar(n,mc,mcc,mcinit,inew,ibun,ibfgs,iters,gp,g,nnk, & alfv,alfn,gamma,d,ic,icn,mal,ncres,iflag) ! Initialization ! USE param, ONLY : zero,one ! given in host ! USE lmbm_sub, ONLY : vneg,copy ! given in host IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & gp ! Basic subgradient of the objective function. REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & g ! Current (auxiliary) subgradient of the objective function. REAL(KIND=prec), DIMENSION(:), INTENT(OUT) :: & d ! Search direction. ! Scalar Arguments INTEGER, INTENT(IN) :: & n, & ! Number of variables mcinit ! Initial maximum number of stored corrections. INTEGER, INTENT(OUT) :: & mc, & ! Current maximum number of stored corrections. mcc, & ! Current number of stored corrections. inew, & ! Index for the circular arrays. ibun, & ! Index for the circular arrays in bundle updating. ibfgs, & ! Index of the type of BFGS update. nnk, & ! Consecutive null steps counter. ic, & ! Correction indicator. icn, & ! Correction indicator for null steps. mal, & ! Current size of the bundle. iflag ! Index for adaptive version. INTEGER, INTENT(INOUT) :: & iters, & ! Null step indicator. ! 0 - Null step. ! 1 - Serious step. ncres ! Number of restarts. REAL(KIND=prec), INTENT(OUT) :: & alfn, & ! Locality measure. alfv, & ! Aggregate locality measure. gamma ! Scaling parameter. ! Restart mc = mcinit mcc = 0 inew = 1 ibun = 1 ibfgs = 0 ic = 0 icn = 0 mal = 0 ncres = ncres + 1 iflag = 0 IF (iters == 0) THEN CALL copy(n,gp,g) iters = 1 nnk = 0 alfv=zero alfn=zero END IF gamma = one CALL vneg(n,g,d) END SUBROUTINE restar SUBROUTINE dobun(n,ma,mal,x,g,f,ay,ag,af,iters,ibun) ! Bundle construction ! USE lmbm_sub, ONLY : copy2 ! given in host IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & x, & ! Vector of variables g ! Subgradient of the objective function. REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & ay, & ! Matrix whose columns are bundle points ! (stored in one-dimensional n*ma -array). ag, & ! Matrix whose columns are bundle subgradients ! (stored in one-dimensional n*ma -array). af ! Vector of values of bundle functions ! (stored in one-dimensional ma -array). ! Scalar Arguments INTEGER, INTENT(IN) :: & n, & ! Number of variables iters, & ! Null step indicator. ! 0 - Null step. ! 1 - Serious step. ma ! Maximum size of the bundle. INTEGER, INTENT(INOUT) :: & ibun, & ! Index for the circular arrays in bundle updating. mal ! Current size of the bundle. REAL(KIND=prec), INTENT(IN) :: & f ! Value of the objective function. ! Local Scalars INTEGER :: i,j IF (iters == 1) THEN ! Serious step af(ibun) = f i = (ibun-1)*n + 1 CALL copy2(n,g,ag(i:),x,ay(i:)) ELSE ! Null step IF (mal < ma) THEN af(ibun) = af(mal) af(mal) = f i = mal*n + 1 CALL copy2(n,ag(i-n:),ag(i:),ay(i-n:),ay(i:)) CALL copy2(n,g,ag(i-n:),x,ay(i-n:)) ELSE i = ibun-1 IF (i < 1) i = mal af(ibun) = af(i) af(i) = f i = (ibun-2)*n + 1 IF (i < 1) i = (mal-1)*n + 1 j = (ibun-1)*n + 1 CALL copy2(n,ag(i:),ag(j:),ay(i:),ay(j:)) CALL copy2(n,g,ag(i:),x,ay(i:)) END IF END IF mal = mal + 1 IF (mal > ma) mal = ma ibun = ibun + 1 IF (ibun > ma) ibun = 1 END SUBROUTINE dobun END SUBROUTINE ldgbm !************************************************************************ !* * !* * SUBROUTINE tinit * * !* * !* Initial stepsize selection for limited memory bundle method * !* * !************************************************************************ SUBROUTINE tinit(n,na,mal,x,af,ag,ay,ibun,d,f,p,t,tmax,tmin,eta,iters,iterm) USE param, ONLY : zero,half,one,large ! half and large are used in destep and nulstep IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & x, & ! Vector of variables (n array). d, & ! Direction vector (n array). ay, & ! Matrix whose columns are bundle points (stored in one-dimensional n*ma -array). ag ! Matrix whose columns are bundle subgradients (stored in one-dimensional n*ma -array). REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & af ! Vector of values of bundle functions (stored in one-dimensional ma -array). ! Scalar Arguments REAL(KIND=prec), INTENT(OUT) :: & t ! Initial stepsize REAL(KIND=prec), INTENT(IN) :: & p, & ! Directional derivative. eta, & ! Distance measure parameter. f, & ! Value of the objective function. tmax, & ! Upper limit for stepsize parameter. tmin ! Lower limit for stepsize parameter. INTEGER, INTENT(IN) :: & n, & ! Number of variables na, & ! Maximum size of the bundle. mal, & ! Current size of the bundle. ibun, & ! Index for the circular arrays in bundle updating. iters ! Null step indicator. ! 0 - Null step. ! 1 - Serious step. INTEGER, INTENT(OUT) :: & iterm ! Cause of termination: ! 0 - Everything is ok. ! -6 - Error. ! INTEGER :: koe = 1 ! Intrinsic Functions INTRINSIC MAX,MIN t = MIN(one,tmax) IF (p == zero) RETURN IF (iters == 1) THEN CALL destep(n,na,mal,x,af,ag,ay,ibun,d,f,p,t,eta,iterm) ELSE CALL nulstep(n,na,mal,x,af,ag,ay,ibun,d,f,p,t,eta,iterm) END IF t = MIN(MAX(t,tmin),tmax) CONTAINS SUBROUTINE destep(n,ma,mal,x,af,ag,ay,ibun,d,f,df,t,eta,iterm) ! Stepsize selection ! USE param, ONLY : zero,half,one,large ! given in host IMPLICIT NONE ! Scalar Arguments REAL(KIND=prec), INTENT(INOUT) :: & t ! Initial stepsize REAL(KIND=prec), INTENT(IN) :: & df, & ! Directional derivative. eta, & ! Distance measure parameter. f ! Value of the objective function. INTEGER, INTENT(IN) :: & n, & ! Number of variables ma, & ! Maximum size of the bundle. mal, & ! Current size of the bundle. ibun ! Index for the circular arrays in bundle updating. INTEGER, INTENT(OUT) :: & iterm ! Cause of termination: ! 0 - Everything is ok. ! -6 - Error. ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & x, & ! Vector of variables (n array). d, & ! Direction vector (n array). ay, & ! Matrix whose columns are bundle points (stored in one-dimensional n*ma -array). ag, & ! Matrix whose columns are bundle subgradients (stored in one-dimensional n*ma -array). af ! Vector of values of bundle functions (stored in one-dimensional ma -array). ! Local Arrays REAL(KIND=prec), DIMENSION(2*ma) :: & tmparray ! Auxiliary array. ! Local Scalars REAL(KIND=prec) :: alf,alfl,alfr,bet,betl,betr,dx,q,r,w INTEGER :: i,j,jn,k,l,lq,ib ! Intrinsic Functions INTRINSIC ABS,REAL,MAX,MIN,SQRT iterm = 0 alfl = zero betl = zero w = df*t* (one - t*half) ! Initial choice of possibly active lines k = 0 l = -1 jn = (ibun-1)*n betr = - large DO j=1,mal-1 ib = ibun - 1 + j IF (ib > mal) ib = ib - mal IF (jn >= mal*n) jn = jn - mal*n r = zero bet = zero alfl = af(ib) - f DO i=1,n dx = x(i) - ay(jn+i) q = ag(jn+i) r = r + dx*dx alfl = alfl + dx*q bet = bet + d(i)*q END DO alf = MAX(ABS(alfl),eta*r) r = one - bet/df IF (r*r + (alf+alf)/df > 1.0E-6_prec) THEN k = k + 1 tmparray(k) = alf tmparray(ma+k) = bet r = t*bet - alf IF (r > w) THEN w = r l = k END IF END IF betr = MAX(betr,bet-alf) jn = jn + n END DO lq = -1 IF (betr <= df*half) RETURN lq = 1 IF (l <= 0) RETURN betr = tmparray(ma+l) IF (betr <= zero) THEN IF (t < one .OR. betr == zero) RETURN lq = 2 END IF alfr = tmparray(l) ! Iteration loop ds_iteration: DO IF (lq >= 1) THEN q = one - betr/df r = q + SQRT(q*q + (alfr+alfr)/df) IF (betr >= zero) r = - (alfr+alfr)/ (df*r) r = MIN(1.95_prec,MAX(zero,r)) ELSE IF (ABS(betr-betl)+ABS(alfr-alfl)< -1.0E-4_prec*df) RETURN IF (betr-betl == zero) THEN iterm = -6 RETURN END IF r = (alfr-alfl)/ (betr-betl) END IF IF (ABS(t-r) < 1.0E-4_prec) RETURN t = r tmparray(l) = - one w = t*betr - alfr l = -1 DO j = 1,k alf = tmparray(j) IF (alf < zero) EXIT bet = tmparray(ma+j) r = t*bet - alf IF (r > w) THEN w = r l = j END IF END DO IF (l < 0) RETURN bet = tmparray(ma+l) IF (bet == zero) RETURN ! New interval selection alf = tmparray(l) IF (bet < zero) THEN IF (lq == 2) THEN alfr = alf betr = bet ELSE alfl = alf betl = bet lq = 0 END IF ELSE IF (lq == 2) THEN alfl = alfr betl = betr lq = 0 END IF alfr = alf betr = bet END IF END DO ds_iteration END SUBROUTINE destep SUBROUTINE nulstep(n,ma,mal,x,af,ag,ay,ibun,d,f,df,t,eta,iterm) ! Stepsize selection ! USE param, ONLY : zero,half,one,large ! given in host IMPLICIT NONE ! Scalar Arguments REAL(KIND=prec), INTENT(INOUT) :: & t ! Initial stepsize REAL(KIND=prec), INTENT(IN) :: & df, & ! Directional derivative. eta, & ! Distance measure parameter. f ! Value of the objective function. INTEGER, INTENT(IN) :: & n, & ! Number of variables ma, & ! Maximum size of the bundle. mal, & ! Current size of the bundle. ibun ! Index for the circular arrays in bundle updating. INTEGER, INTENT(OUT) :: & iterm ! Cause of termination: ! 0 - Everything is ok. ! -6 - Error. ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & x, & ! Vector of variables (n array). d, & ! Direction vector (n array). ay, & ! Matrix whose columns are bundle points (stored in one-dimensional n*ma -array). ag, & ! Matrix whose columns are bundle subgradients (stored in one-dimensional n*ma -array). af ! Vector of values of bundle functions (stored in one-dimensional 4*ma -array). ! Local Arrays REAL(KIND=prec), DIMENSION(2*ma) :: & tmparray ! Auxiliary array. ! Local Scalars REAL(KIND=prec) :: alf,alfl,alfr,bet,betl,betr,dx,q,r,w INTEGER :: i,j,jn,k,l,ib ! Intrinsic Functions INTRINSIC ABS,REAL,MAX,MIN,SQRT iterm = 0 w = df*t ! Initial choice of possibly active parabolas k = 0 l = -1 jn = (ibun-1)*n betr = - large DO j = 1,mal - 1 ib = ibun - 1 + j IF (ib > mal) ib = ib - mal IF (jn >= mal*n) jn = jn - mal*n bet = zero r = zero alfl = af(ib) - f DO i = 1,n dx = x(i) - ay(jn+i) r = r + dx*dx q = ag(jn+i) alfl = alfl + dx*q bet = bet + d(i)*q END DO alf = MAX(ABS(alfl),eta*r) betr = MAX(betr,bet-alf) IF (alf < bet-df) THEN k = k + 1 r = t*bet - alf tmparray(k) = alf tmparray(ma+k) = bet IF (r > w) THEN w = r l = k END IF END IF jn = jn + n END DO IF (l <= 0) RETURN betr = tmparray(ma+l) alfr = tmparray(l) alf = alfr bet = betr alfl = zero betl = df ! Iteration loop ns_iteration: DO w = bet/df IF (ABS(betr-betl)+ABS(alfr-alfl)< -1.0E-4_prec*df) RETURN IF (betr-betl == zero) THEN iterm = -6 RETURN END IF r = (alfr-alfl)/ (betr-betl) IF (ABS(t-w) < ABS(t-r)) r = w q = t t = r IF (ABS(t-q) < 1.0E-3_prec) RETURN tmparray(l) = - one w = t*bet - alf l = -1 DO j=1,k alf = tmparray(j) IF (alf < zero) EXIT bet = tmparray(ma+j) r = t*bet - alf IF (r > w) THEN w = r l = j END IF END DO IF (l <= 0) RETURN bet = tmparray(ma+l) q = bet - t*df IF (Q == zero) RETURN ! New interval selection alf = tmparray(l) IF (q < zero) THEN alfl = alf betl = bet ELSE alfr = alf betr = bet END IF END DO ns_iteration END SUBROUTINE nulstep END SUBROUTINE tinit !************************************************************************ !* * !* * SUBROUTINE ldgbm_lls * * !* * !* Special line search for limited memory discrete gradient * !* bundle method. * !* * !************************************************************************ SUBROUTINE ldgbm_lls(n,x,dg,d,xo,t,fo,f,p,alfn,sl,pwt,tmin,dnorm,wk,theta,& epsl,epsr,eta,iters,nfe,ngrad,nnk,iterm) USE param, ONLY : zero,half,one USE obj_fun, ONLY : & myf ! Computation of the value of the objective function. USE lmbm_sub, ONLY : & scsum, & ! Sum of a vector and the scaled vector. vdot ! Dot product of vectors. IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & d, & ! Direction vector. xo ! Previous vector of variables. REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & x ! Vector of variables. REAL(KIND=prec), DIMENSION(:), INTENT(OUT) :: & dg ! discrete gradient of the objective function. ! Scalar Arguments REAL(KIND=prec), INTENT(INOUT) :: & epsl,& ! Linesearch parameter. epsr,& ! Linesearch parameter. t, & ! Stepsize p ! Directional derivative. REAL(KIND=prec), INTENT(IN) :: & sl, & pwt, & theta, & ! Scaling parameter. eta, & ! Distance measure parameter. fo, & ! Previous value of the objective function. wk, & ! Stopping parameter. dnorm, & ! Euclidean norm of the direction vector. tmin ! Lower limit for stepsize parameter. REAL(KIND=prec), INTENT(OUT) :: & f, & ! Value of the objective function. alfn ! Locality measure. INTEGER, INTENT(IN) :: & n, & ! Number of variables nnk ! Number of consequtive null steps. INTEGER, INTENT(INOUT) :: & iters, & ! Null step indicator. ! 0 - Null step. ! 1 - Serious step. nfe,ngrad ! Number of function and discrete gradient evaluations. INTEGER, INTENT(OUT) :: & iterm ! Cause of termination: ! 0 - Everything is ok. ! -3 - Failure in function or subgradient calculations. ! Local arrays REAL(KIND=prec), DIMENSION(n) :: & g ! Initial direction. ! Local Scalars REAL(KIND=prec) :: & tl,tu, & ! Lower and upper limits for t used in interpolation. fl,fu, & ! Values of the objective function for t=tl and t=tu. epsa,epst,epslk,epsrk, & ! Line search parameters. thdnorm,epsawk,epstwk,epslwk,epsrwk ! Auxiliary scalars. INTEGER :: i,nin ! Number of interpolations. ! Parameters INTEGER, PARAMETER :: maxint = 200 ! Maximum number of interpolations. ! Intrinsic Functions INTRINSIC ABS,MAX ! Initialization nin = 0 epst = epsl+epsl epsa = half*(epsr - epst) thdnorm = theta*dnorm tl = zero tu = t fl = fo IF (theta < one) THEN epst = theta*epst epsa = theta*epsa epslk = epsl epsl = theta*epsl epsrk = epsr epsr = theta*epsr END IF epsawk = epsa*wk epslwk = epsl*wk epsrwk = epsr*wk epstwk = epst*wk ! Function and gradient evaluation at a new point DO i=1,n g(i)=d(i)/dnorm END DO lls_iteration: DO CALL scsum(n,theta*t,d,xo,x) CALL myf(n,x,f,iterm) nfe = nfe + 1 IF (iterm /= 0) RETURN ! Null/descent step test (ITERS=0/1) iters = 1 IF (f <= fo - t*epstwk) THEN tl = t fl = f ELSE tu = t fu = f END IF ! Additional interpolation IF (f > fo .AND. tu-tl >= tmin*0.1_prec & .AND. nnk >= 1 .AND. nin < maxint) THEN nin=nin+1 IF (tl == zero .AND. wk > zero) THEN t = qint(tu,fl,fu,wk,one-half/(one-epst)) ELSE t = half*(tu+tl) END IF CYCLE lls_iteration END IF CALL dgrad(n,x,sl,g,dg,f,ngrad,nfe,pwt,iterm) IF (iterm /= 0) RETURN p = theta*vdot(n,dg,d) alfn = MAX(ABS(fo-f+p*t),eta*(t*thdnorm)**2) ! Serious step IF (f <= fo - t*epslwk .AND. (t >= tmin .OR. alfn > epsawk)) EXIT lls_iteration ! Null step IF (p-alfn >= -epsrwk .OR. tu-tl < tmin*0.1_prec .OR. & nin >= maxint) THEN iters = 0 EXIT lls_iteration END IF ! Interpolation nin=nin+1 IF (tl == zero .AND. wk > zero) THEN t = qint(tu,fl,fu,wk,one-half/(one-epst)) ELSE t = half*(tu+tl) END IF END DO lls_iteration IF (theta /= one) THEN epsl = epslk epsr = epsrk END IF CONTAINS FUNCTION qint(tu,fl,fu,wk,kappa) RESULT(t) ! Quadratic interpolation ! USE param, ONLY : half,one ! given in host IMPLICIT NONE ! Scalar Arguments REAL(KIND=prec), INTENT(IN) :: & fl, & ! Value of the objective function. fu, & ! Value of the objective function for t=tu. wk, & ! Directional derivative. tu, & ! Upper value of the stepsize parameter. kappa ! Interpolation parameter. REAL(KIND=prec) :: & t ! Stepsize. ! Local Scalars REAL(KIND=prec) :: tmp1,tmp2 ! Intrinsic Functions INTRINSIC MAX tmp1 = (fu-fl)/ (-wk*tu) ! Quadratic interpolation with one directional derivative tmp2 = 2.0_prec * (one - tmp1) IF (tmp2 > one) THEN ! Interpolation accepted t = MAX(kappa*tu,tu/tmp2) RETURN END IF ! Bisection t = half*tu END FUNCTION qint END SUBROUTINE ldgbm_lls !************************************************************************ !* !* * SUBROUTINE ldgbm_dlbfgs * !* !* Matrix update and computation of the search direction d = -dm*g !* by the limited memory BFGS update. !* !************************************************************************ SUBROUTINE ldgbm_dlbfgs(n,mc,mcc,inew,ibfgs,iflag,d,g,gp,s,u,sm,um,rm, & umtum,cm,smtgp,umtgp,gamma,tmpn1,iscale) USE param, ONLY : zero,small,one,half ! half is used at sclpar USE lmbm_sub, ONLY : & vdot, & ! Dot product. vneg, & ! Copying of a vector with change of the sign. xdiffy, & ! Difference of two vectors. xsumy, & ! Sum of two vectors. scdiff, & ! Difference of the scaled vector and a vector. scsum, & ! Sum of a vector and the scaled vector. vxdiag, & ! Multiplication of a vector and a diagonal matrix. symax, & ! Multiplication of a dense symmetric matrix by a vector. cwmaxv, & ! Multiplication of a vector by a dense rectangular matrix. rwaxv2, & ! Multiplication of two rowwise stored dense rectangular ! matrices A and B by vectors x and y. trlieq, & ! Solving x from linear equation L*x=y or trans(L)*x=y. copy2 ! Copying of two vectors. IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & g, & ! Current subgradient of the objective function. gp ! Previous subgradient of the objective function. REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & sm, & ! Matrix whose columns are stored corrections. um, & ! Matrix whose columns are stored subgradient differences. rm, & ! Upper triangular matrix. cm, & ! Diagonal matrix. umtum, & ! Matrix umtum = trans(um) * um. smtgp, & ! Vector smtgp = trans(sm)*gp. umtgp, & ! vector umtgp = trans(um)*gp. s, & ! Difference of current and previous variables. u, & ! Difference of current and previous subgradients. tmpn1 ! Auxiliary array. On input: previous aggregate subgradient. REAL(KIND=prec), DIMENSION(:), INTENT(OUT) :: & d ! Direction vector. ! Scalar Arguments REAL(KIND=prec), INTENT(INOUT) :: & gamma ! Scaling parameter. INTEGER, INTENT(IN) :: & n, & ! Number of variables mc, & ! Declared number of stored corrections. iscale ! Selection of the scaling: ! 0 - Scaling at every iteration with STU/UTU. ! 1 - Scaling at every iteration with STS/STU. ! 2 - Interval scaling with STU/UTU. ! 3 - Interval scaling with STS/STU. ! 4 - Preliminary scaling with STU/UTU. ! 5 - Preliminary scaling with STS/STU. ! 6 - No scaling. INTEGER, INTENT(INOUT) :: & mcc, & ! Current number of stored corrections. inew, & ! Index for circular arrays. iflag ! Index for adaptive version: ! 0 - Maximum number of stored corrections ! has not been changed at this iteration. ! 1 - Maximum number of stored corrections ! has been changed at this iteration. INTEGER, INTENT(OUT) :: & ibfgs ! Index of the type of BFGS update: ! 1 - BFGS update: the corrections are stored. ! 2 - BFGS update: the corrections are not stored. ! 3 - BFGS update is skipped. ! Local Arrays REAL(KIND=prec), DIMENSION(mcc+1) :: & tmpmc1,tmpmc2,tmpmc3,tmpmc4 ! Local Scalars REAL(KIND=prec) :: & stu, & ! stu = trans(s)*u. sts ! sts = trans(s)*s. INTEGER :: i,j,k, & mcnew, & ! Current size of vectors. iold, & ! Index of the oldest corrections. iflag2, & ! Index for adaptive version. ierr ! Error indicator ! Intrinsic Functions INTRINSIC SQRT,MIN,MAX ierr = 0 ibfgs = 0 iflag2 = 0 stu = vdot(n,s,u) sts = vdot(n,s,s) ! Positive definiteness IF (stu > zero) THEN IF (-vdot(n,d,u)-vdot(n,tmpn1,s) < -small) THEN ! Update matrices ibfgs = 1 ! Initialization of indices. CALL indic1(mc,mcc,mcnew,inew,iold,iflag,iflag2,ibfgs) ! Update sm and um CALL copy2(n,s,sm((inew-1)*n+1:),u,um((inew-1)*n+1:)) ! Computation of trans(sm)*g and trans(um)*g IF (inew >= mcnew) THEN CALL rwaxv2(n,mcnew,sm((inew-mcnew)*n+1:),& um((inew-mcnew)*n+1:),g,g,tmpmc1(iold:),tmpmc2(iold:)) ELSE CALL rwaxv2(n,inew,sm,um,g,g,tmpmc1,tmpmc2) CALL rwaxv2(n,mcnew-inew,sm((iold-1)*n+1:),& um((iold-1)*n+1:),g,g,tmpmc1(iold:),tmpmc2(iold:)) END IF ! Computation of trans(sm)*u and trans(um)*u IF (inew >= mcnew) THEN DO i=iold,inew-1 tmpmc3(i) = tmpmc1(i) - smtgp(i) smtgp(i) = tmpmc1(i) tmpmc4(i) = tmpmc2(i) - umtgp(i) umtgp(i) = tmpmc2(i) END DO ELSE DO i=1,inew-1 tmpmc3(i) = tmpmc1(i) - smtgp(i) smtgp(i) = tmpmc1(i) tmpmc4(i) = tmpmc2(i) - umtgp(i) umtgp(i) = tmpmc2(i) END DO DO i=iold,mcnew+1 tmpmc3(i) = tmpmc1(i) - smtgp(i) smtgp(i) = tmpmc1(i) tmpmc4(i) = tmpmc2(i) - umtgp(i) umtgp(i) = tmpmc2(i) END DO END IF tmpmc3(inew) = tmpmc1(inew) - vdot(n,s,gp) smtgp(inew) = tmpmc1(inew) tmpmc4(inew) = tmpmc2(inew) - vdot(n,u,gp) umtgp(inew) = tmpmc2(inew) ! Update rm and umtum IF (mcc >= mc .AND. iflag2 /= 1) THEN DO i=1,mcnew-1 j=(i-1)*i/2+1 k=i*(i+1)/2+2 CALL copy2(i,rm(k:),rm(j:),umtum(k:),umtum(j:)) END DO END IF IF (inew >= mcnew) THEN CALL copy2(mcnew,tmpmc3(iold:),rm((mcnew-1)*mcnew/2+1:),& tmpmc4(iold:),umtum((mcnew-1)*mcnew/2+1:)) ELSE CALL copy2(mcnew-inew,tmpmc3(iold:),rm((mcnew-1)*mcnew/2+1:)& ,tmpmc4(iold:),umtum((mcnew-1)*mcnew/2+1:)) CALL copy2(inew,tmpmc3,rm((mcnew-1)*mcnew/2+mcnew-inew+1:),& tmpmc4,umtum((mcnew-1)*mcnew/2+mcnew-inew+1:)) END IF ! Update CM cm(inew) = stu ! Computation of gamma gamma = ldgbm_sclpar(mcc,iscale,sts,stu,tmpmc4(inew)) inew = inew + 1 IF (inew > mc + 1) inew = 1 IF (iflag == 0 .AND. mcc < mc + 1) mcc = mcc + 1 ELSE ! BFGS update, corrections are not saved. ibfgs = 2 ! Initialization of indices. CALL indic1(mc,mcc,mcnew,inew,iold,iflag,iflag2,ibfgs) ! Update sm and um CALL copy2(n,s,sm((inew-1)*n+1:),u,um((inew-1)*n+1:)) ! Computation of trans(sm)*g and trans(um)*g CALL rwaxv2(n,mcnew,sm,um,g,g,tmpmc1,tmpmc2) ! Computation of trans(sm)*u and trans(um)*u IF (iold /= 1) THEN DO i=1,inew-1 tmpmc3(i) = tmpmc1(i) - smtgp(i) smtgp(i) = tmpmc1(i) tmpmc4(i) = tmpmc2(i) - umtgp(i) umtgp(i) = tmpmc2(i) END DO DO i=iold,mcnew tmpmc3(i) = tmpmc1(i) - smtgp(i) smtgp(i) = tmpmc1(i) tmpmc4(i) = tmpmc2(i) - umtgp(i) umtgp(i) = tmpmc2(i) END DO ELSE DO i=1,mcnew-1 tmpmc3(i) = tmpmc1(i) - smtgp(i) smtgp(i) = tmpmc1(i) tmpmc4(i) = tmpmc2(i) - umtgp(i) umtgp(i) = tmpmc2(i) END DO END IF tmpmc3(inew) = tmpmc1(inew) - vdot(n,s,gp) smtgp(inew) = tmpmc1(inew) tmpmc4(inew) = tmpmc2(inew) - vdot(n,u,gp) umtgp(inew) = tmpmc2(inew) ! Update rm and umtum IF (iold /= 1) THEN CALL copy2(mcnew-inew,tmpmc3(iold:),& rm((mcnew-1)*mcnew/2+1:),tmpmc4(iold:),& umtum((mcnew-1)*mcnew/2+1:)) CALL copy2(inew,tmpmc3,rm((mcnew-1)*mcnew/2+mcnew-inew+1:),tmpmc4,& umtum((mcnew-1)*mcnew/2+mcnew-inew+1:)) ELSE CALL copy2(mcnew,tmpmc3,rm((mcnew-1)*mcnew/2+1:)& ,tmpmc4,umtum((mcnew-1)*mcnew/2+1:)) END IF ! Update cm cm(inew) = stu ! Computation of gamma gamma = ldgbm_sclpar(mcc,iscale,sts,stu,tmpmc4(inew)) END IF ELSE ! BFGS update is skipped ibfgs = 3 IF (mcc == 0) THEN iflag = 0 CALL vneg(n,g,d) RETURN END IF ! Initialization of indices. CALL indic1(mc,mcc,mcnew,inew,iold,iflag,iflag2,ibfgs) ! Computation of gamma IF (iscale >= 4) gamma = one ! Computation of trans(sm)*g and trans(um)*g and the two intermediate values IF (iold <= 2) THEN CALL rwaxv2(n,mcnew,sm((iold-1)*n+1:),um((iold-1)*n+1:),g,g,& smtgp(iold:),umtgp(iold:)) ELSE CALL rwaxv2(n,inew-1,sm,um,g,g,smtgp,umtgp) CALL rwaxv2(n,mcnew-inew+1,sm((iold-1)*n+1:),& um((iold-1)*n+1:),g,g,smtgp(iold:),umtgp(iold:)) END IF END IF ! Computation of two intermediate values tmpmc1 and tmpmc2 IF (iold == 1 .OR. ibfgs == 2) THEN CALL trlieq(mcnew,mcnew,iold,rm,tmpmc1,smtgp,1,ierr) CALL symax(mcnew,mcnew,iold,umtum,tmpmc1,tmpmc3) CALL vxdiag(mcnew,cm,tmpmc1,tmpmc2) CALL scsum(mcnew,gamma,tmpmc3,tmpmc2,tmpmc2) CALL scsum(mcnew,-gamma,umtgp,tmpmc2,tmpmc3) CALL trlieq(mcnew,mcnew,iold,rm,tmpmc2,tmpmc3,0,ierr) ELSE IF (iflag == 0) THEN CALL trlieq(mcnew,mc+1,iold,rm,tmpmc1,smtgp,1,ierr) CALL symax(mcnew,mc+1,iold,umtum,tmpmc1,tmpmc3) CALL vxdiag(mc+1,cm,tmpmc1,tmpmc2) CALL scsum(mc+1,gamma,tmpmc3,tmpmc2,tmpmc2) CALL scsum(mc+1,-gamma,umtgp,tmpmc2,tmpmc3) CALL trlieq(mcnew,mc+1,iold,rm,tmpmc2,tmpmc3,0,ierr) ELSE CALL trlieq(mcnew,mc,iold,rm,tmpmc1,smtgp,1,ierr) CALL symax(mcnew,mc,iold,umtum,tmpmc1,tmpmc3) CALL vxdiag(mc,cm,tmpmc1,tmpmc2) CALL scsum(mc,gamma,tmpmc3,tmpmc2,tmpmc2) CALL scsum(mc,-gamma,umtgp,tmpmc2,tmpmc3) CALL trlieq(mcnew,mc,iold,rm,tmpmc2,tmpmc3,0,ierr) END IF ! Computation of the search direction d IF (iold == 1 .OR. ibfgs == 2) THEN CALL cwmaxv(n,mcnew,um,tmpmc1,d) CALL xdiffy(n,d,g,d) CALL cwmaxv(n,mcnew,sm,tmpmc2,tmpn1) CALL scdiff(n,gamma,d,tmpn1,d) ELSE CALL cwmaxv(n,inew-1,um,tmpmc1,d) CALL cwmaxv(n,mcnew-inew+1,um((iold-1)*n+1:),tmpmc1(iold:),tmpn1) CALL xsumy(n,d,tmpn1,d) CALL xdiffy(n,d,g,d) CALL cwmaxv(n,inew-1,sm,tmpmc2,tmpn1) CALL scdiff(n,gamma,d,tmpn1,d) CALL cwmaxv(n,mcnew-inew+1,sm((iold-1)*n+1:),tmpmc2(iold:),tmpn1) CALL xdiffy(n,d,tmpn1,d) END IF CONTAINS FUNCTION ldgbm_sclpar(mcc,iscale,sts,stu,utu) RESULT(spar) ! Calculation of the scaling parameter. ! USE param, ONLY : small,one,half ! given in host IMPLICIT NONE ! Scalar Arguments REAL(KIND=prec), INTENT(IN) :: & sts, & ! sts = trans(s)*s. stu, & ! stu = trans(s)*u. utu ! utu = trans(u)*u. REAL(KIND=prec) :: & spar ! Scaling parameter. INTEGER, INTENT(IN) :: & mcc, & ! Current number of stored corrections. iscale ! Selection of the scaling: ! 0 - Scaling at every iteration with STU/UTU. ! 1 - Scaling at every iteration with STS/STU. ! 2 - Interval scaling with STU/UTU. ! 3 - Interval scaling with STS/STU. ! 4 - Preliminary scaling with STU/UTU. ! 5 - Preliminary scaling with STS/STU. ! 6 - No scaling. ! Intrinsic Functions INTRINSIC SQRT ! Computation of scaling parameter. SELECT CASE(iscale) ! Scaling parameter = STU/UTU CASE(0,2,4) IF (utu < SQRT(small)) THEN spar = one RETURN ELSE spar = stu/utu END IF ! Scaling parameter = STS/STU CASE(1,3,5) IF (stu < SQRT(small)) THEN spar = one RETURN ELSE spar = sts/stu END IF ! No scaling CASE DEFAULT spar = one RETURN END SELECT ! Scaling IF (MCC == 0) THEN IF (spar < 0.01_prec) spar=0.01_prec IF (spar > 100.0_prec) spar=100.0_prec ELSE SELECT CASE(iscale) ! Interval scaling CASE(2) IF (spar < 0.6_prec .OR. spar > 6.0_prec) spar = one CASE(3) IF (spar < half .OR. spar > 5.0_prec) spar = one ! Preliminary scaling CASE(4,5) spar = one ! Scaling at every iteration CASE DEFAULT CONTINUE END SELECT END IF IF (spar < 1.0E+03_prec*small) spar = 1.0E+03_prec*small END FUNCTION ldgbm_sclpar END SUBROUTINE ldgbm_dlbfgs !************************************************************************ !* !* * SUBROUTINE dlsr1 * !* !* Matrix update and computation of the search direction d = -dm*ga !* by the limited memory SR1 update. !* !************************************************************************ SUBROUTINE dlsr1(n,mc,mcc,inew,isr1,iflag,d,gp,ga,s,u,sm,um,rm,& umtum,cm,smtgp,umtgp,gamma,tmpmc1,tmpmc2,tmpn1,nnk,iprint) USE param, ONLY : zero,small,one USE lmbm_sub, ONLY : & vdot, & ! Dot product. vneg, & ! Copying of a vector with change of the sign. scalex, & ! Scaling a vector. xdiffy, & ! Difference of two vectors. scdiff, & ! Difference of the scaled vector and a vector. xsumy, & ! Sum of two vectors. cwmaxv, & ! Multiplication of a vector by a dense rectangular matrix. rwaxv2, & ! Multiplication of two rowwise stored dense rectangular ! matrices A and B by vectors x and y. calq, & ! Solving x from linear equation A*x=y. copy, & ! Copying of a vector. copy2 ! Copying of two vectors. IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & ga, & ! Current aggregate subgradient of the objective function. gp ! Basic subgradient of the objective function. REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & sm, & ! Matrix whose columns are stored corrections. um, & ! Matrix whose columns are stored subgradient differences. rm, & ! Upper triangular matrix. cm, & ! Diagonal matrix. umtum, & ! Matrix umtum = trans(um) * um. smtgp, & ! Vector smtgp = trans(sm)*gp. umtgp, & ! vector umtgp = trans(um)*gp. s, & ! Difference of current and previous variables. u, & ! Difference of current and previous subgradients. tmpn1 ! Auxiliary array. On input: previous aggregate subgradient. REAL(KIND=prec), DIMENSION(:), INTENT(OUT) :: & tmpmc1, & ! Auxiliary array. On output: trans(sm)*ga. tmpmc2, & ! Auxiliary array. On output: trans(um)*ga. d ! Direction vector. ! Scalar Arguments REAL(KIND=prec), INTENT(INOUT) :: & gamma ! Scaling parameter. INTEGER, INTENT(IN) :: & n, & ! Number of variables mc, & ! Declared number of stored corrections. nnk, & ! Consecutive null steps counter. iprint ! Printout specification. INTEGER, INTENT(INOUT) :: & mcc, & ! Current number of stored corrections. inew, & ! Index for circular arrays. iflag ! Index for adaptive version: ! 0 - Maximum number of stored corrections ! has not been changed at this iteration. ! 1 - Maximum number of stored corrections ! has been changed at this iteration. INTEGER, INTENT(OUT) :: & isr1 ! Index of the type of L-SR1 update: ! 1 - SR1 update: the corrections are stored. ! 3 - SR1 update is skipped. ! Local Arrays REAL(KIND=prec), DIMENSION(n) :: tmpn2 REAL(KIND=prec), DIMENSION((mcc+1)*(mcc+2)/2) :: tmpmat REAL(KIND=prec), DIMENSION(mcc+1) :: tmpmc3,tmpmc4,tmpmc5,tmpmc6 ! Local Scalars REAL(KIND=prec) :: & stu, & ! stu = trans(s)*u. a, & ! a = trans(ga) dm_(k-1) ga. b ! b = trans(ga) dm_k ga. INTEGER :: i,j,k, & mcnew, & ! Current size of vectors. iold, & ! Index of the oldest corrections. iflag2 ! Index for adaptive version. iflag2 = 0 isr1 = 0 ! Initialization of indices CALL indic1(mc,mcc,mcnew,inew,iold,iflag,iflag2,3) ! Computation of GAMMA gamma = one ! Computation of trans(sm)*ga and trans(um)*ga IF (iold <= 2) THEN CALL rwaxv2(n,mcnew,sm((iold-1)*n+1:),um((iold-1)*n+1:),ga,ga,& tmpmc1(iold:),tmpmc2(iold:)) ELSE CALL rwaxv2(n,inew-1,sm,um,ga,ga,tmpmc1,tmpmc2) CALL rwaxv2(n,mcnew-inew+1,sm((iold-1)*n+1:),um((iold-1)*n+1:),& ga,ga,tmpmc1(iold:),tmpmc2(iold:)) END IF ! Positive definiteness IF (-vdot(n,d,u) - vdot(n,tmpn1,s) >= -small) THEN ! SR1 update is skipped isr1 = 3 IF (mcc == 0) THEN iflag = 0 CALL vneg(n,ga,d) RETURN END IF ELSE stu = vdot(n,s,u) tmpmc1(inew) = vdot(n,s,ga) tmpmc2(inew) = vdot(n,u,ga) ! Convergence conditions IF ((nnk == 1 .OR. mcc < mc) .OR. & (iflag == 1 .AND. (inew == 1 .OR. inew == mc))) THEN ! SR1 Update isr1 = 1 ! Initialization of indices CALL indic1(mc,mcc,mcnew,inew,iold,iflag,iflag2,1) if (iflag2 == 1 .and. iold == 2) then tmpmc1(inew) = tmpmc1(1) tmpmc2(inew) = tmpmc2(1) end if ! Update sm and um CALL copy2(n,s,sm((inew-1)*n+1:),u,um((inew-1)*n+1:)) ! Update trans(sm)*gp and trans(um)*gp smtgp(inew) = vdot(n,s,gp) umtgp(inew) = vdot(n,u,gp) ! Computation of trans(sm)*u and trans(um)*u IF (iold <= 2) THEN CALL rwaxv2(n,mcnew-1,sm((iold-1)*n+1:),um((iold-1)*n+1:),& u,u,tmpmc3(iold:),tmpmc4(iold:)) ELSE CALL rwaxv2(n,inew-1,sm,um,u,u,tmpmc3,tmpmc4) CALL rwaxv2(n,mcnew-inew,sm((iold-1)*n+1:),um((iold-1)*n+1:),& u,u,tmpmc3(iold:),tmpmc4(iold:)) END IF tmpmc3(inew) = stu tmpmc4(inew) = vdot(n,u,u) ! Update rm and umtum IF (mcc >= mc .AND. iflag2 /= 1) THEN DO i=1,mcnew-1 j=(i-1)*i/2+1 k=i*(i+1)/2+2 CALL copy2(i,rm(k:),rm(j:),umtum(k:),umtum(j:)) END DO END IF IF (inew >= mcnew) THEN CALL copy2(mcnew,tmpmc3(iold:),rm((mcnew-1)*mcnew/2+1:),& tmpmc4(iold:),umtum((mcnew-1)*mcnew/2+1:)) ELSE CALL copy2(mcnew-inew,tmpmc3(iold:),& rm((mcnew-1)*mcnew/2+1:),tmpmc4(iold:),& umtum((mcnew-1)*mcnew/2+1:)) CALL COPY2(inew,tmpmc3,rm((mcnew-1)*mcnew/2+mcnew-inew+1:),tmpmc4,& umtum((mcnew-1)*mcnew/2+mcnew-inew+1:)) END IF ! Update cm cm(inew) = stu inew = inew + 1 IF (inew > mc + 1) inew = 1 IF (iflag == 0 .AND. mcc < mc + 1) mcc = mcc + 1 ELSE ! Calculation of matrix (umtum-rm-trans(rm)+cm) from previous iteration DO i=1,mcnew*(mcnew+1)/2 tmpmat(i)= gamma * umtum(i) - rm(i) END DO ! Computation of tmpmat*tmpmc4 = gamma*trans(um)*ga-trans(sm)*ga IF (iold == 1) THEN CALL scdiff(mcnew,gamma,tmpmc2,tmpmc1,tmpmc5) CALL calq(mcnew,mcnew,iold,tmpmat,tmpmc4,tmpmc5,0) ELSE IF (iflag == 0) THEN CALL scdiff(mc+1,gamma,tmpmc2,tmpmc1,tmpmc5) CALL calq(mcnew,mc+1,iold,tmpmat,tmpmc4,tmpmc5,0) ELSE CALL scdiff(mc,gamma,tmpmc2,tmpmc1,tmpmc5) CALL calq(mcnew,mc,iold,tmpmat,tmpmc4,tmpmc5,0) END IF ! Computation of a = -trans(ga)*dm_(k-1)*ga IF (iold <= 2) THEN CALL scalex(mcnew,gamma,tmpmc4(iold:),tmpmc3(iold:)) CALL cwmaxv(n,mcnew,sm((iold-1)*n+1:),tmpmc4(iold:),tmpn1) CALL scdiff(n,-gamma,ga,tmpn1,tmpn2) CALL cwmaxv(n,mcnew,um((iold-1)*n+1:),tmpmc3(iold:),tmpn1) CALL xsumy(n,tmpn2,tmpn1,tmpn2) ELSE CALL scalex(mcc,gamma,tmpmc4,tmpmc3) CALL cwmaxv(n,inew-1,sm,tmpmc4,tmpn1) CALL scdiff(n,-gamma,ga,tmpn1,tmpn2) CALL cwmaxv(n,mcnew-inew+1,sm((iold-1)*n+1:),tmpmc4(iold:),& tmpn1) CALL xdiffy(n,tmpn2,tmpn1,tmpn2) CALL cwmaxv(n,inew-1,um,tmpmc3,tmpn1) CALL xsumy(n,tmpn2,tmpn1,tmpn2) CALL cwmaxv(n,mcnew-inew+1,um((iold-1)*n+1:),tmpmc3(iold:),& tmpn1) CALL xsumy(n,tmpn2,tmpn1,tmpn2) END IF a = vdot(n,ga,tmpn2) IF (iflag == 0) THEN mcnew = mc iold = inew + 2 IF (iold > mc+1) iold = iold - mc - 1 ELSE mcnew = mc - 1 iold = inew + 2 IF (iold > mc) iold = iold - mc END IF ! Calculation of the new canditate for search direction ! Updates are not necessarily saved ! Update sm and um CALL copy2(n,s,sm((inew-1)*n+1:),u,um((inew-1)*n+1:)) ! Computation of trans(sm)*u and trans(um)*u IF (iold == 1 .OR. iold == 2) THEN CALL rwaxv2(n,mcnew-1,sm((iold-1)*n+1:),um((iold-1)*n+1:),u,u,& tmpmc3(iold:),tmpmc4(iold:)) ELSE CALL rwaxv2(n,inew-1,sm,um,u,u,tmpmc3,tmpmc4) CALL rwaxv2(n,mcnew-inew,sm((iold-1)*n+1:),um((iold-1)*n+1:),u,u,& tmpmc3(iold:),tmpmc4(iold:)) END IF tmpmc3(inew) = stu tmpmc4(inew) = vdot(n,u,u) ! Calculation of matrix (umtum-rm-trans(rm)+cm) without updating ! matrices rm, umtum and cm DO i=1,mcnew*(mcnew+1)/2 tmpmat(i)= gamma * umtum(i) - rm(i) END DO DO i=1,mcnew-1 j=(i-1)*i/2+1 k=i*(i+1)/2+2 CALL copy(i,tmpmat(k:),tmpmat(j:)) END DO CALL scdiff(mcnew+1,gamma,tmpmc4,tmpmc3,tmpmc5) IF (inew >= mcnew) THEN CALL copy(mcnew,tmpmc5(iold:),tmpmat((mcnew-1)*mcnew/2+1:)) ELSE CALL copy(mcnew-inew,tmpmc5(iold:),tmpmat((mcnew-1)*mcnew/2+1:)) CALL copy(inew,tmpmc5,tmpmat((mcnew-1)*mcnew/2+mcnew-inew+1:)) END IF IF (iflag == 0) THEN CALL scdiff(mc+1,gamma,tmpmc2,tmpmc1,tmpmc5) CALL calq(mcnew,mc+1,iold,tmpmat,tmpmc5,tmpmc5,iprint) ELSE CALL scdiff(mc,gamma,tmpmc2,tmpmc1,tmpmc5) CALL calq(mcnew,mc,iold,tmpmat,tmpmc5,tmpmc5,iprint) END IF ! Calculation of the new canditate for search direction d = -dm_k*ga ! and computation of b = -trans(ga)*dm_k*ga IF (iold <= 2) THEN CALL scalex(mcnew,gamma,tmpmc5(iold:),tmpmc6(iold:)) CALL cwmaxv(n,mcnew,sm((iold-1)*n+1:),tmpmc5(iold:),tmpn1) CALL scdiff(n,-gamma,ga,tmpn1,d) CALL cwmaxv(n,mcnew,um((iold-1)*n+1:),tmpmc6(iold:),tmpn1) CALL xsumy(n,d,tmpn1,d) ELSE CALL scalex(mcnew+1,gamma,tmpmc5,tmpmc6) CALL cwmaxv(n,inew,sm,tmpmc5,tmpn1) CALL scdiff(n,-gamma,ga,tmpn1,d) CALL cwmaxv(n,mcnew-inew,sm((iold-1)*n+1:),tmpmc5(iold:),& tmpn1) CALL xdiffy(n,d,tmpn1,d) CALL cwmaxv(n,inew,um,tmpmc6,tmpn1) CALL xsumy(n,d,tmpn1,d) CALL cwmaxv(n,mcnew-inew,um((iold-1)*n+1:),tmpmc6(iold:),& tmpn1) CALL xsumy(n,d,tmpn1,d) END IF b = vdot(n,ga,d) ! Checking the convergence conditions IF (b - a < zero) THEN isr1 = 3 CALL copy(n,tmpn2,d) ELSE isr1 = 1 ! Update trans(sm)*gp and trans(um)*gp smtgp(inew) = vdot(n,s,gp) umtgp(inew) = vdot(n,u,gp) ! Update rm and umtum DO i=1,mcnew-1 j=(i-1)*i/2+1 k=i*(i+1)/2+2 CALL copy2(i,rm(k:),rm(j:),umtum(k:),umtum(j:)) END DO IF (inew >= mcnew) THEN CALL copy2(mcnew,tmpmc3(iold:),rm((mcnew-1)*mcnew/2+1:),tmpmc4(iold:),& umtum((mcnew-1)*mcnew/2+1:)) ELSE CALL copy2(mcnew-inew,tmpmc3(iold:),rm((mcnew-1)*mcnew/2+1:),tmpmc4(iold:),& umtum((mcnew-1)*mcnew/2+1:)) CALL copy2(inew,tmpmc3,rm((mcnew-1)*mcnew/2+mcnew-inew+1:),tmpmc4,& umtum((mcnew-1)*mcnew/2+mcnew-inew+1:)) END IF ! Update cm cm(inew) = stu inew = inew + 1 IF (inew > mc + 1) inew = 1 IF (iflag == 0 .AND. mcc < mc + 1) mcc = mcc + 1 END IF RETURN END IF END IF DO i=1,mcnew*(mcnew+1)/2 tmpmat(i)= gamma * umtum(i) - rm(I) END DO ! Computation of tmpmat*tmpmc4 = gamma*trans(um)*ga-trans(sm)*ga IF (iold == 1) THEN CALL scdiff(mcnew,gamma,tmpmc2,tmpmc1,tmpmc4) CALL calq(mcnew,mcnew,iold,tmpmat,tmpmc4,tmpmc4,iprint) ELSE IF (iflag == 0) THEN CALL scdiff(mc+1,gamma,tmpmc2,tmpmc1,tmpmc4) CALL calq(mcnew,mc+1,iold,tmpmat,tmpmc4,tmpmc4,iprint) ELSE CALL scdiff(mc,gamma,tmpmc2,tmpmc1,tmpmc4) CALL calq(mcnew,mc,iold,tmpmat,tmpmc4,tmpmc4,iprint) END IF ! Computation of the search direction d IF (iold <= 2) THEN CALL scalex(mcnew,gamma,tmpmc4(iold:),tmpmc3(iold:)) CALL cwmaxv(n,mcnew,sm((iold-1)*n+1:),tmpmc4(iold:),tmpn1) CALL scdiff(n,-gamma,ga,tmpn1,d) CALL cwmaxv(n,mcnew,um((iold-1)*n+1:),tmpmc3(iold:),tmpn1) CALL xsumy(n,d,tmpn1,d) ELSE CALL scalex(mcc,gamma,tmpmc4,tmpmc3) CALL cwmaxv(n,inew-1,sm,tmpmc4,tmpn1) CALL scdiff(n,-gamma,ga,tmpn1,d) CALL cwmaxv(n,mcnew-inew+1,sm((iold-1)*n+1:),tmpmc4(iold:),& tmpn1) CALL xdiffy(n,d,tmpn1,d) CALL cwmaxv(n,inew-1,um,tmpmc3,tmpn1) CALL xsumy(n,d,tmpn1,d) CALL cwmaxv(n,mcnew-inew+1,um((iold-1)*n+1:),tmpmc3(iold:),& tmpn1) CALL xsumy(n,d,tmpn1,d) END IF END SUBROUTINE dlsr1 !************************************************************************ !* * !* * SUBROUTINE indic1 * * !* * !* Initialization of indices. * !* * !************************************************************************ SUBROUTINE indic1(mc,mcc,mcnew,inew,iold,iflag,iflag2,itype) IMPLICIT NONE ! Scalar Arguments INTEGER, INTENT(IN) :: & mc, & ! Declared number of stored corrections. mcc, & ! Current number of stored corrections. itype ! Type of Initialization: ! 1 - corrections are stored, ! 2 - corrections are not stored, ! 3 - update is skipped. INTEGER, INTENT(INOUT) :: & inew, & ! Index for circular arrays. iflag, & ! Index for adaptive version: ! 0 - Maximum number of stored corrections ! has not been changed at this iteration. ! 1 - Maximum number of stored corrections ! has been changed at this iteration. iflag2 ! Index for adaptive version. ! 0 - iflag has not been changed. ! 1 - iflag has been changed. INTEGER, INTENT(OUT) :: & mcnew, & ! Current size of vectors. iold ! Index of the oldest corrections. IF (itype == 1) THEN IF (mcc < mc) THEN mcnew = mcc + 1 iold = 1 iflag = 0 ELSE IF (iflag == 0) THEN mcnew = mc iold = inew + 2 IF (iold > mc+1) iold = iold - mc - 1 ELSE IF (inew == 1) THEN inew = mc + 1 mcnew = mc iold = 2 iflag = 0 iflag2 = 1 ELSE IF (inew == mc) THEN mcnew = mc iold = 1 iflag = 0 iflag2 = 1 ELSE mcnew = mc - 1 iold = inew + 2 IF (iold > mc) iold = iold - mc END IF END IF END IF ELSE IF (itype == 2) THEN IF (mcc < mc) THEN mcnew = mcc + 1 iold = 1 iflag = 0 ELSE IF (iflag == 0) THEN mcnew = mc + 1 iold = inew + 1 IF (iold > mc + 1) iold = 1 ELSE mcnew = mc iold = inew + 1 IF (iold > mc) iold = 1 END IF END IF ELSE IF (mcc < mc) THEN mcnew = mcc iold = 1 iflag = 0 ELSE IF (iflag == 0) THEN mcnew = mc iold = inew + 1 IF (iold > mc + 1) iold = 1 ELSE mcnew = mc - 1 iold = inew + 1 IF (iold > mc) iold = 1 END IF END IF END IF END SUBROUTINE indic1 !************************************************************************ !* !* * SUBROUTINE agbfgs * !* !* Computation of aggregate values by the limited memory BFGS update. !* !************************************************************************ SUBROUTINE agbfgs(n,mc,mcc,inew,ibfgs,iflag,g,gp,ga,u,d,sm,um, & rm,cm,umtum,alfn,alfv,gamma,ic,rho) USE param, ONLY : zero,half,one USE lmbm_sub, ONLY : & symax, & ! Multiplication of a dense symmetric matrix by a vector. rwaxv2, & ! Multiplication of two rowwise stored dense rectangular ! matrices A and B by vectors x and y. trlieq, & ! Solving x from linear equation L*x=y or trans(L)*x=y. vdot ! Dot product. IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & d, & ! Direction vector. g, & ! Current (auxiliary) subgradient of the objective function. gp, & ! Previous subgradient of the objective function. u, & ! Difference of trial and aggregate gradients. sm, & ! Matrix whose columns are stored corrections. um, & ! Matrix whose columns are stored subgradient differences. rm, & ! Upper triangular matrix. umtum, & ! Matrix umtum = trans(um) * um. cm ! Diagonal matrix. REAL(KIND=prec), DIMENSION(:), INTENT(OUT) :: & ga ! Next aggregate subgradient of the objective function. ! Scalar Arguments REAL(KIND=prec), INTENT(OUT) :: & alfv ! Aggregate locality measure. REAL(KIND=prec), INTENT(IN) :: & gamma, & ! Scaling parameter. alfn, & ! Locality measure. rho ! Correction parameter. INTEGER, INTENT(IN) :: & n, & ! Number of variables mc, & ! Declared number of stored corrections. mcc, & ! Current number of stored corrections. inew, & ! Index for circular arrays. ibfgs, & ! Index of the type of BFGS update. ic ! Correction indicator. INTEGER, INTENT(INOUT) :: & iflag ! Index for adaptive version: ! 0 - Maximum number of stored corrections ! has not been changed at this iteration. ! 1 - Maximum number of stored corrections ! has been changed at this iteration. ! Local arrays REAL(KIND=prec), DIMENSION(mcc+1) :: tmpmc1, tmpmc2 ! Local Scalars REAL(KIND=prec) :: & p, & ! p = trans(d)*u - alfn. q, & ! q = trans(u)*dm*u, where dm is the inverse approximation of ! the Hessian calculated by using the L-BFGS formula. lam, & ! Multiplier used to calculate aggregate values. w ! Correction. INTEGER :: i, & mcnew, & ! Current size of vectors. iold, & ! Index of the oldest corrections. ierr ! Error indicador. ! Intrinsic Functions INTRINSIC MAX,MIN,SIGN ierr = 0 IF (mcc < mc) THEN IF (ibfgs == 2) THEN mcnew = mcc + 1 ELSE mcnew = mcc END IF iold = 1 ELSE IF (iflag == 0) THEN IF (ibfgs == 2) THEN mcnew = mc + 1 ELSE mcnew = mc END IF iold = inew + 1 IF (iold > mc+1) iold = 1 ELSE IF (ibfgs == 2) THEN mcnew = mc ELSE mcnew = mc - 1 END IF iold = inew + 1 IF (iold > mc) iold = 1 END IF END IF ! Computation of trans(d) * u - alfn p = vdot(n,d,u) - alfn q = vdot(n,u,u) IF (ic == 1) THEN w = rho * q ELSE w = zero END IF ! Computation of the product trans(u)*dm*u IF (mcc > 0 .OR. ibfgs == 2) THEN IF (iold == 1 .OR. ibfgs == 2) THEN CALL rwaxv2(n,mcnew,sm,um,u,u,tmpmc1,tmpmc2) CALL trlieq(mcnew,mcnew,iold,rm,tmpmc1,tmpmc1,1,ierr) q = q - 2.0_prec*vdot(mcnew,tmpmc2,tmpmc1) q = gamma*q DO i=1,mcnew tmpmc2(i) = cm(i)*tmpmc1(i) END DO q = q + vdot(mcnew,tmpmc1,tmpmc2) CALL symax(mcnew,mcnew,iold,umtum,tmpmc1,tmpmc2) q = q + gamma*vdot(mcnew,tmpmc1,tmpmc2) ELSE CALL rwaxv2(n,inew-1,sm,um,u,u,tmpmc1,tmpmc2) CALL rwaxv2(n,mcc-inew,sm((iold-1)*n+1:),um((iold-1)*n+1:), & u,u,tmpmc1(iold:),tmpmc2(iold:)) CALL trlieq(mcnew,mcc,iold,rm,tmpmc1,tmpmc1,1,ierr) q = q - 2.0_prec*(vdot(mcc-inew,tmpmc2(iold:),tmpmc1(iold:)) + & vdot(inew-1,tmpmc2,tmpmc1)) q = gamma*q DO i=1,mcc tmpmc2(i) = cm(i)*tmpmc1(i) END DO q = q + vdot(mcc-inew,tmpmc1(iold:),tmpmc2(iold:)) + & vdot(inew-1,tmpmc1,tmpmc2) CALL symax(mcnew,mcc,iold,umtum,tmpmc1,tmpmc2) q = q + gamma*(vdot(mcc-inew,tmpmc1(iold:),tmpmc2(iold:)) + & vdot(inew-1,tmpmc1,tmpmc2)) END IF END IF q = q + w lam = half + SIGN(half,p) IF (q > zero) lam = MIN(one,MAX(zero,p/q)) ! Computation of the aggregate values p = one - lam DO i=1,n ga(i)=lam*g(i) + p*gp(i) END DO alfv = lam*alfn END SUBROUTINE agbfgs !************************************************************************ !* !* * SUBROUTINE aggsr1 * !* !* Computation of aggregate values by the limited memory SR1 update. !* !************************************************************************ SUBROUTINE aggsr1(n,mc,mcc,inew,iflag,g,gp,ga,d,alfn,alfv, & umtum,rm,gamma,smtgp,umtgp,smtga,umtga,sm,um,icn,rho) USE param, ONLY : zero,one,small USE lmbm_sub, ONLY : & vdot, & ! Dot product. scalex, & ! Scaling a vector. xsumy, & ! Sum of two vectors. xdiffy, & ! Difference of two vectors. scsum, & ! Sum of a vector and the scaled vector. scdiff, & ! Difference of the scaled vector and a vector. rwaxv2, & ! Multiplication of two rowwise stored dense rectangular ! matrices A and B by vectors x and y. cwmaxv, & ! Multiplication of a vector by a dense rectangular matrix. lineq, & ! Solver for linear equation. calq ! Solving x from linear equation A*x=y. IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & d, & ! Direction vector. g, & ! Current (auxiliary) subgradient of the objective function. gp, & ! Previous subgradient of the objective function. sm, & ! Matrix whose columns are stored corrections. um, & ! Matrix whose columns are stored subgradient differences. rm, & ! Upper triangular matrix. umtum, & ! Matrix umtum = trans(um) * um. smtgp, & ! Vector smtgp = trans(sm)*gp. umtgp, & ! vector umtgp = trans(um)*gp. smtga, & ! vector smtga = trans(sm)*ga. umtga ! vector umtga = trans(um)*ga. REAL(KIND=prec), DIMENSION(:), INTENT(INOUT) :: & ga ! Aggregate subgradient of the objective function. ! Scalar Arguments REAL(KIND=prec), INTENT(INOUT) :: & alfv ! Aggregate locality measure. REAL(KIND=prec), INTENT(IN) :: & gamma, & ! Scaling parameter. alfn, & ! Locality measure. rho ! Correction parameter. INTEGER, INTENT(IN) :: & n, & ! Number of variables mc, & ! Declared number of stored corrections. mcc, & ! Current number of stored corrections. inew, & ! Index for circular arrays. icn ! Correction indicator. INTEGER, INTENT(INOUT) :: & iflag ! Index for adaptive version: ! 0 - Maximum number of stored corrections ! has not been changed at this iteration. ! 1 - Maximum number of stored corrections ! has been changed at this iteration. ! Local arrays REAL(KIND=prec), DIMENSION(n) :: tmpn2,tmpn3,tmpn4 REAL(KIND=prec), DIMENSION((mcc+1)*(mcc)/2) :: tmpmat REAL(KIND=prec), DIMENSION(mcc+1) :: tmpmc3, tmpmc4 ! Local Scalars REAL(KIND=prec) :: & pr, & ! pr = trans(gp-ga) dm (gp-ga), where dm ! presents the L-SR1- approximation of Hessian. rrp, & ! rrp = trans(gp-ga) dm ga - alfv. prqr, & ! prqr = trans(gp-ga) dm (g-ga). rrq, & ! rrq = trans(g-ga) dm ga - alfv + alfn. qr, & ! qr = trans(g-ga) dm (g-ga). pq, & ! pq = trans(g-gp) dm (g-gp). qqp, & ! qqp = trans(g-gp) dm g + alfn. lam1, & ! Multiplier used to calculate aggregate values. lam2, & ! Multiplier used to calculate aggregate values. w, & ! Correction. tmp1, & ! Auxiliary scalar. tmp2 ! Auxiliary scalar. INTEGER :: i, & mcnew, & ! Current size of vectors. iold, & ! Index of the oldest corrections. ierr ! Error indicador. ! Intrinsic Functions INTRINSIC MIN,MAX ierr = 0 IF (mcc < mc) THEN iold = 1 mcnew = mcc ELSE IF (iflag == 0) THEN mcnew = mc iold = inew + 1 IF (iold > mc+1) iold = 1 ELSE mcnew = mc - 1 iold = inew + 1 IF (iold > mc) iold = 1 END IF CALL xdiffy(n,gp,ga,tmpn2) ! Calculation of tmpn3 = trans(gp - ga)dm IF (mcc > 0) THEN DO i=1,mcnew*(mcnew+1)/2 tmpmat(i)= gamma * umtum(i) - rm(i) END DO IF (iold == 1) THEN CALL xdiffy(mcnew,umtgp,umtga,tmpmc4) CALL scdiff(mcnew,gamma,tmpmc4,smtgp,tmpmc4) CALL xsumy(mcnew,tmpmc4,smtga,tmpmc4) CALL calq(mcnew,mcnew,iold,tmpmat,tmpmc3,tmpmc4,0) CALL scalex(mcnew,gamma,tmpmc3,tmpmc4) CALL cwmaxv(n,mcnew,sm,tmpmc3,tmpn4) CALL scsum(n,gamma,tmpn2,tmpn4,tmpn3) CALL cwmaxv(n,mcnew,um,tmpmc4,tmpn4) CALL xdiffy(n,tmpn3,tmpn4,tmpn3) ELSE CALL xdiffy(mcc,umtgp,umtga,tmpmc4) CALL scdiff(mcc,gamma,tmpmc4,smtgp,tmpmc4) CALL xsumy(mcc,tmpmc4,smtga,tmpmc4) CALL calq(mcnew,mcc,iold,tmpmat,tmpmc3,tmpmc4,0) CALL scalex(mcc,gamma,tmpmc3,tmpmc4) CALL cwmaxv(n,inew-1,sm,tmpmc3,tmpn4) CALL scsum(n,gamma,tmpn2,tmpn4,tmpn3) CALL cwmaxv(n,mcnew-inew+1,sm((iold-1)*n+1:),tmpmc3(iold:)& ,tmpn4) CALL xsumy(n,tmpn3,tmpn4,tmpn3) CALL cwmaxv(n,inew-1,um,tmpmc4,tmpn4) CALL xdiffy(n,tmpn3,tmpn4,tmpn3) CALL cwmaxv(n,mcnew-inew+1,um((iold-1)*n+1:),tmpmc4(iold:)& ,tmpn4) CALL xdiffy(n,tmpn3,tmpn4,tmpn3) END IF IF (icn == 1) THEN CALL scsum(n,rho,tmpn2,tmpn3,tmpn3) END IF pr = vdot(n,tmpn3,tmpn2) rrp = vdot(n,tmpn3,ga) CALL xdiffy(n,g,ga,tmpn4) prqr = vdot(n,tmpn3,tmpn4) rrq = -vdot(n,tmpn4,d) ELSE pr = vdot(n,tmpn2,tmpn2) rrp = vdot(n,tmpn2,ga) CALL xdiffy(n,g,ga,tmpn4) prqr = vdot(n,tmpn2,tmpn4) rrq = -vdot(n,tmpn4,d) END IF ! calculation of qr = trans(g - ga) dm (g - ga) qr = vdot(n,tmpn4,tmpn4) IF (icn == 1) THEN w = rho*qr ELSE w = zero END IF IF (mcc > 0) THEN qr = gamma*qr IF (iold == 1) THEN CALL rwaxv2(n,mcnew,sm,um,tmpn4,tmpn4,tmpmc4,tmpmc3) CALL scsum(mcnew,-gamma,tmpmc3,tmpmc4,tmpmc4) CALL lineq(mcnew,mcnew,iold,tmpmat,tmpmc3,tmpmc4,ierr) qr = qr - vdot(mcnew,tmpmc4,tmpmc3) + w ELSE CALL rwaxv2(n,inew-1,sm,um,tmpn4,tmpn4,tmpmc4,tmpmc3) CALL rwaxv2(n,mcnew-inew+1,sm((iold-1)*n+1:),& um((iold-1)*n+1:),tmpn4,tmpn4,tmpmc4(iold:),tmpmc3(iold:)) CALL scsum(mcc,-gamma,tmpmc3,tmpmc4,tmpmc4) CALL lineq(mcnew,mcc,iold,tmpmat,tmpmc3,tmpmc4,ierr) qr = qr - vdot(mcc-inew,tmpmc4(iold:),tmpmc3(iold:)) -& vdot(inew-1,tmpmc4,tmpmc3) + w END IF END IF pq = qr - prqr - prqr + pr qqp = pq + prqr + rrq - pr - rrp + alfn rrp = rrp - alfv rrq = rrq + alfn - alfv ! computation of multipliers lam1 and lam2 IF (pr > zero .AND. qr > zero) THEN tmp1 = rrq/qr tmp2 = prqr/qr w = pr - prqr*tmp2 IF (w /= zero) THEN lam1 = (tmp1*prqr - rrp)/w lam2 = -tmp1 - lam1*tmp2 IF (lam1*(lam1 - one) < zero .AND. & lam2*(lam1 + lam2 - one) < zero) GO TO 200 END IF END IF ! Minimum on the boundary 100 continue lam1 = zero lam2 = zero IF (alfn <= alfv) lam2 = one IF (qr > zero) lam2 = MIN(one,MAX(zero,-rrq/qr)) w = (lam2*qr + rrq+rrq)*lam2 ! w = (lam2*qr + 2.0_prec*rrq)*lam2 tmp1 = zero IF (alfv >= zero) tmp1 = one IF (pr > zero) tmp1 = MIN(one,MAX(zero,-rrp/pr)) ! tmp2 = (tmp1*pr + 2.0_prec*rrp)*tmp1 tmp2 = (tmp1*pr + rrp+rrp)*tmp1 IF (tmp2 < w) THEN w = tmp2 lam1 = tmp1 lam2 = zero END IF IF (qqp*(qqp - pq) < zero) THEN IF (qr + rrq + rrq - qqp*qqp/pq < W) THEN lam1 = qqp/pq lam2 = one - lam1 END IF END IF 200 CONTINUE IF (lam1 == zero .AND. lam2*(lam2 - one) < zero & .AND. -rrp - lam2*prqr > zero .AND. pr > zero) & lam1 = MIN(one - lam2, (-rrp-lam2*prqr)/pr) ! Computation of the aggregate values tmp1 = one - lam1 - lam2 DO i=1,n ga(i)=lam1*gp(i)+lam2*g(i)+tmp1*ga(i) END DO alfv = lam2*alfn + tmp1*alfv END SUBROUTINE aggsr1 !************************************************************************ !* * !* * SUBROUTINE dgrad * * !* * !* Calculation of discrete gradients. * !* * !************************************************************************ SUBROUTINE dgrad(n,x,sl,g,dg,f,ngrad,nfe,pwt,iterm) USE param, ONLY : zero,half,one,small USE obj_fun, ONLY : myf ! Computation of the value of the objective function. USE lmbm_sub, ONLY : vdot ! Dot product IMPLICIT NONE ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & x, & ! Current iteration point. g ! Direction of discrete gradient. REAL(KIND=prec), DIMENSION(:), INTENT(OUT) :: & dg ! Disgrete gradient. ! Scalar Arguments REAL(KIND=prec), INTENT(IN) :: & f, & ! Value of the objective at x. sl, & ! Parameter for discrete gradient. (lambda) pwt ! Parameter: pwt = z(sl)*alpha^j*e_j. INTEGER, INTENT(IN) :: & n ! Number of variables INTEGER, INTENT(INOUT) :: & ngrad, & ! Number of discrete gradient calls. nfe ! Number of function evaluations. INTEGER, INTENT(OUT) :: & iterm ! Cause of termination: ! 0 - Everything is ok. ! -3 - Failure in function calculations. ! Local arrays REAL(KIND=prec), DIMENSION(n) :: x1 ! Local Scalars REAL(KIND=prec) :: & a1, & ! a1 = argmax{|g_i|} r2, & ! Function value at (x + sl*g) r3, & ! Function value at (x^(j-1)) r4, & ! Function value at (x^j) dsum, & ! trans(dg)*g - dg(imax)*g(imax) tmp1 ! Auxiliary scalar. INTEGER :: k, & imax ! Index of the largest component of g. ! Intrinsic Functions INTRINSIC ABS ! Compute a1 = argmax{|g_i|} and set imax a1 = zero DO k=1,n tmp1 = ABS(g(k)) IF (a1 < tmp1) THEN a1 = tmp1 imax = k END IF END DO DO k=1,n x1(k) = x(k)+sl*g(k) END DO CALL myf(n,x1,r2,iterm) IF (iterm /= 0) RETURN nfe = nfe+1 dsum = zero r4 = r2 DO k=1,n IF (k /= imax) THEN r3 = r4 x1(k) = x1(k) + pwt CALL myf(n,x1,r4,iterm) nfe = nfe+1 IF (iterm /= 0) RETURN dg(k) = (r4 - r3)/pwt dsum = dsum + dg(k)*g(k) END IF END DO dg(imax) = (r2 - f)/(sl*g(imax)) - dsum/g(imax) ngrad = ngrad+1 END SUBROUTINE dgrad !************************************************************************ !* !* * SUBROUTINE ldgbm_wprint * !* !* Printout the warning and error messages. !* !************************************************************************ SUBROUTINE ldgbm_wprint(iterm,iprint,nout) IMPLICIT NONE ! Scalar Arguments INTEGER, INTENT(IN) :: & iprint, & ! Printout specification: ! -1 - No printout. ! 0 - Only the error messages. ! 1 - The final values of the objective ! function. ! 2 - The final values of the objective ! function and the most serious ! warning messages. ! 3 - The whole final solution. ! 4 - At each iteration values of the ! objective function. ! 5 - At each iteration the whole ! solution nout, & ! Auxilary printout specification. iterm ! Cause of termination: ! 1 - The problem has been solved with desired accuracy. ! 2 - Changes in function values < tolf in mtesf ! subsequent iterations. ! 3 - Changes in function value < tolf*small*MAX(|f_k|,|f_(k-1)|,1), ! where small is the smallest positive number such that ! 1.0 + small > 1.0. ! 4 - Number of function calls > mfe. ! 5 - Number of iterations > mit. ! 6 - Time limit exceeded. ! 7 - f < tolb. ! -1 - Two consecutive restarts. ! -2 - Number of restarts > maximum number of restarts. ! -3 - Failure in function or subgradient calculations ! (assigned by the user). ! -4 - Failure in attaining the demanded accuracy. ! -5 - Invalid input parameters. IF (iprint >= 0) THEN ! Initial error messages IF (iterm == -5) THEN IF (nout == 1) WRITE (6,FMT='(1X,''Error: '' & ''Number of variables (n) is too small, iterm='',I3)') iterm IF (nout == 2) WRITE (6,FMT='(1X,''Error: '' & ''The maximum number of stored corrections (mcu) '' & ''is too small, iterm='',I3)') iterm IF (nout == 3) WRITE (6,FMT='(1X,''Error: '' & ''The size of the bundle (na) is too small, iterm='' & ,I3)') iterm IF (nout == 4) WRITE (6,FMT='(1X,''Error: '' & ''Line search parameter epsl >= 0.25, iterm='',I3)') iterm RETURN END IF ! Warning messages IF (iprint >= 2) THEN IF (iterm == 0) THEN IF (nout == -1) WRITE (6,FMT='(1X,''Warning: '' & ''mc > mcu. Assigned mc = mcu.'')') IF (nout == -2) WRITE (6,FMT='(1X,''Warning: '' & ''A line search parameter epsr >= 0.5.'')') IF (nout == -3) WRITE (6,FMT='(1X,''Warning: '' & ''A nondescent search direction occured. Restart.'')') IF (nout == -4) WRITE (6,FMT='(1X,''Warning: '' & ''Does not converge.'')') IF (nout == -5) WRITE (6,FMT='(1X,''Warning: '' & ''tmax < tmin. Restart.'')') RETURN END IF ! Printout the final results IF (iterm == 6) WRITE (6,FMT='(1X,''Abnormal exit: Time is up.'')') IF (iterm == 7) WRITE (6,FMT='(1X,''Abnormal exit: f < tolb.'')') IF (iterm == 2) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''Too many steps without significant progress.'')') IF (iterm == 3) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''The value of the function does not change.'')') IF (iterm == 5) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''Number of iterations > '',I5)') nout IF (iterm == 4) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''Number of function evaluations > '',I5)') nout IF (iterm == -1) THEN IF (nout == -1) THEN WRITE (6,FMT='(1X,''Abnormal exit: Two consecutive restarts.'')') ELSE WRITE (6,FMT='(1X,''Abnormal exit: tmax < tmin in two subsequent iterations.'')') END IF END IF IF (iterm == -2) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''Number of restarts > '',I5''.'')') nout IF (iterm == -3) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''Failure in function calculations.'')') IF (iterm == -4) WRITE (6,FMT='(1X,''Abnormal exit: '' & ''Failure in attaining the demanded accuracy.'')') END IF END IF END SUBROUTINE ldgbm_wprint !************************************************************************ !* !* * SUBROUTINE ldgbm_rprint * !* !* Printout the (final) results. !* !************************************************************************ SUBROUTINE ldgbm_rprint(n,noutit,nit,nfe,ngrad,x,f,wk,qk,iterm,iprint) IMPLICIT NONE ! Scalar Arguments INTEGER, INTENT(IN) :: & n, & ! Number of variables noutit, & ! Number of used outer iterations. nit, & ! Number of used iterations. nfe, & ! Number of used function evaluations. ngrad, & ! Number of used discrete gradient calls. iprint, & ! Printout specification: ! -1 - No printout. ! 0 - Only the error messages. ! 1 - The final values of the objective ! function. ! 2 - The final values of the objective ! function and the most serious ! warning messages. ! 3 - The whole final solution. ! 4 - At each iteration values of the ! objective function. ! 5 - At each iteration the whole ! solution iterm ! Cause of termination: ! 1 - The problem has been solved with desired accuracy. ! 2 - Changes in function values < tolf in mtesf ! subsequent iterations. ! 3 - Changes in function value < tolf*small*MAX(|f_k|,|f_(k-1)|,1), ! where small is the smallest positive number such that ! 1.0 + small > 1.0. ! 4 - Number of function calls > mfe. ! 5 - Number of iterations > mit. ! 6 - Time limit exceeded. ! 7 - f < tolb. ! -1 - Two consecutive restarts. ! -2 - Number of restarts > maximum number of restarts. ! -3 - Failure in function or subgradient calculations ! (assigned by the user). ! -4 - Failure in attaining the demanded accuracy. ! -5 - Invalid input parameters. REAL(KIND=prec), INTENT(IN) :: & f, & ! Value of the objective function. wk, & ! Value of the first stopping criterion. qk ! Value of the second stopping criterion. ! Array Arguments REAL(KIND=prec), DIMENSION(:), INTENT(IN) :: & x ! Vector of variables ! Local Scalars INTEGER :: i ! Intermediate results IF (iterm == 0) THEN IF (iprint > 3) WRITE (6,FMT='(1X,''nout='',I3,2X,''nit='',I5,2X, & ''nfe='',I7,2X,''ndg='',I7,2X,''f='',D15.8,2X,''wk='',D11.4,2X, & ''qk='',D11.4,2X)') noutit,nit,nfe,ngrad,f,wk,qk IF (iprint == 5) WRITE (6,FMT='(1X,''x='', & 5D15.7:/(4X,5D15.7))')(x(i),i=1,n) RETURN END IF ! Final results IF (iprint > 0) WRITE (6,FMT='(1X,''nout='',I3,2X,''nit='',I5,2X, & ''nfe='',I7,2X,''ndg='',I7,2X,''f='',D15.8,2X,''wk='',D11.4,2X, & ''qk='',D11.4,2X,''iterm='',I3)') noutit,nit,nfe,ngrad,f,wk,qk,iterm IF (IPRINT .EQ. 3 .OR. IPRINT .EQ. 5) & WRITE (6,FMT='(1X,''x='',5D15.7:/(4X,5D15.7))')(x(i),i=1,n) END SUBROUTINE ldgbm_rprint END MODULE ldgbm_mod