psqp Subroutine

private subroutine psqp(me, nf, nb, nc, x, ix, xl, xu, cf, ic, cl, cu, cg, cfo, cfd, gc, ica, cr, cz, cp, gf, g, h, s, xo, go, xmax, tolx, tolc, tolg, rpf, cmax, gmax, f, mit, mfv, met, mec, iprnt, iterm)

recursive quadratic programming method with the bfgs variable metric update for general nonlinear programming problems.

Method

recursive quadratic programming method with the bfgs variable metric update.

Type Bound

psqp_class

Arguments

Type IntentOptional Attributes Name
class(psqp_class), intent(inout) :: me
integer :: nf

number of variables.

integer :: nb

choice of simple bounds.

  • nb=0 - simple bounds suppressed.
  • nb>0 - simple bounds accepted.
integer :: nc

number of linear constraints.

real(kind=wp) :: x(*)

x(nf) vector of variables.

integer, intent(inout) :: ix(*)

ix(nf) vector containing types of bounds.

  • ix(i)=0 - variable x(i) is unbounded.
  • ix(i)=1 - lover bound xl(i)<=x(i).
  • ix(i)=2 - upper bound x(i)<=xu(i).
  • ix(i)=3 - two side bound xl(i)<=x(i)<=xu(i).
  • ix(i)=5 - variable x(i) is fixed.
real(kind=wp) :: xl(*)

xl(nf) vector containing lower bounds for variables.

real(kind=wp) :: xu(*)

xu(nf) vector containing upper bounds for variables.

real(kind=wp) :: cf(*)

cf(nc+1) vector containing values of the constraint functions.

integer, intent(inout) :: ic(*)

ic(nc) vector containing types of constraints.

  • ic(kc)=0 - constraint cf(kc) is not used.
  • ic(kc)=1 - lower constraint cl(kc)<=cf(kc).
  • ic(kc)=2 - upper constraint cf(kc)<=cu(kc).
  • ic(kc)=3 - two side constraint cl(kc)<=cf(kc)<=cu(kc).
  • ic(kc)=5 - equality constraint cf(kc)==cl(kc).
real(kind=wp) :: cl(*)

cl(nc) vector containing lower bounds for constraint functions.

real(kind=wp) :: cu(*)

cu(nc) vector containing upper bounds for constraint functions.

real(kind=wp) :: cg(*)

cg(nf*nc) matrix whose columns are normals of the linear constraints.

real(kind=wp) :: cfo(*)

cfo(nc) vector containing saved values of the constraint functions.

real(kind=wp) :: cfd(*)

cfd(nc) vector containing increments of the constraint functions.

real(kind=wp) :: gc(*)

gc(nf) gradient of the selected constraint function.

integer :: ica(*)

ica(nf) vector containing indices of active constraints.

real(kind=wp) :: cr(*)

cr(nf*(nf+1)/2) triangular decomposition of kernel of the orthogonal projection.

real(kind=wp) :: cz(*)

cz(nf) vector of lagrange multipliers.

real(kind=wp) :: cp(*)
real(kind=wp) :: gf(*)

gf(nf) gradient of the model function.

real(kind=wp) :: g(*)

g(nf) gradient of the objective function.

real(kind=wp) :: h(*)

h(nf*(nf+1)/2) triangular decomposition or inversion of the hessian matrix approximation.

real(kind=wp) :: s(*)

s(nf) direction vector.

real(kind=wp) :: xo(*)

xo(nf) vectors of variables difference.

real(kind=wp) :: go(*)

go(nf) gradients difference.

real(kind=wp) :: xmax

maximum stepsize.

real(kind=wp) :: tolx

tolerance for change of variables.

real(kind=wp) :: tolc

tolerance for constraint violations.

real(kind=wp) :: tolg

tolerance for the gradient of the lagrangian function.

real(kind=wp) :: rpf

penalty coefficient.

real(kind=wp) :: cmax

maximum constraint violation.

real(kind=wp) :: gmax

maximum partial derivative of the lagrangian function.

real(kind=wp) :: f

value of the objective function.

integer :: mit

maximum number of iterations.

integer :: mfv

maximum number of function evaluations.

integer :: met

variable metric update used.

  • met=1 - the bfgs update.
  • met=2 - the hoshino update.
integer :: mec

correction if the negative curvature occurs.

  • mec=1 - correction suppressed.
  • mec=2 - powell's correction.
integer :: iprnt

print specification.

  • iprnt=0 - no print.
  • abs(iprnt)=1 - print of final results.
  • abs(iprnt)=2 - print of final results and iterations.
  • iprnt>0 - basic final results.
  • iprnt<0 - extended final results.
integer :: iterm

variable that indicates the cause of termination.

  • iterm=1-if abs(x-xo) was less than or equal to tolx in mtesx (usually two) subsequent iterations.
  • iterm=2-if abs(f-fo) was less than or equal to tolf in mtesf (usually two) subsequent iterations.
  • iterm=3-if f is less than or equal to tolb.
  • iterm=4-if gmax is less than or equal to tolg.
  • iterm=11-if nit exceeded mit.
  • iterm=12-if nfv exceeded mfv.
  • iterm=13-if nfg exceeded mfg.
  • iterm<0-if the method failed.
  • if iterm=-6, then the termination criterion has not been satisfied, but the point obtained if usually acceptable.

Calls

proc~~psqp~~CallsGraph proc~psqp psqp_class%psqp proc~bfgs_variable_metric_update bfgs_variable_metric_update proc~psqp->proc~bfgs_variable_metric_update proc~compute_augmented_lagrangian compute_augmented_lagrangian proc~psqp->proc~compute_augmented_lagrangian proc~compute_con_and_dcon psqp_class%compute_con_and_dcon proc~psqp->proc~compute_con_and_dcon proc~compute_new_penalty_parameters compute_new_penalty_parameters proc~psqp->proc~compute_new_penalty_parameters proc~compute_obj_and_dobj psqp_class%compute_obj_and_dobj proc~psqp->proc~compute_obj_and_dobj proc~dual_range_space_qp dual_range_space_qp proc~psqp->proc~dual_range_space_qp proc~dual_range_space_quad_prog psqp_class%dual_range_space_quad_prog proc~psqp->proc~dual_range_space_quad_prog proc~extended_line_search psqp_class%extended_line_search proc~psqp->proc~extended_line_search proc~mxdsmi mxdsmi proc~psqp->proc~mxdsmi proc~mxvcop mxvcop proc~psqp->proc~mxvcop proc~mxvdir mxvdir proc~psqp->proc~mxvdir proc~mxvdot mxvdot proc~psqp->proc~mxvdot proc~mxvina mxvina proc~psqp->proc~mxvina proc~mxvmax mxvmax proc~psqp->proc~mxvmax proc~mxvset mxvset proc~psqp->proc~mxvset proc~test_simple_bound test_simple_bound proc~psqp->proc~test_simple_bound proc~transform_incompatible_qp_subproblem transform_incompatible_qp_subproblem proc~psqp->proc~transform_incompatible_qp_subproblem proc~bfgs_variable_metric_update->proc~mxvcop proc~bfgs_variable_metric_update->proc~mxvdir proc~bfgs_variable_metric_update->proc~mxvdot proc~mxdpgb mxdpgb proc~bfgs_variable_metric_update->proc~mxdpgb proc~mxdpgp mxdpgp proc~bfgs_variable_metric_update->proc~mxdpgp proc~mxdpgs mxdpgs proc~bfgs_variable_metric_update->proc~mxdpgs proc~mxdpgu mxdpgu proc~bfgs_variable_metric_update->proc~mxdpgu proc~mxvdif mxvdif proc~bfgs_variable_metric_update->proc~mxvdif proc~mxvscl mxvscl proc~bfgs_variable_metric_update->proc~mxvscl proc~compute_con_and_dcon->proc~mxvcop proc~mxvneg mxvneg proc~compute_obj_and_dobj->proc~mxvneg proc~dual_range_space_qp->proc~mxvdir proc~dual_range_space_qp->proc~mxvdif proc~mxvsav mxvsav proc~dual_range_space_qp->proc~mxvsav proc~dual_range_space_quad_prog->proc~mxvcop proc~dual_range_space_quad_prog->proc~mxvdir proc~dual_range_space_quad_prog->proc~mxvina proc~determine_new_active_linear_constr determine_new_active_linear_constr proc~dual_range_space_quad_prog->proc~determine_new_active_linear_constr proc~determine_new_active_simple_bound determine_new_active_simple_bound proc~dual_range_space_quad_prog->proc~determine_new_active_simple_bound proc~dual_range_space_quad_prog->proc~mxdpgb proc~mxdpgf mxdpgf proc~dual_range_space_quad_prog->proc~mxdpgf proc~mxdprb mxdprb proc~dual_range_space_quad_prog->proc~mxdprb proc~mxdsmm mxdsmm proc~dual_range_space_quad_prog->proc~mxdsmm proc~mxvinv mxvinv proc~dual_range_space_quad_prog->proc~mxvinv proc~dual_range_space_quad_prog->proc~mxvneg proc~ops_after_constr_deletion psqp_class%ops_after_constr_deletion proc~dual_range_space_quad_prog->proc~ops_after_constr_deletion proc~update_tri_decomp_general update_tri_decomp_general proc~dual_range_space_quad_prog->proc~update_tri_decomp_general proc~line_search_interpolation line_search_interpolation proc~extended_line_search->proc~line_search_interpolation proc~determine_new_active_linear_constr->proc~mxvdot proc~mxdpgu->proc~mxvscl proc~update_tri_decomp_orthogonal update_tri_decomp_orthogonal proc~ops_after_constr_deletion->proc~update_tri_decomp_orthogonal proc~update_tri_decomp_general->proc~mxvcop proc~update_tri_decomp_general->proc~mxvdot proc~update_tri_decomp_general->proc~mxvset proc~update_tri_decomp_general->proc~mxdpgb proc~update_tri_decomp_general->proc~mxdprb proc~update_tri_decomp_general->proc~mxdsmm proc~mxdsmv mxdsmv proc~update_tri_decomp_general->proc~mxdsmv proc~update_tri_decomp_orthogonal->proc~mxvcop proc~update_tri_decomp_orthogonal->proc~mxvset proc~mxvort mxvort proc~update_tri_decomp_orthogonal->proc~mxvort proc~mxvrot mxvrot proc~update_tri_decomp_orthogonal->proc~mxvrot

Called by

proc~~psqp~~CalledByGraph proc~psqp psqp_class%psqp proc~psqpn psqp_class%psqpn proc~psqpn->proc~psqp

Source Code

   subroutine psqp(me, nf, nb, nc, x, ix, xl, xu, cf, ic, cl, cu, cg, cfo, cfd, gc, ica, &
                   cr, cz, cp, gf, g, h, s, xo, go, xmax, tolx, tolc, tolg, rpf, &
                   cmax, gmax, f, mit, mfv, met, mec, iprnt, iterm)

      class(psqp_class), intent(inout) :: me
      real(wp) :: f         !! value of the objective function.
      real(wp) :: cmax      !! maximum constraint violation.
      real(wp) :: gmax      !! maximum partial derivative of the lagrangian function.
      real(wp) :: rpf       !! penalty coefficient.
      real(wp) :: tolx      !! tolerance for change of variables.
      real(wp) :: tolc      !! tolerance for constraint violations.
      real(wp) :: tolg      !! tolerance for the gradient of the lagrangian function.
      real(wp) :: told      !!
      real(wp) :: tols      !!
      real(wp) :: xmax      !! maximum stepsize.
      integer :: iprnt      !! print specification.
                            !!
                            !! * iprnt=0      - no print.
                            !! * abs(iprnt)=1 - print of final results.
                            !! * abs(iprnt)=2 - print of final results and iterations.
                            !! * iprnt>0      - basic final results.
                            !! * iprnt<0      - extended final results.
      integer :: iterm      !! variable that indicates the cause of termination.
                            !!
                            !! * iterm=1-if abs(x-xo) was less than or equal to tolx in
                            !!   mtesx (usually two) subsequent iterations.
                            !! * iterm=2-if abs(f-fo) was less than or equal to tolf in
                            !!   mtesf (usually two) subsequent iterations.
                            !! * iterm=3-if f is less than or equal to tolb.
                            !! * iterm=4-if gmax is less than or equal to tolg.
                            !! * iterm=11-if nit exceeded mit.
                            !! * iterm=12-if nfv exceeded mfv.
                            !! * iterm=13-if nfg exceeded mfg.
                            !! * iterm<0-if the method failed.
                            !! * if iterm=-6, then the termination criterion has not been
                            !!   satisfied, but the point obtained if usually acceptable.
      integer :: met        !! variable metric update used.
                            !!
                            !! * met=1 - the bfgs update.
                            !! * met=2 - the hoshino update.
      integer :: met1       !!
      integer :: mec        !! correction if the negative curvature occurs.
                            !!
                            !! * mec=1 - correction suppressed.
                            !! * mec=2 - powell's correction.
      integer :: mes        !!
      integer :: mfv        !! maximum number of function evaluations.
      integer :: mit        !! maximum number of iterations.
      integer :: nb         !! choice of simple bounds.
                            !!
                            !! * nb=0 - simple bounds suppressed.
                            !! * nb>0 - simple bounds accepted.
      integer :: nc         !! number of linear constraints.
      integer :: nf         !! number of variables.
      real(wp) :: cf(*)     !! cf(nc+1)  vector containing values of the constraint functions.
      real(wp) :: cg(*)     !! cg(nf*nc)  matrix whose columns are normals of the linear constraints.
      real(wp) :: cfo(*)    !! cfo(nc)  vector containing saved values of the constraint functions.
      real(wp) :: cfd(*)    !! cfd(nc)  vector containing increments of the constraint functions.
      real(wp) :: cl(*)     !! cl(nc)  vector containing lower bounds for constraint functions.
      real(wp) :: cu(*)     !! cu(nc)  vector containing upper bounds for constraint functions.
      real(wp) :: cp(*)     !!
      real(wp) :: cr(*)     !! cr(nf*(nf+1)/2)  triangular decomposition of kernel
                            !! of the orthogonal projection.
      real(wp) :: cz(*)     !! cz(nf)  vector of lagrange multipliers.
      real(wp) :: g(*)      !! g(nf)  gradient of the objective function.
      real(wp) :: gc(*)     !! gc(nf)  gradient of the selected constraint function.
      real(wp) :: gf(*)     !! gf(nf)  gradient of the model function.
      real(wp) :: go(*)     !! go(nf)  gradients difference.
      real(wp) :: h(*)      !! h(nf*(nf+1)/2)  triangular decomposition or inversion of
                            !! the hessian matrix approximation.
      real(wp) :: s(*)      !! s(nf)  direction vector.
      real(wp) :: x(*)      !! x(nf)  vector of variables.
      real(wp) :: xl(*)     !! xl(nf)  vector containing lower bounds for variables.
      real(wp) :: xu(*)     !! xu(nf)  vector containing upper bounds for variables.
      real(wp) :: xo(*)     !! xo(nf)  vectors of variables difference.
      integer,intent(inout) :: ic(*) !! ic(nc)  vector containing types of constraints.
                                     !!
                                     !! * ic(kc)=0 - constraint cf(kc) is not used.
                                     !! * ic(kc)=1 - lower constraint cl(kc)<=cf(kc).
                                     !! * ic(kc)=2 - upper constraint cf(kc)<=cu(kc).
                                     !! * ic(kc)=3 - two side constraint cl(kc)<=cf(kc)<=cu(kc).
                                     !! * ic(kc)=5 - equality constraint cf(kc)==cl(kc).
      integer :: ica(*)     !! ica(nf)  vector containing indices of active constraints.
      integer,intent(inout) :: ix(*) !! ix(nf)  vector containing types of bounds.
                                     !!
                                     !! * ix(i)=0 - variable x(i) is unbounded.
                                     !! * ix(i)=1 - lover bound xl(i)<=x(i).
                                     !! * ix(i)=2 - upper bound x(i)<=xu(i).
                                     !! * ix(i)=3 - two side bound xl(i)<=x(i)<=xu(i).
                                     !! * ix(i)=5 - variable x(i) is fixed.

      real(wp) :: alf1, alf2, cmaxo, dmax, eps7, eps9, eta0, &
                  eta2, eta9, fmax, fmin, fo, gnorm, p, po, &
                  r, rmax, rmin, ro, snorm, tolb, tolf, &
                  umax, rp, fp, pp, ff, fc
      integer :: i, idecf, iext, irest, iterd, iterh, iterq, &
                 iters, kbc, kbf, kc, kd, kit, ld, mred, mtesf, &
                 mtesx, n, k, ntesx, iest, inits, kters, maxst, &
                 isys, mfp, nred, ipom, lds

      if (abs(iprnt) > 1) write (6, '(1x,"entry to psqp :")')

      ! initiation
      kbf = 0
      kbc = 0
      if (nb > 0) kbf = 2
      if (nc > 0) kbc = 2
      me%nres = 0
      me%ndec = 0
      me%nrem = 0
      me%nadd = 0
      me%nit = 0
      me%nfv = 0
      me%nfg = 0
      me%nfh = 0
      isys = 0
      iest = 0
      iext = 0
      mtesx = 2
      mtesf = 2
      inits = 1
      iterm = 0
      iters = 0
      iterd = 0
      iterq = 0
      mred = 20
      irest = 1
      iters = 2
      kters = 5
      idecf = 1
      eta0 = 1.0e-15_wp
      eta2 = 1.0e-15_wp
      eta9 = huge(1.0_wp) !1.0e60_wp
      eps7 = 1.0e-15_wp
      eps9 = 1.0e-8_wp
      alf1 = 1.0e-10_wp
      alf2 = 1.0e10_wp
      fmax = huge(1.0_wp) !1.0e60_wp
      fmin = -fmax
      tolb = -fmax
      dmax = eta9
      tolf = 1.0e-16_wp
      if (xmax <= 0.0_wp) xmax = 1.0e+16_wp
      if (tolx <= 0.0_wp) tolx = 1.0e-16_wp
      if (tolg <= 0.0_wp) tolg = 1.0e-6_wp
      if (tolc <= 0.0_wp) tolc = 1.0e-6_wp
      told = 1.0e-8_wp
      tols = 1.0e-4_wp
      if (rpf <= 0.0_wp) rpf = 1.0e-4_wp
      if (met <= 0) met = 1
      met1 = 2
      if (mec <= 0) mec = 2
      mes = 1
      if (mit <= 0) mit = 1000
      if (mfv <= 0) mfv = 2000
      kd = 1
      ld = -1
      kit = 0
      call mxvset(nc, 0.0_wp, cp)
      ! initial operations with simple bounds
      if (kbf > 0) then
         do i = 1, nf
            if ((ix(i) == 3 .or. ix(i) == 4) .and. xu(i) <= xl(i)) then
               xu(i) = xl(i)
               ix(i) = 5
            elseif (ix(i) == 5 .or. ix(i) == 6) then
               xl(i) = x(i)
               xu(i) = x(i)
               ix(i) = 5
            end if
            if (ix(i) == 1 .or. ix(i) == 3) x(i) = max(x(i), xl(i))
            if (ix(i) == 2 .or. ix(i) == 3) x(i) = min(x(i), xu(i))
         end do
      end if
      ! initial operations with general constraints
      if (kbc > 0) then
         k = 0
         do kc = 1, nc
            if ((ic(kc) == 3 .or. ic(kc) == 4) .and. cu(kc) <= cl(kc)) then
               cu(kc) = cl(kc)
               ic(kc) = 5
            elseif (ic(kc) == 5 .or. ic(kc) == 6) then
               cu(kc) = cl(kc)
               ic(kc) = 5
            end if
            k = k + nf
         end do
      end if
      if (kbf > 0) then
         do i = 1, nf
            if (ix(i) >= 5) ix(i) = -ix(i)
            if (ix(i) <= 0) then
            elseif ((ix(i) == 1 .or. ix(i) == 3) .and. x(i) <= xl(i)) then
               x(i) = xl(i)
            elseif ((ix(i) == 2 .or. ix(i) == 3) .and. x(i) >= xu(i)) then
               x(i) = xu(i)
            end if
            call test_simple_bound(x, ix, xl, xu, eps9, i)
            if (ix(i) > 10) ix(i) = 10 - ix(i)
         end do
      end if
      fo = fmin
      gmax = eta9
      dmax = eta9

      main: do

         lds = ld
         call me%compute_obj_and_dobj(nf, x, gf, gf, ff, f, kd, ld, iext)
         ld = lds
         call me%compute_con_and_dcon(nf, nc, x, fc, cf, cl, cu, ic, gc, cg, cmax, kd, ld)
         cf(nc + 1) = f
         ! JW : seems to start with iter 0, so add 1 to iterations for report output
         if (associated(me%report)) call me%report(me%nit+1,x(1:nf),j=f,f=cf(1:nc))    
         if (abs(iprnt) > 1) &
            write (6, '(1x,"nit=",i9,2x,"nfv=",i9,2x,"nfg=",i9,2x,"f=",g13.6,2x,"c=",e8.1,2x,"g=",e8.1)') &
            me%nit, me%nfv, me%nfg, f, cmax, gmax
         ! start of the iteration with tests for termination.
         if (iterm < 0) exit main
         if (iters /= 0) then
            if (f <= tolb) then
               iterm = 3
               exit main
            end if
            if (dmax <= tolx) then
               iterm = 1
               ntesx = ntesx + 1
               if (ntesx >= mtesx) exit main
            else
               ntesx = 0
            end if
         end if
         if (me%nit >= mit) then
            iterm = 11
            exit main
         end if
         if (me%nfv >= mfv) then
            iterm = 12
            exit main
         end if
         iterm = 0
         me%nit = me%nit + 1

         restart: do

            ! restart
            n = nf
            if (irest > 0) then
               call mxdsmi(n, h)
               ld = min(ld, 1)
               idecf = 1
               if (kit < me%nit) then
                  me%nres = me%nres + 1
                  kit = me%nit
               else
                  iterm = -10
                  if (iters < 0) iterm = iters - 5
                  exit main
               end if
            end if
            ! direction determination using a quadratic programming procedure
            call mxvcop(nc + 1, cf, cfo)
            mfp = 2
            ipom = 0
            dir_loop: do
               call me%dual_range_space_quad_prog(nf, nc, x, ix, xl, xu, cf, cfd, ic, ica, &
                                                  cl, cu, cg, cr, cz, g, gf, h, s, mfp, kbf, &
                                                  kbc, idecf, eta2, eta9, eps7, &
                                                  eps9, umax, gmax, n, iterq)
               if (iterq < 0) then
                  if (ipom < 10) then
                     ipom = ipom + 1
                     call transform_incompatible_qp_subproblem(nc, cf, ic, cl, cu, kbc)
                     cycle dir_loop
                  end if
                  iterd = iterq - 10
               else
                  ipom = 0
                  iterd = 1
                  gmax = mxvmax(nf, g)
                  gnorm = sqrt(mxvdot(nf, g, g))
                  snorm = sqrt(mxvdot(nf, s, s))
               end if
               exit dir_loop
            end do dir_loop
            if (iterd < 0) iterm = iterd
            if (iterm == 0) then
               call mxvcop(nc + 1, cfo, cf)
               ! test for sufficient descent
               p = mxvdot(nf, g, s)
               irest = 1
               if (snorm <= 0.0_wp) then
               elseif (p + told*gnorm*snorm <= 0.0_wp) then
                  irest = 0
               end if
               if (irest /= 0) cycle restart
               nred = 0
               rmin = alf1*gnorm/snorm
               rmax = min(alf2*gnorm/snorm, xmax/snorm)
               if (gmax <= tolg .and. cmax <= tolc) then
                  iterm = 4
                  exit main
               end if
               call compute_new_penalty_parameters(nf, n, nc, ica, cz, cp)
               call mxvina(nc, ic)
               call compute_augmented_lagrangian(nf, n, nc, cf, ic, ica, cl, cu, cz, rpf, fc, f)
               ! preparation of line search
               ro = 0.0_wp
               fo = f
               po = p
               cmaxo = cmax
               call mxvcop(nf, x, xo)
               call mxvcop(nf, g, go)
               call mxvcop(nf, gf, cr)
               call mxvcop(nc + 1, cf, cfo)

               line_search: do

                  ! line search without directional derivatives
                  call me%extended_line_search(r, ro, rp, f, fo, fp, po, pp, fmin, fmax, &
                                               rmin, rmax, tols, kd, ld, me%nit, kit, nred, &
                                               mred, maxst, iest, inits, iters, kters, mes, isys)
                  if (isys == 0) then
                     kd = 1
                     ! decision after unsuccessful line search
                     if (iters <= 0) then
                        r = 0.0_wp
                        f = fo
                        p = po
                        call mxvcop(nf, xo, x)
                        call mxvcop(nf, cr, gf)
                        call mxvcop(nc + 1, cfo, cf)
                        irest = 1
                        ld = kd
                        cycle restart
                     end if
                     ! computation of the value and the gradient of the objective
                     ! function together with the values and the gradients of the
                     ! approximated functions
                     if (kd > ld) then
                        lds = ld
                        call me%compute_obj_and_dobj(nf, x, gf, gf, ff, f, kd, ld, iext)
                        ld = lds
                        call me%compute_con_and_dcon(nf, nc, x, fc, cf, cl, cu, ic, gc, &
                                                     cg, cmax, kd, ld)
                     end if
                     ! preparation of variable metric update
                     call mxvcop(nf, gf, g)
                     call dual_range_space_qp(nf, n, x, xo, ica, cg, cz, g, go, r, f, fo, p, po, &
                                              cmax, cmaxo, dmax, kd, ld, iters)
                     ! variable metric update
                     call bfgs_variable_metric_update(n, h, g, s, xo, go, r, po, me%nit, &
                                                      kit, iterh, met, met1, mec)
                     ! if (mer>0.and.iterh>0) irest=1
                     cycle main   ! end of the iteration
                  else
                     ! go to (11174,11172) isys+1
                     call mxvdir(nf, r, s, xo, x)
                     lds = ld
                     call me%compute_obj_and_dobj(nf, x, gf, g, ff, f, kd, ld, iext)
                     ld = lds
                     call me%compute_con_and_dcon(nf, nc, x, fc, cf, cl, cu, ic, gc, cg, cmax, kd, ld)
                     cf(nc + 1) = f
                     call compute_augmented_lagrangian(nf, n, nc, cf, ic, ica, cl, cu, cz, rpf, fc, f)
                  end if

               end do line_search

            end if

            exit restart
         end do restart

         exit main
      end do main

      if (iprnt > 1 .or. iprnt < 0) write (6, '(1x,"exit from psqp :")')
      if (iprnt /= 0) &
         write (6, '(1x,"nit=",i4,2x,"nfv=",i4,2x,"nfg=",i4,2x,"f=",g13.6,2x,"c=",e8.1,2x,"g=",e8.1,2x,"iterm=",i3)') &
                  me%nit, me%nfv, me%nfg, f, cmax, gmax, iterm
      if (iprnt < 0) write (6, '(1x,"x=",5(g14.7,1x):/(3x,5(g14.7,1x)))') (x(i), i=1, nf)

   end subroutine psqp