C      ALGORITHM 728, COLLECTED ALGORITHMS FROM ACM.
C      THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE,
C      VOL. 20, NO. 1, MARCH, 1994, PP. 120-123.
      subroutine qbpgen(rhom2,rhom4,nx,ny,m1,m2,m3,m4,lcondm,non0,
     1                  info,iseed)
      integer maxn
      parameter (maxn=2000)

c     **********
c
c     To change the precision of this program, run the change
c     program on qbpgen.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c     This routine generates random quadratic bilevel programs of
c     the form:
c
c     Minimize Q(x,y)= (1/2)(Mv)'(Mv) + c'(Mv) + nx/2
c
c     where v' = [ x' y' ] and y(x) solves the lower-level problem
c
c           minimize q(x,y)= (1/2)v'(MSM)v
c
c           subject to Av <= b
c
c     Here
c
c                                    ( Sxx  Sxy )
c      c' = [ -1(x)' 0(y)' ] and S = (          )
c                                    ( Sxy' Syy )
c
c     where Sxx is the order-nx zero matrix, Syy is the order-ny
c     identity matrix and
c
c                { -1  1 <= i=j <= m
c      (Sxy)   = {
c           ij   {  0  otherwise
c
c
c      and A = [ Ax Ay ] and  b = [ 1(m)'  rho' -1(m)' ]
c
c     with rho' = [ 1(m1)' rhom2' 2(m3)' rhom4' ] and
c
c           (  Px )       ( -Py )                    { 1  1 <= i=j <= m
c      Ax = (  Px ), Ay = (  Py ), (Px)   = (Py)   = {
c           ( -Px )       ( -Py )      ij       ij   { 0  otherwise
c
c     and
c
c      nx is the number of upper-level variables
c      ny is the number of lower-level variables
c       n is the total number of variables (ie. n=nx+ny)
c       m equals min{nx,ny}
c    0(v) is the zero vector of the same dimension as v,
c    1(v) is the ones vector of the same dimension as v,
c       M is a (sparse) positive definite matrix defined by M = HDH
c         where H is a block-diagonal matrix defined by H=diag(Hx,Hy),
c         Hx and Hy are order nx and ny Householder matrices generated
c         by the (Householder) unit 2-norm vectors zx and zy
c         respectively, z'=[zx' zy'] has non0 components from (-1,1)
c         in rows pz(1) through pz(non0), and D=diag(d(1) ,..., d(n))
c         is a positive definite diagonal matrix with 2-norm condition
c         10**lcondm
c       W is the inverse of M
c      m1 is as described below
c      m2 is as described below
c      m3 is as described below
c      m4 is as described below
c   rhom2 is as described below
c   rhom4 is as described below
c
c     This problem has 2^{m3} global solutions and an additional
c     2^{abs(m2)+m3+abs(m4)} - 2^{m3} local solutions.
c
c     The user is referred to:
c       Calamai, P.H. and Vicente, L.N., "Generating Quadratic Bilevel
c       Programming Test Problems", ACM TOMS, (1993)
c     for a description of how this is accomplished.
c
c     **********
c
c INTEGER INPUT PARAMETERS (unchanged on exit)
c
c nx     - the number of upper-level variables (1 <= nx <= maxn - ny)
c
c ny     - the number of lower-level variables (1 <= ny <= maxn - nx)
c
c m1     - in the untransformed space the components
c               (x(i),y(i)), i=1,...,m1
c          have their (only) minimizer at
c               (1,0)
c
c m2     - in the untransformed space the components
c              (x(m1+i),y(m1+i)), i=1,...,im2
c          have their global minimizer at
c            ((1+rhom2(i))/2,(rhom2(i)-1)/2), i=1,...,im2
c          respectively, and their local minimizer at
c                       (1/2,1/2)
c          where im2=abs(m2)
c
c m3     - in the untransformed space the components
c              (x(m1+im2+i),y(m1+im2+i)), i=1,...,m3
c          have their global minimizers at both
c              (1/2,1/2) and (3/2,1/2)
c
c m4     - in the untransformed space the components
c              (x(m1+im2+m3+i),y(m1+im2+m3+i)), i=1,...,im4
c          have their global minimizer at
c                       (1/2,1/2)
c          and their local minimizer at
c            ((1+rhom4(i))/2,(rhom4(i)-1)/2), i=1,...,im4
c          respectively, where im4=abs(m4).
c
c *************************************************
c NOTE - m1+im2+m3+im4 must equal m in this version
c *************************************************
c
c lcondm - log (base 10) of the condition number of M (lcondm >= 0)
c
c non0   - (maximum) number of nonzeros in z (0 < non0 <= n)
c
c INTEGER INPUT PARAMETERS (changed on exit)
c
c iseed  - see comments in subprogram rand
c
c REAL INPUT PARAMETERS
c
c rhom2  - real vector of length im2 that controls the minima
c          corresponding to components m1+1 through m1+im2 of x
c          and y as described above under m2.
c          The use of rhom2 depends on the sign of m2 as follows:
c
c        value   use
c
c        m2 < 0  input values are ignored and the im2 components of
c                rhom2 are generated randomly to fall in the open
c                interval (1,2)
c
c        m2 > 0  if -2 < rhom2(1) < -1 then the im2 components of
c                rhom2 are all set to -rhom2(1); otherwise, the
c                values that are input are used and these must all
c                lie in the open interval (1,2)
c
c rhom4  - real vector of length im4 that controls the minima
c          corresponding to components m1+im2+m3+1 through m1+im2+
c          m3+im4 of x and y as described above under m4.
c          The use of rhom4 depends on the sign of m4 as follows:
c
c        value   use
c
c        m4 < 0  input values are ignored and the im4 components of
c                rhom4 are generated randomly to fall in the open
c                interval (2,rhom4(1)).  NOTE: rhom4(1) must be
c                greater than 2 when m4 < 0.
c
c        m4 > 0  if rhom4(1) < -2 then the im4 components of
c                rhom4 are all set to -rhom4(1); otherwise, the
c                values that are input are used and these must all
c                be greater than 2
c
c DIAGNOSTIC PARAMETERS
c
c info - on exit contains a value indicating the state of program
c         qbpgen when it terminated
c
c     value     definition
c
c         0     program terminated normally
c
c        >0     the state is given by that subset of the following
c               conditions whose value sum to the value of info:
c
c            value   condition
c
c                1   nx and/or ny outside permissible range
c                2   lcondm outside permissible range
c                4   non0 outside permissible range
c                8   m1 and/or m2 and/or m3 and/or m4 outside
c                    permissible range
c               16   components of rhom2 outside permissible range
c               32   components of rhom4 outside permissible range
c
c PARAMETERS OF COMMON /M/
c
c d      - the diagonals of D
c
c z      - the Householder vectors that generate Hx and Hy
c
c pz     - row indices of (possible) nonzeros in z
c
c num0   - same as non0
c
c PARAMETERS OF COMMON /OBJ/
c
c c      - the coefficients of the linear term of Q(x,y)
c
c b      - the upper-bounds on the linear constraints
c
c PARAMETERS OF COMMON /DIM/
c
c dimx   - same as nx
c
c dimy   - same as ny
c
c im1    - same as m1
c
c im2    - abs(m2)
c
c im3    - same as m3
c
c im4    - abs(m4)
c
c m      - min(nx,ny)
c
c n      - nx+ny
c
c ********************
c Subprograms called
c   Modified Linpack:                copy
c   TOMS (MINPACK project) supplied: rand
c   Fortran supplied:                abs,min
c   Local suite:                     qbpmkm,dload
c ********************
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	October 26, 1991
c     Dates Modified:   July 7, 1992
c                       September 18, 1992
c
c ********************

c declarations for passed parameters

      integer nx,ny,m1,m2,m3,m4,lcondm,non0,info,iseed
c*****precision > double
      double precision rhom2(*),rhom4(*)
c*****end precision > double
c*****precision > single
c      real rhom2(*),rhom4(*)
c*****end precision > single

c declarations for local parameters

      logical fault
      integer i,msum
c*****precision > double
      double precision rho
c*****end precision > double
c*****precision > single
c      real rho
c*****end precision > single

c function declarations

      real rand
      intrinsic abs,min

c parameter declarations

c*****precision > double
      double precision minus2,minus1,zero,one,two
      parameter (minus2=-2.d0,minus1=-1.d0)
      parameter (zero=0.d0,one=1.d0,two=2.d0)
c*****end precision > double
c*****precision > single
c      real minus2,minus1,zero,one,two
c      parameter (minus2=-2.0,minus1=-1.0)
c      parameter (zero=0.0,one=1.0,two=2.0)
c*****end precision > single

c declarations for named common /m/

      integer num0
      integer pz(maxn)
c*****precision > double
      double precision d(maxn),z(maxn)
c*****end precision > double
c*****precision > single
c      real d(maxn),z(maxn)
c*****end precision > single
      common/m/d,z,pz,num0

c declarations for named common /obj/

c*****precision > double
      double precision c(maxn),b(3*maxn/2)
c*****end precision > double
c*****precision > single
c      real c(maxn),b(3*maxn/2)
c*****end precision > single
      common/obj/c,b

c declarations for named common /dim/

      integer dimx,dimy,im1,im2,im3,im4,m,n
      common/dim/dimx,dimy,im1,im2,im3,im4,m,n

c store information for commons

      dimx = nx
      dimy = ny
      im1  = m1
      im2  = abs(m2)
      im3  = m3
      im4  = abs(m4)
      m    = min(nx,ny)
      n    = nx + ny
      num0 = non0

c check validity of integer input parameters and set info

      msum = m1+im2+m3+im4
      info = 0
      if (nx.lt.1 .or. ny.lt.1 .or. n.gt.maxn) then
        info=1
      endif
      if (lcondm.lt.0) then
        info=info+2
      endif
      if (non0.lt.1 .or. non0.gt.n) then
        info=info+4
      endif
      if (m1.lt.0 .or. m3.lt.0 .or. msum.ne.m) then
        info=info+8
      endif
      if (info.ne.0) return

c check and adjust rhom2 when appropriate

      if (m2.ne.0) then
        if (m2.gt.0) then
          if (minus2.lt.rhom2(1) .and. rhom2(1).lt.minus1) then
            rho=-rhom2(1)
            call dload(im2,rho,rhom2,1)
          else
            fault=.false.
            do 10 i=1,im2
              if (rhom2(i).lt.one .or. rhom2(i).gt.two) fault=.true.
   10       continue
            if (fault) info=info+16
          endif
        else
          do 20 i=1,im2
            rhom2(i)=rand(iseed)+one
   20     continue
        endif
      endif

c check and adjust rhom4 when appropriate

      if (m4.ne.0) then
        if (m4.gt.0) then
          if (rhom4(1).lt.minus2) then
            rho=-rhom4(1)
            call dload(im4,rho,rhom4,1)
          else
            fault=.false.
            do 30 i=1,im4
              if (rhom4(i).lt.two) fault=.true.
   30       continue
            if (fault) info=info+32
          endif
        else
          rho=rhom4(1)
          if (rho.le.two) then
            info=info+32
          else
            do 40 i=1,im4
              rhom4(i)=rho*rand(iseed)+two
   40       continue
          endif
        endif
      endif
      if (info.ne.0) return

c store data for constructing M

      call qbpmkm(lcondm,iseed)

c construct c

      call dload(nx,minus1,c,1)
      call dload(ny,zero,c(nx+1),1)

c construct b

      call dload(m,one,b,1)
      call dload(m1,one,b(m+1),1)
      call copy(im2,rhom2,1,b(m+m1+1),1)
      call dload(m3,two,b(m+m1+im2+1),1)
      call copy(im4,rhom4,1,b(m+m1+im2+m3+1),1)
      call dload(m,minus1,b(m+m+1),1)

c end of subroutine qbpgen

      end
      subroutine qbpfun(v,upper,lower,res)
      integer maxn
      parameter (maxn=2000)

c     **********
c
c     This subroutine computes the value of the upper-
c     and lower-level objectives and the residuals of
c     the lower-level constraints of the quadratic bilevel
c     programming problem generated using subroutine
c     qbpgen
c
c     Details of this problem generation can be found
c     in the comments of qbpgen
c
c     To change the precision of this program, run the change
c     program on qbpfun.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c     **********
c     Subprograms called
c        Modified Linpack: dot
c        Local suite:      qbpax,qbpmx,qbpsx
c     **********
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	October 26, 1991
c     Date Modified:	September 18, 1992
c
c     **********

c declarations for passed parameters

c*****precision > double
      double precision v(*)
      double precision upper,lower
      double precision res(*)
c*****end precision > double
c*****precision > single
c      real v(*)
c      real upper,lower
c      real res(*)
c*****end precision > single

c declarations for local parameters

c*****precision > double
      double precision mv(maxn),smv(maxn)
c*****end precision > double
c*****precision > single
c      real mv(maxn),smv(maxn)
c*****end precision > single
      integer i,mm

c function declarations

c*****precision > double
      double precision dot
c*****end precision > double
c*****precision > single
c      real dot
c*****end precision > single

c parameter declarations

c*****precision > double
      double precision two
      parameter (two=2.d0)
c*****end precision > double
c*****precision > single
c      real two
c      parameter (two=2.0)
c*****end precision > single

c declarations for named common /m/

c*****precision > double
      double precision d(maxn),z(maxn)
c*****end precision > double
c*****precision > single
c      real d(maxn),z(maxn)
c*****end precision > single
      integer num0
      integer pz(maxn)
      common/m/d,z,pz,num0

c declarations for named common /obj/

c*****precision > double
      double precision c(maxn),b(3*maxn/2)
c*****end precision > double
c*****precision > single
c      real c(maxn),b(3*maxn/2)
c*****end precision > single
      common/obj/c,b

c declarations for named common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c store Mv in mv

      call qbpmx(v,mv,.false.)

c compute the upper-level objective

      upper=nx/two
      do 10 i=1,n
        upper = upper + mv(i)*(mv(i)/two + c(i))
   10 continue

c store S(Mv) in smv

      call qbpsx(mv,smv)

c compute the lower-level objective

c*****precision > double
      lower=dot(n,mv,1,smv,1)/two
c*****end precision > double
c*****precision > single
c      lower=dot(n,mv,1,smv,1)/two
c*****end precision > single

c compute the residuals

      call qbpax(mv,res)
      mm=m+m
      do 30 i=1,m
        res(i)     = b(i)     - res(i)
        res(m+i)   = b(m+i)   - res(m+i)
        res(mm+i)  = b(mm+i)  - res(mm+i)
   30 continue
      return

c last card of subroutine qbpfun

      end
      subroutine qbpchk(v,mr,errl2,type)
      integer maxn
      parameter (maxn=2000)

c     **********
c
c     This subroutine checks Wv (the point corresponding to v
c     in the untransformed space) and finds the closest (local
c     or global) solution r (in the untransformed space) to
c     the problem generated by subroutine qbpgen and returns:
c
c      errl2 - The l2 distance from Wv to r (and an upper-bound
c              on the distance from v to Mr)
c      mr    - The point corresponding to r in the transformed
c              space (ie. Mr)
c      type  - A classifier for the point mr
c
c        value  classification
c
c          1     mr is the unique global minimizer of the
c                untransformed problem
c          2     mr is a nonunique global minimizer of the
c                untransformed problem
c          3     mr is a local minimizer of the untransformed
c                problem
c
c     To change the precision of this program, run the change
c     program on qbpchk.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c ********************
c Subprograms called
c   Fortran supplied: abs, sqrt
c   Local suite:      qbpmx
c ********************
c
c    Authors:		Paul H. Calamai and Luis N. Vicente
c    Date Written:	October 26, 1991
c    Date Modified:	September 18, 1992
c
c ********************

c declarations for passed parameters

      integer type
c*****precision > double
      double precision v(*),mr(*)
      double precision errl2
c*****end precision > double
c*****precision > single
c      real v(*),mr(*)
c      real errl2
c*****end precision > single

c declarations for local parameters

      integer i,istart,iend
c*****precision > double
      double precision xtog,ytog,errtog,xtol,ytol,errtol
      double precision rhok,temp
      double precision wv(maxn)
c*****end precision > double
c*****precision > single
c      real xtog,ytog,errtog,xtol,ytol,errtol
c      real rhok,temp
c      real wv(maxn)
c*****end precision > single

c function declarations

      intrinsic abs,sqrt

c parameter declarations

c*****precision > double
      double precision zero,half,one,trehlf,two
      parameter (zero=0.d0,half=0.5d0,one=1.d0,trehlf=1.5d0,two=2.d0)
c*****end precision > double
c*****precision > single
c      real zero,half,one,trehlf,two
c      parameter (zero=0.0,half=0.50,one=1.0,trehlf=1.50,two=2.0)
c*****end precision > single

c declarations for named common /obj/

c*****precision > double
      double precision c(maxn),b(3*maxn/2)
c*****end precision > double
c*****precision > single
c      real c(maxn),b(3*maxn/2)
c*****end precision > single
      common/obj/c,b

c declarations for named common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c obtain Wv

      call qbpmx(v,wv,.true.)

c find the closest solution (in the untransformed space)
c to Wv (ie. find r)

      type=1
      errl2=zero

c check the components in M3 first

      if (m3.gt.0) then
        type=2
        istart=m1+m2+1
        iend=istart+m3-1
        do 10 i=istart,iend
          xtol=abs(wv(i)-half)
          xtog=abs(wv(i)-trehlf)
          mr(i)=trehlf
          if (xtog.gt.xtol) then
            xtog=xtol
            mr(i)=half
          endif
          ytog=abs(wv(nx+i)-half)
          mr(nx+i)=half
          errl2=errl2+xtog**2+ytog**2
   10   continue
      endif

c check the components in M1 second

      if (m1.gt.0) then
        istart=1
        iend=m1
        do 20 i=istart,iend
          xtog=abs(wv(i)-one)
          ytog=abs(wv(nx+i))
          mr(i)    = one
          mr(nx+i) = zero
          errl2   = errl2+xtog**2+ytog**2
   20   continue
      endif

c check the components in M2 third

      if (m2.gt.0) then
        istart=m1+1
        iend=istart+m2-1
        do 30 i=istart,iend
          rhok=b(m+i)
          temp=(one+rhok)/two
          xtol   = abs(wv(i)-half)
          ytol   = abs(wv(nx+i)-half)
          errtol = xtol**2+ytol**2
          xtog   = abs(wv(i)-temp)
          ytog   = abs(wv(nx+i)-temp+one)
          errtog = xtog**2+ytog**2
          if (errtog.lt.errtol) then
            errl2    = errl2+errtog
            mr(i)    = temp
            mr(nx+i) = temp-one
          else
            type     = 3
            errl2    = errl2+errtol
            mr(i)    = half
            mr(nx+i) = half
          endif
   30   continue
      endif

c check the components in M4 fourth

      if (m4.gt.0) then
        istart=m1+m2+m3+1
        iend=istart+m4-1
        do 40 i=istart,iend
          rhok=b(m+i)
          temp=(one+rhok)/two
          xtog   = abs(wv(i)-half)
          ytog   = abs(wv(nx+i)-half)
          errtog = xtog**2+ytog**2
          xtol   = abs(wv(i)-temp)
          ytol   = abs(wv(nx+i)-temp+one)
          errtol = xtol**2+ytol**2
          if (errtog.lt.errtol) then
            errl2    = errl2+errtog
            mr(i)    = half
            mr(nx+i) = half
          else
            type     = 3
            errl2    = errl2+errtol
            mr(i)    = temp
            mr(nx+i) = temp-one
          endif
   40   continue
      endif

c check the components of x with index greater than m

      if (nx.gt.m) then
        istart=m1+m2+m3+m4+1
        iend=istart+nx-m-1
        do 50 i=istart,iend
          xtog  = abs(wv(i)-one)
          errl2 = errl2+xtog**2
          mr(i) = one
   50   continue
      endif

c check the components of y with index greater than m

      if (ny.gt.m) then
        istart=nx+m1+m2+m3+m4+1
        iend=istart+ny-m-1
        do 60 i=istart,iend
          ytog  = abs(wv(i))
          errl2 = errl2+ytog**2
          mr(i) = zero
   60   continue
      endif

      errl2=sqrt(errl2)

c transform mr to get point Mr in transformed space

      call qbpmx(mr,mr,.false.)

c end of subroutine qbpchk

      end
      subroutine qbpax(x,y)

c     **********
c     This subroutine forms the product Ax where A is defined as:
c
c     A = [ Ax Ay ] and
c
c          (  Px )       ( -Py )                    { 1  1 <= i=j <= m
c     Ax = (  Px ), Ay = (  Py ), (Px)   = (Py)   = {
c          ( -Px )       ( -Py )      ij       ij   { 0  otherwise
c
c     See comments in subroutine qbpgen
c
c     To change the precision of this program, run the change
c     program on qbpax.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c     **********
c     Subprograms called
c     **********
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	October 26, 1991
c     Date Modified:	September 18, 1992
c
c     **********

c declarations for passed parameters

c*****precision > double
      double precision x(*),y(*)
c*****end precision > double
c*****precision > single
c      real x(*),y(*)
c*****end precision > single

c declarations for local parameters

      integer i,mm

c declarations for named common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

      mm=m+m
      do 10 i=1,m
        y(i)     =  x(i) - x(nx+i)
        y(m+i)   =  x(i) + x(nx+i)
        y(mm+i)  = -y(m+i)
   10 continue
      return

c last card of subroutine qbpax

      end
      subroutine qbpmx(x,y,invert)
      integer maxn
      parameter (maxn=2000)

c     **********
c
c     This subroutine forms the product Mx (or M**(-1)x when invert
c     is true), where M is the transformation constructed in
c     subroutine qbpmkm (see comments in subroutine qbpmkm and in
c     subroutine qbpgen).
c
c     To change the precision of this program, run the change
c     program on qbpmx.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c     **********
c     Subprograms called
c       Modified Linpack: copy
c       Local suite:      qbpdot
c     **********
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	October 26, 1991
c     Dates Modified:   July 7, 1992
c                       September 18, 1992
c
c     **********

c declarations for passed parameters

      logical invert
c*****precision > double
      double precision x(*),y(*)
c*****end precision > double
c*****precision > single
c      real x(*),y(*)
c*****end precision > single

c declarations for local parameters

      integer indx,k
c*****precision > double
      double precision produ,prodl
c*****end precision > double
c*****precision > single
c      real produ,prodl
c*****end precision > single

c parameter declarations

c*****precision > double
      double precision two
      parameter (two=2.d0)
c*****end precision > double
c*****precision > single
c      real two
c      parameter (two=2.0)
c*****end precision > single

c declarations for named common /m/

c*****precision > double
      double precision d(maxn),z(maxn)
c*****end precision > double
c*****precision > single
c      real d(maxn),z(maxn)
c*****end precision > single
      integer pz(maxn)
      integer num0
      common/m/d,z,pz,num0

c declarations for named common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c store Householder inner-products in produ and prodl

      call qbpdot(num0,z,x,pz,produ,prodl)
      produ=two*produ
      prodl=two*prodl

c store Householder reflections in y

      call copy(n,x,1,y,1)
      call qbpflp(num0,produ,prodl,z,y,indx)

c store Dy (or D**(-1)y when invert) in y

      if (invert) then
        do 30 k=1,n
          y(k)=y(k)/d(k)
   30   continue
      else
        do 40 k=1,n
          y(k)=y(k)*d(k)
   40   continue
      endif

c store Householder inner-products in produ and prodl

      call qbpdot(num0,z,y,pz,produ,prodl)
      produ=two*produ
      prodl=two*prodl

c store Householder reflections in y

      call qbpflp(num0,produ,prodl,z,y,indx)
      return

c last card of subroutine qbpmx

      end
      subroutine qbpsx(x,y)

c     **********
c
c     This subroutine forms the product Sx where S is defined as:
c
c          ( Sxx  Sxy )                { -1  1 <= i=j <= m
c      S = (          ) with (Sxy)   = {                      and
c          ( Sxy' Syy )           ij   {  0  otherwise
c
c      Sxx = order-nx zero matrix and Syy = order-ny identity matrix.
c
c     To change the precision of this program, run the change
c     program on qbpsx.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c     **********
c     Subprograms called
c        Modified Linpack: axpy,copy,scal
c        Local suite:      dload
c     **********
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	October 26, 1991
c     Date Modified:	September 18, 1992
c
c     **********

c declarations for passed parameters

c*****precision > double
      double precision x(*),y(*)
c*****end precision > double
c*****precision > single
c      real x(*),y(*)
c*****end precision > single

c parameter declarations

c*****precision > double
      double precision minus1,zero
      parameter (minus1=-1.d0,zero=0.d0)
c*****end precision > double
c*****precision > single
c      real minus1,zero
c      parameter (minus1=-1.0,zero=0.0)
c*****end precision > single

c declarations for named common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

      call dload(n,zero,y,1)
      call copy(m,x(nx+1),1,y,1)
      call scal(m,minus1,y,1)
      call copy(ny,x(nx+1),1,y(nx+1),1)
      call axpy(m,minus1,x,1,y(nx+1),1)
      return

c last card of subroutine qbpsx

      end
      subroutine qbpmkm(condm,iseed)
      integer maxn
      parameter (maxn=2000)

c     **********
c
c     This subroutine defines the n by n matrices M = HDH,
c     where H is a block-diagonal matrix defined by H=diag(Hx,Hy),
c     Hx and Hy are order nx and ny Householder matrices generated
c     by the (Householder) unit 2-norm vectors zx and zy
c     respectively, z'=[zx' zy'] has non0 components from (-1,1)
c     in rows pz(1) through pz(non0), and D=diag(d(1) ,..., d(n))
c     is a positive definite diagonal matrix with 2-norm condition
c     10**lcondm
c
c     To change the precision of this program, run the change
c     program on qbpmkm.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c     **********
c     Subprograms called
c        Modified Linpack:                nrm2,scal
c        TOMS (MINPACK project) supplied: rand
c        Fortran supplied:                int,dble
c        Local suite:                     dload
c     **********
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	October 26, 1991
c     Dates Modified:   July 7, 1992
c                       September 18, 1992
c
c     **********

c declarations for passed parameters

      integer condm,iseed

c declarations for local parameters

      integer indx,k
c*****precision > double
      double precision znorm,tempz,factor
c*****end precision > double
c*****precision > single
c      real znorm,tempz,factor
c*****end precision > single

c function declarations

c*****precision > double
      double precision nrm2
c*****end precision > double
c*****precision > single
c      real nrm2
c*****end precision > single
      real rand
      intrinsic int

c parameter declarations

c*****precision > double
      double precision zero,one
      parameter (zero=0.d0,one=1.d0)
c*****end precision > double
c*****precision > single
c      real zero,one
c      parameter (zero=0.0,one=1.0)
c*****end precision > single

c declarations for common /m/

c*****precision > double
      double precision d(maxn),z(maxn)
c*****end precision > double
c*****precision > single
c      real d(maxn),z(maxn)
c*****end precision > single
      integer pz(maxn)
      integer num0
      common/m/d,z,pz,num0

c declarations for common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c put num0 random elements in (-1,1) into random locations
c of z and store locations in pz(1) through pz(num0)

      call dload(n,zero,z,1)
      do 20 k = 1, num0
        tempz = 2*rand(iseed) - one
   10   continue
        indx=int(n*rand(iseed)+1)
        if (indx.gt.n) go to 10
        if (z(indx).ne.zero) go to 10
        z(indx)=tempz
        pz(k)=indx
   20 continue

c make zx and zy unit 2-norm vectors

      znorm = nrm2(nx,z,1)
      if (znorm.ne.zero) then
        call scal(nx,one/znorm,z,1)
      endif
      znorm = nrm2(ny,z(nx+1),1)
      if (znorm.ne.zero) then
        call scal(ny,one/znorm,z(nx+1),1)
      endif

c store diagonal of D

      do 30 k = 1,n
c*****precision > double
        factor = (dble(k-1)/dble(n-1))
c*****end precision > double
c*****precision > single
c        factor = (real(k-1)/real(n-1))
c*****end precision > single
        d(k) = 10**(-condm*factor)
   30 continue
      return

c     Last card of subroutine qbpmkm

      end
      subroutine dload(n,da,dx,incx)

c     copies a scalar, a, to a vector, x.
c     uses unrolled loops when incx equals one.

c     To change the precision of this program, run the change
c     program on dload.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

c*****precision > double
      double precision da,dx(*)
c*****end precision > double
c*****precision > single
c      real da,dx(*)
c*****end precision > single
      integer i,incx,ix,m,mp1,n

      if(n.le.0)return
      if(incx.eq.1)go to 20

c     code for incx not equal to 1

      ix = 1
      if(incx.lt.0)ix = (-n+1)*incx + 1
      do 10 i = 1,n
        dx(ix) = da
        ix = ix + incx
   10 continue
      return

c     code for incx equal to 1 and clean-up loop

   20 m = mod(n,7)
      if( m .eq. 0 ) go to 40
      do 30 i = 1,m
        dx(i) = da
   30 continue
      if( n .lt. 7 ) return
   40 mp1 = m + 1
      do 50 i = mp1,n,7
        dx(i) = da
        dx(i + 1) = da
        dx(i + 2) = da
        dx(i + 3) = da
        dx(i + 4) = da
        dx(i + 5) = da
        dx(i + 6) = da
   50 continue
      return
      end
      subroutine qbpdot(non0,x,y,ind,produ,prodl)
c
c     splits the sparse dot product of x and y between
c     produ and prodl
c
c     To change the precision of this program, run the change
c     program on qbpdot.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c ********************
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	July 7, 1992
c     Date Modified:	September 18, 1992
c
c ********************

c*****precision > double
      double precision x(*),y(*),produ,prodl,zero
c*****end precision > double
c*****precision > single
c      real x(*),y(*),produ,prodl,zero
c*****end precision > single
      integer i,ind(*),ixy,non0

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c*****precision > double
      parameter (zero=0.d0)
c*****end precision > double
c*****precision > single
c      parameter (zero=0.0)
c*****end precision > single

      produ = zero
      prodl = zero
      if(n.le.0)return
      do 10 i = 1,non0
        ixy = ind(i)
        if (ixy.le.nx) then
          produ=produ + x(ixy)*y(ixy)
        else
          prodl=prodl + x(ixy)*y(ixy)
        endif
   10 continue
      return

c     Last card of subroutine qbpdot

      end
      subroutine qbpflp(non0,da,db,dx,dy,inc)

c     vector minus constant times a vector.

c     To change the precision of this program, run the change
c     program on qbpflp.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

c*****precision > double
      double precision dx(*),dy(*),da,db
c*****end precision > double
c*****precision > single
c      real dx(*),dy(*),da,db
c*****end precision > single
      integer i,inc(*),ixy,non0

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c*****precision > double
      double precision zero
      parameter (zero=0.d0)
c*****end precision > double
c*****precision > single
c      real zero
c      parameter (zero=0.0)
c*****end precision > single

      if(non0.le.0)return
      if (da .eq. zero .and. db .eq. zero) return

      do 10 i = 1,non0
        ixy=inc(i)
        if (ixy.le.nx) then
          dy(ixy) = dy(ixy) - da*dx(ixy)
        else
          dy(ixy) = dy(ixy) - db*dx(ixy)
        endif
   10 continue
      return

c last card of subroutine qbpflp

      end
      real function rand(iseed)
      integer iseed
c     **********
c
c     function rand
c
c     Rand is the portable random number generator of L. Schrage.
c
c     The generator is full cycle, that is, every integer from
c     1 to 2**31 - 2 is generated exactly once in the cycle.
c     It is completely described in TOMS 5(1979),132-138.
c
c     The function statement is
c
c       real function rand(iseed)
c
c     where
c
c       iseed is a positive integer variable which specifies
c         the seed to the random number generator. Given the
c         input seed, rand returns a random number in the
c         open interval (0,1). On output the seed is updated.
c
c     Argonne National Laboratory. MINPACK Project. March 1981.
c
c     **********
      integer a,b15,b16,fhi,k,leftlo,p,xhi,xalo
      real c
c
c     Set a = 7**5, b15 = 2**15, b16 = 2**16, p = 2**31-1, c = 1/p.
c
      data a/16807/, b15/32768/, b16/65536/, p/2147483647/
      data c/4.656612875e-10/
c
c     There are 8 steps in rand.
c
c     1. Get 15 hi order bits of iseed.
c     2. Get 16 lo bits of iseed and form lo product.
c     3. Get 15 hi order bits of lo product.
c     4. Form the 31 highest bits of full product.
c     5. Get overflo past 31st bit of full product.
c     6. Assemble all the parts and pre-substract p.
c        The parentheses are essential.
c     7. Add p back if necessary.
c     8. Multiply by 1/(2**31-1).
c
      xhi = iseed/b16
      xalo = (iseed - xhi*b16)*a
      leftlo = xalo/b16
      fhi = xhi*a + leftlo
      k = fhi/b15
      iseed = (((xalo-leftlo*b16)-p) + (fhi-k*b15)*b16) + k
      if (iseed .lt. 0) iseed = iseed + p
      rand = c*float(iseed)
      return
c
c     Last card of function rand.
c
      end
      subroutine axpy(n,a,x,incx,y,incy)

c     constant times a vector plus a vector.
c     uses unrolled loops for increments equal to one.
c     jack dongarra, linpack, 3/11/78.
c     modified, paul calamai, 20/10/92.

c     To change the precision of this program, run the change
c     program on axpy.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

c*****precision > double
      double precision x(*),y(*),a
      double precision zero
      parameter (zero=0.d0)
c*****end precision > double
c*****precision > single
c      real x(*),y(*),a
c      real zero
c      parameter (zero=0.0)
c*****end precision > single
      integer i,incx,incy,ix,iy,m,mp1,n

      if(n.le.0)return
      if (a .eq. zero) return
      if(incx.eq.1.and.incy.eq.1)go to 20

c        code for unequal increments or equal increments
c          not equal to 1

      ix = 1
      iy = 1
      if(incx.lt.0)ix = (-n+1)*incx + 1
      if(incy.lt.0)iy = (-n+1)*incy + 1
      do 10 i = 1,n
        y(iy) = y(iy) + a*x(ix)
        ix = ix + incx
        iy = iy + incy
   10 continue
      return

c        code for both increments equal to 1


c        clean-up loop

   20 m = mod(n,4)
      if( m .eq. 0 ) go to 40
      do 30 i = 1,m
        y(i) = y(i) + a*x(i)
   30 continue
      if( n .lt. 4 ) return
   40 mp1 = m + 1
      do 50 i = mp1,n,4
        y(i) = y(i) + a*x(i)
        y(i + 1) = y(i + 1) + a*x(i + 1)
        y(i + 2) = y(i + 2) + a*x(i + 2)
        y(i + 3) = y(i + 3) + a*x(i + 3)
   50 continue
      return
      end
      subroutine copy(n,x,incx,y,incy)

c     copies a vector, x, to a vector, y.
c     uses unrolled loops for increments equal to 1.
c     jack dongarra, linpack, 3/11/78.
c     modified, paul calamai, 20/10/92.

c     To change the precision of this program, run the change
c     program on copy.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

c*****precision > double
      double precision x(*),y(*)
c*****end precision > double
c*****precision > single
c      real x(*),y(*)
c*****end precision > single
      integer i,incx,incy,ix,iy,m,mp1,n

      if(n.le.0)return
      if(incx.eq.1.and.incy.eq.1)go to 20

c        code for unequal increments or equal increments
c          not equal to 1

      ix = 1
      iy = 1
      if(incx.lt.0)ix = (-n+1)*incx + 1
      if(incy.lt.0)iy = (-n+1)*incy + 1
      do 10 i = 1,n
        y(iy) = x(ix)
        ix = ix + incx
        iy = iy + incy
   10 continue
      return

c        code for both increments equal to 1


c        clean-up loop

   20 m = mod(n,7)
      if( m .eq. 0 ) go to 40
      do 30 i = 1,m
        y(i) = x(i)
   30 continue
      if( n .lt. 7 ) return
   40 mp1 = m + 1
      do 50 i = mp1,n,7
        y(i) = x(i)
        y(i + 1) = x(i + 1)
        y(i + 2) = x(i + 2)
        y(i + 3) = x(i + 3)
        y(i + 4) = x(i + 4)
        y(i + 5) = x(i + 5)
        y(i + 6) = x(i + 6)
   50 continue
      return
      end
c*****precision > double
      double precision function dot(n,x,incx,y,incy)
c*****end precision > double
c*****precision > single
c      real function dot(n,x,incx,y,incy)
c*****end precision > single

c     forms the dot product of two vectors.
c     uses unrolled loops for increments equal to one.
c     jack dongarra, linpack, 3/11/78.
c     modified, paul calamai, 20/10/92.

c     To change the precision of this program, run the change
c     program on dot.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

c*****precision > double
      double precision x(*),y(*),temp
      double precision zero
      parameter (zero=0.d0)
c*****end precision > double
c*****precision > single
c      real x(*),y(*),temp
c      real zero
c      parameter (zero=0.0)
c*****end precision > single
      integer i,incx,incy,ix,iy,m,mp1,n

      temp = zero
      dot = zero
      if(n.le.0)return
      if(incx.eq.1.and.incy.eq.1)go to 20

c        code for unequal increments or equal increments
c          not equal to 1

      ix = 1
      iy = 1
      if(incx.lt.0)ix = (-n+1)*incx + 1
      if(incy.lt.0)iy = (-n+1)*incy + 1
      do 10 i = 1,n
        temp = temp + x(ix)*y(iy)
        ix = ix + incx
        iy = iy + incy
   10 continue
      dot = temp
      return

c        code for both increments equal to 1


c        clean-up loop

   20 m = mod(n,5)
      if( m .eq. 0 ) go to 40
      do 30 i = 1,m
        temp = temp + x(i)*y(i)
   30 continue
      if( n .lt. 5 ) go to 60
   40 mp1 = m + 1
      do 50 i = mp1,n,5
        temp = temp + x(i)*y(i) + x(i + 1)*y(i + 1) +
     *   x(i + 2)*y(i + 2) + x(i + 3)*y(i + 3) + x(i + 4)*y(i + 4)
   50 continue
   60 dot = temp
      return
      end
c*****precision > double
      double precision function nrm2 ( n, x, incx)
c*****end precision > double
c*****precision > single
c      real function nrm2 ( n, x, incx)
c*****end precision > single

c     To change the precision of this program, run the change
c     program on nrm2.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

      integer          next
c*****precision > double
      double precision x(*),cutlo,cuthi,hitest,sum,xmax,zero,one
      parameter (zero=0.d0,one=1.d0)
c*****end precision > double
c*****precision > single
c      real x(*),cutlo,cuthi,hitest,sum,xmax,zero,one
c      parameter (zero=0.0e0,one=1.0e0)
c*****end precision > single
      intrinsic abs,sqrt

c     euclidean norm of the n-vector stored in x() with storage
c     increment incx .
c     if    n .le. 0 return with result = 0.
c     if n .ge. 1 then incx must be .ge. 1
c
c           c.l.lawson, 1978 jan 08
c           modified, paul calamai, 20/10/92.
c
c     four phase method     using two built-in constants that are
c     hopefully applicable to all machines.
c         cutlo = maximum of  sqrt(u/eps)  over all known machines.
c         cuthi = minimum of  sqrt(v)      over all known machines.
c     where
c         eps = smallest no. such that eps + 1. .gt. 1.
c         u   = smallest positive no.   (underflow limit)
c         v   = largest  no.            (overflow  limit)
c
c     brief outline of algorithm..
c
c     phase 1    scans zero components.
c     move to phase 2 when a component is nonzero and .le. cutlo
c     move to phase 3 when a component is .gt. cutlo
c     move to phase 4 when a component is .ge. cuthi/m
c     where m = n for x() real and m = 2*n for complex.
c
c     values for cutlo and cuthi..
c     from the environmental parameters listed in the imsl converter
c     document the limiting values are as follows..
c     cutlo, s.p.   u/eps = 2**(-102) for  honeywell.  close seconds are
c                   univac and dec at 2**(-103)
c                   thus cutlo = 2**(-51) = 4.44089e-16
c     cuthi, s.p.   v = 2**127 for univac, honeywell, and dec.
c                   thus cuthi = 2**(63.5) = 1.30438e19
c     cutlo, d.p.   u/eps = 2**(-67) for honeywell and dec.
c                   thus cutlo = 2**(-33.5) = 8.23181d-11
c     cuthi, d.p.   same as s.p.  cuthi = 1.30438d19
c*****precision > double
      parameter (cutlo=8.232d-11,cuthi=1.304d19)
c*****end precision > double
c*****precision > single
c      parameter (cutlo=4.441e-16,cuthi=1.304e19)
c*****end precision > single

      if(n .gt. 0) go to 10
         nrm2  = zero
         go to 300

   10 assign 30 to next
      sum = zero
      nn = n * incx
c                                                 begin main loop
      i = 1
   20    go to next,(30, 50, 70, 110)
   30 if( abs(x(i)) .gt. cutlo) go to 85
      assign 50 to next
      xmax = zero

c                        phase 1.  sum is zero

   50 if( x(i) .eq. zero) go to 200
      if( abs(x(i)) .gt. cutlo) go to 85

c                                prepare for phase 2.
      assign 70 to next
      go to 105

c                                prepare for phase 4.

  100 i = j
      assign 110 to next
      sum = (sum / x(i)) / x(i)
  105 xmax = abs(x(i))
      go to 115

c                   phase 2.  sum is small.
c                             scale to avoid destructive underflow.

   70 if( abs(x(i)) .gt. cutlo ) go to 75

c                     common code for phases 2 and 4.
c                     in phase 4 sum is large.  scale to avoid overflow.

  110 if( abs(x(i)) .le. xmax ) go to 115
         sum = one + sum * (xmax / x(i))**2
         xmax = abs(x(i))
         go to 200

  115 sum = sum + (x(i)/xmax)**2
      go to 200


c                  prepare for phase 3.

   75 sum = (sum * xmax) * xmax


c     for real or d.p. set hitest = cuthi/n
c     for complex      set hitest = cuthi/(2*n)

   85 hitest = cuthi/float( n )

c                   phase 3.  sum is mid-range.  no scaling.

      do 95 j =i,nn,incx
      if(abs(x(j)) .ge. hitest) go to 100
   95    sum = sum + x(j)**2
      nrm2 = sqrt( sum )
      go to 300

  200 continue
      i = i + incx
      if ( i .le. nn ) go to 20

c              end of main loop.

c              compute square root and adjust for scaling.

      nrm2 = xmax * sqrt(sum)
  300 continue
      return
      end
      subroutine scal(n,a,x,incx)

c     scales a vector by a constant.
c     uses unrolled loops for increment equal to 1.
c     jack dongarra, linpack, 3/11/78.
c     modified, paul calamai, 20/10/92.

c     To change the precision of this program, run the change
c     program on scal.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.

c*****precision > double
      double precision a,x(*)
c*****end precision > double
c*****precision > single
c      real a,x(*)
c*****end precision > single
      integer i,incx,m,mp1,n,nincx

      if(n.le.0)return
      if(incx.eq.1)go to 20

c        code for increment not equal to 1

      nincx = n*incx
      do 10 i = 1,nincx,incx
        x(i) = a*x(i)
   10 continue
      return

c        code for increment equal to 1


c        clean-up loop

   20 m = mod(n,5)
      if( m .eq. 0 ) go to 40
      do 30 i = 1,m
        x(i) = a*x(i)
   30 continue
      if( n .lt. 5 ) return
   40 mp1 = m + 1
      do 50 i = mp1,n,5
        x(i) = a*x(i)
        x(i + 1) = a*x(i + 1)
        x(i + 2) = a*x(i + 2)
        x(i + 3) = a*x(i + 3)
        x(i + 4) = a*x(i + 4)
   50 continue
      return
      end
*****************END SOURCE CODE**************************
*****************BEGIN USAGE CODE*************************
      program usage

c     The purpose of this program is to demonstrate the use
c     of a suite of routines for generating quadratic
c     bilevel programming problems.
c
c     The comments in subroutine qbpgen describe the form
c     of the problems generated.
c
c     The user is referred to the article "Generating quadratic
c     bilevel programming test problems", ACM TOMS, 1993 for
c     further details.
c
c     To change the precision of this program, run the change
c     program on usage.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c ********************
c Subprograms called
c   Local suite: qbpchk, qbpgen, qbpfun
c ********************
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	November 26, 1991
c     Date Modified:	September 18, 1992
c
c ********************

c declarations for parameters to be passed to subroutine qbpgen
c (ie. rhom2,rhom4,nx,ny,m1,m2,m3,m4,lcondm,non0,info and iseed)
c see comments in subroutine qbpgen for details

c Note: the dimension of rhom2 and rhom4 need be no greater
c       than min(nx,ny)

      integer nx,ny,m1,m2,m3,m4,lcondm,non0,info,iseed
c*****precision > double
      double precision rhom2(4),rhom4(4)
c*****end precision > double
c*****precision > single
c      real rhom2(4),rhom4(4)
c*****end precision > single

c declarations for parameters to be passed to subroutines
c qbpchk and qbpfun

c Note: this would typically be the current solution produced
c       by whatever solver was being tested by the user.

c*****precision > double
      double precision soln(10)
c*****end precision > double
c*****precision > single
c      real soln(10)
c*****end precision > single

c declarations for parameters returned by subroutine qbpchk
c (ie. mr,errl2,type)

c Note: the dimension of mr need be no greater than
c       nx+ny

      integer type
c*****precision > double
      double precision mr(10),errl2
c*****end precision > double
c*****precision > single
c      real mr(10),errl2
c*****end precision > single

c declarations for parameters returned by subroutine qbpfun
c (ie. upper,lower,res)

c Note: the dimension of res need be no greater than
c       3*min(nx,ny)

c*****precision > double
      double precision upper,lower,res(12)
c*****end precision > double
c*****precision > single
c      real upper,lower,res(12)
c*****end precision > single

c parameter declarations

c*****precision > double
      double precision minus4,trehlf,three
      parameter (minus4=-4.d0,trehlf=1.5d0,three=3.d0)
c*****end precision > double
c*****precision > single
c      real minus4,trehlf,three
c      parameter (minus4=-4.0,trehlf=1.5,three=3.0)
c*****end precision > single

c To generate quadratic bilevel programming problems with
c 4 upper-level variables and 6 lower-level variables we
c need to set nx=4 and ny=6

      nx=4
      ny=6

c We will demonstrate the usage of the suite of routines
c using three different versions of this 10 dimensional
c problem.  Subroutines qbpchk and qbpfun will only be called
c in the first version of this problem.

c *********
c VERSION 1
c *********

c For this version we want to generate a problem with 2
c global solutions.  To accomplish this we must set m3=1.

      m3=1

c We also want an additional 6 local solutions (requiring
c abs(m2)+m3+abs(m4)=3 --> abs(m2)+abs(m4)=2).
c More specifically we want one pair of solution components
c to correspond to Case 2 and another pair to correspond
c to Case 4 (see the ACM TOMS article).
c Thus abs(m2)=abs(m4)=1.

c Finally, we want to select our own values for rhom2 and
c rhom4 for these two cases. Thus m2=m4=1.

      m2=1
      m4=1

c Since m2=1 we must provide a value for rhom2(1) in
c the open interval (1,2).  Similarily, since m4=1
c we must provide a value for rhom4(1) in the open
c interval (2,+infinity).
c We choose rhom2(1)=1.5 and rhom4(1)=3.0 to
c coincide with the diagrams corresponding to Case 2
c and Case 4 in the ACM TOMS article.

      rhom2(1)=trehlf
      rhom4(1)=three

c Since the sum of m1+abs(m2)+m3+abs(m4) must equal
c min(nx,ny) we must set m1=1.

      m1=1

c Finally, to obtain a sparse (but ideally conditioned)
c transformation matrix (see comments in subroutines
c qbpgen and qbpmkm) we set non0=1 and lcondm=0.

c NOTE: when lcondm=0 the transformation matrix should
c       (with exact arithmetic) be the identity matrix
c       (We do not, however, use this fact explicitly
c       in the code.)

      non0=1
      lcondm=0

c We now need simply to initialize the seed for the
c random number generator (see subroutine rand) and
c then call subroutine qbpgen.

      iseed=1
      call qbpgen(rhom2,rhom4,nx,ny,m1,m2,m3,m4,lcondm,
     1            non0,info,iseed)

c The value of info returned by subroutine qbpgen
c should be checked to make sure that termination
c was normal (ie. info=0)

      if (info.ne.0) then
        print *,'** Something is wrong (info=',info,')'
        print *,'** VERSION 1 run abandoned **'
      else

c Much of the data defining the problem generated by
c subroutine qbpgen is stored in named common blocks
c (see comments in subroutine qbpgen).  However, the
c user may only need to call subroutine qbpchk and
c subroutine qbpfun in order to access this information.

c To demonstrate this concept suppose that the user
c wishes to evaluate the functions and constraints
c of the generated bilevel problem.  This can easily
c be accomplished by calling subroutine qbpfun.

c Suppose, for example, that the user wishes to evaluate
c the bilevel problem at the point stored in vector soln.
c Here we set soln to a feasible point of the problem we
c have just generated.

        soln(1) = 0.75d0
        soln(2) = 0.75d0
        soln(3) = 0.75d0
        soln(4) = 0.75d0
        soln(5) = 0.25d0
        soln(6) = 0.25d0
        soln(7) = 0.25d0
        soln(8) = 0.25d0
        soln(9) = 0.00d0
        soln(10)= 0.00d0

c The following call to subroutine qbpfun

        call qbpfun(soln,upper,lower,res)
        print *, 'upper = ',upper
        print *, 'lower = ',lower
        print *, 'res   = '
        print 10, res

c would return the value of the upper-level objective
c evaluated at soln in upper, the lower-level objective
c evaluated at soln in lower and the residuals of the
c constraints (ie. their slacks) in the vector res.
c In this particular case the values returned should
c (approximately) be:

c upper =    0.25000000000000
c lower =   -0.62500000000000
c res   =
c             0.50000000000000   0.50000000000000
c             0.50000000000000   0.50000000000000
c             0.00000000000000   0.50000000000000
c             1.00000000000000   2.00000000000000
c             0.00000000000000   0.00000000000000
c             0.00000000000000   0.00000000000000

c Suppose, in addition, that the user wishes to see
c if the point (in soln) is a minimizer of the generated
c problem. To some extent this question can be answered
c using the following call to subroutine qbpchk

        call qbpchk(soln,mr,errl2,type)
        print *,'errl2 = ',errl2
        print *,'type  = ',type
        print *,'mr    = '
        print 10, mr

c As described in the comments of subroutine qbpchk
c this call actually results in a comparison against
c all minimizers in the untransformed space.  If the value
c returned in errl2 is "small" then the point stored in
c soln is "close" to a minimizer of the type specified by
c the value returned in type (see comments in subroutine
c qbpchk). The point returned in vector mr corresponds to
c the closest minimizer (in the untransformed space).
c In this particular case the values returned should
c (approximately) be:

c errl2 =    0.70710678118655
c type  =   3
c mr    =
c             1.00000000000000   0.50000000000000
c             0.50000000000000   0.50000000000000
c             0.00000000000000   0.50000000000000
c             0.50000000000000   0.50000000000000
c             0.00000000000000   0.00000000000000

        print *,'** VERSION 1 **'
        print *,'   Check output above against values in'
        print *,'   program usage.'
      endif

c *********
c VERSION 2
c *********

c For this version we want to generate a problem with a
c unique global solution.  To accomplish this we set m3=0.

      m3=0

c We also want an additional 15 local solutions (requiring
c abs(m2)+m3+abs(m4)=4 --> abs(m2)+abs(m4)=4).
c More specifically we want two pair of solution components
c to correspond to Case 2 and two pair to correspond
c to Case 4 (see the ACM TOMS article).
c Thus abs(m2)=abs(m4)=2.

c Finally, we want subroutine qbpgen to set both components
c of rhom2 to 1.5 and both components of rhom4 to 4.0
c We therefore set m2=m4=2, rhom2(1)=-1.5 and rhom4(1)=-4.0
c as per the instructions in subroutine qbpgen.

      m2=2
      m4=2
      rhom2(1)=-trehlf
      rhom4(1)=minus4

c Since the sum of m1+abs(m2)+m3+abs(m4) must equal
c min(nx,ny) we must set m1=0.

      m1=0

c Finally, to obtain a (relatively) dense transformation matrix
c with two-norm condition 10 we set non0=6 and lcondm=1

      non0=6
      lcondm=1

c We now need simply to call subroutine qbpgen (iseed has
c already been initialized).

      call qbpgen(rhom2,rhom4,nx,ny,m1,m2,m3,m4,lcondm,
     1            non0,info,iseed)
      if (info.ne.0) then
        print *,'** Something is wrong (info=',info,')'
        print *,'** VERSION 2 **'
      endif

c *********
c VERSION 3
c *********

c For this version we also want to generate a problem with a
c unique global solution.  To accomplish this we set m3=0.

      m3=0

c We also want an additional 7 local solutions (requiring
c abs(m2)+m3+abs(m4)=3 --> abs(m2)+abs(m4)=3).
c More specifically we want two pair of solution components
c to correspond to Case 2 and one pair to correspond
c to Case 4 (see the ACM TOMS article).
c Thus abs(m2)=2 and abs(m4)=1.

c Finally, we want subroutine qbpgen to select both components
c of rhom2 and we want rhom4=3.0.
c We therefore set m2=-2, m4=1 and rhom4(1)=3.0 as per the
c instructions in subroutine qbpgen.

      m2=-2
      m4=1
      rhom4(1)=three

c Since the sum of m1+abs(m2)+m3+abs(m4) must equal
c min(nx,ny) we must set m1=1.

      m1=1

c Finally, to obtain a (relatively) sparse transformation matrix
c with two-norm condition 100 we set non0=2 and lcondm=2

      non0=2
      lcondm=2

c We now need simply to call subroutine qbpgen (iseed has
c already been initialized).

      call qbpgen(rhom2,rhom4,nx,ny,m1,m2,m3,m4,lcondm,
     1            non0,info,iseed)
      if (info.ne.0) then
        print *,'** Something is wrong (info=',info,')'
        print *,'** VERSION 3 **'
      endif

c format specifications

   10 format(9x,2f19.14)
      stop
c last card of usage
      end
*****************END USAGE CODE**************************
*****************BEGIN VERIFY CODE*************************
      program verify
      integer maxn
      parameter (maxn=2000)

c     The purpose of this program is to test (albeit minimally) the
c     integrity of the routines in this suite after they are
c     installed. It is by no means a thorough test. For usage
c     examples see program usage.
c
c     The user is referred to the article "Generating quadratic
c     bilevel programming test problems", ACM TOMS, 1993 for
c     details about the suite, and to the comments in
c     subroutines qbpgen, qbpchk and qbpfun for details about
c     the parameters.
c
c     To change the precision of this program, run the change
c     program on verify.f
c     Alternatively, to make a single precision version append a
c     comment character to the start of all lines between sequential
c        precision > double
c     and
c        end precision > double
c     comments and delete the comment character at the start of all
c     lines between sequential
c        precision > single
c     and
c        end precision > single
c     comments.  To make a double precision version interchange
c     the append and delete operations in these instructions.
c
c ********************
c Subprograms called
c   Local suite: qbpax,qbpchk,qbpgen,qbpmkm,qbpmx,qbpfun,qbpsx,dload
c   Modified Linpack: axpy,dot,nrm2
c   Fortran supplied: min
c ********************
c
c     Authors:		Paul H. Calamai and Luis N. Vicente
c     Date Written:	November 26, 1991
c     Date Modified:	September 18, 1992
c
c ********************

c declarations for parameters to be passed to subroutine qbpgen
c (ie. rhom2,rhom4,lcondm,non0,info and iseed)
c see comments in subroutine qbpgen for details

c Note: the dimension of rhom2 and rhom4 need be no greater
c       than maxn/2

      integer lcondm,non0,info,iseed
c*****precision > double
      double precision rhom2(maxn/2),rhom4(maxn/2)
c*****end precision > double
c*****precision > single
c      real rhom2(maxn/2),rhom4(maxn/2)
c*****end precision > single

c declarations for parameters returned by subroutine qbpchk
c (ie. mr,errl2,type)

c Note: the dimension of mr need be no greater than
c       maxn

      integer type
c*****precision > double
      double precision mr(maxn),errl2
c*****end precision > double
c*****precision > single
c      real mr(maxn),errl2
c*****end precision > single

c declarations for parameters returned by subroutine qbpfun
c (ie. upper,lower,res)

c Note: the dimension of res need be no greater than
c       3*maxn/2

c*****precision > double
      double precision upper,lower,res(3*maxn/2)
c*****end precision > double
c*****precision > single
c      real upper,lower,res(3*maxn/2)
c*****end precision > single

c declarations for local parameters

      integer i
c*****precision > double
      double precision error,x(maxn),y(maxn)
c*****end precision > double
c*****precision > single
c      real error,x(maxn),y(maxn)
c*****end precision > single

c function declarations

c*****precision > double
      double precision dot,nrm2
c*****end precision > double
c*****precision > single
c      real dot,nrm2
c*****end precision > single
      intrinsic min

c parameter declarations

c*****precision > double
      double precision minus1,one,trehlf,three
      parameter (minus1=-1.d0,one=1.d0,trehlf=1.5d0,three=3.d0)
c*****end precision > double
c*****precision > single
c      real minus1,one,trehlf,three
c      parameter (minus1=-1.0,one=1.0,trehlf=1.5,three=3.0)
c*****end precision > single

c declarations for named common /m/

      integer num0
      integer pz(maxn)
c*****precision > double
      double precision d(maxn),z(maxn)
c*****end precision > double
c*****precision > single
c      real d(maxn),z(maxn)
c*****end precision > single
      common/m/d,z,pz,num0

c declarations for named common /dim/

      integer nx,ny,m1,m2,m3,m4,m,n
      common/dim/nx,ny,m1,m2,m3,m4,m,n

c *******************
c VERIFICATION TEST 1
c *******************

c Subroutines tested:
c  qbpchk, qbpgen, qbpfun
c *******************

c The first test will be conducted using VERSION 1 of the
c problem described in program usage.  See the comments
c in program usage for details.

      rhom2(1)=trehlf
      rhom4(1)=three
      nx=4
      ny=6
      m1=1
      m2=1
      m3=1
      m4=1
      lcondm=0
      non0=1
      iseed=1

c To conduct a test of subroutines qbpfun and qbpchk we begin
c by calling the problem generator (ie. subroutine qbpgen)
c using the above data.  The fact that lcondm=0 is essential
c since this yields an identity transformation.

      call qbpgen(rhom2,rhom4,nx,ny,m1,m2,m3,m4,lcondm,
     1            non0,info,iseed)

c The value of info returned by subroutine qbpgen should
c be checked to make sure that termination was normal
c (ie. info=0)

      if (info.ne.0) then
        print *,'** Something is wrong (info=',info,')'
        print *,'** VERIFICATION TEST 1 abandoned **'
      else

c Since the transformed and untransformed problem are identical
c we have complete knowledge of all minimizers of the generated
c problem.  To test these subroutines we will pass them one of
c the known global solutions using vector parameter x.

        x(1)  = 1.00d0
        x(2)  = 1.25d0
        x(3)  = 1.50d0
        x(4)  = 0.50d0
        x(5)  = 0.00d0
        x(6)  = 0.25d0
        x(7)  = 0.50d0
        x(8)  = 0.50d0
        x(9)  = 0.00d0
        x(10) = 0.00d0

c The following call to subroutine qbpfun

        call qbpfun(x,upper,lower,res)
        print *, 'upper = ',upper
        print *, 'lower = ',lower
        print *, 'res   = '
        print 10, (res(i),i=1,3*m)

c should return the value of the upper-level objective
c evaluated at x in upper, the lower-level objective
c evaluated at x in lower and the residuals of the
c constraints (ie. their slacks) in the vector res.
c In this particular case the values returned should
c (approximately) be:

c upper =    0.56250000000000
c lower =    -1.0312500000000
c res   =
c             0.00000000000000   0.00000000000000
c             0.00000000000000   1.00000000000000
c             0.00000000000000   0.00000000000000
c             0.00000000000000   2.00000000000000
c             0.00000000000000   0.50000000000000
c             1.00000000000000   0.00000000000000

c Similarly, the following call to subroutine qbpchk

        call qbpchk(x,mr,errl2,type)
        print *,'errl2 = ',errl2
        print *,'type  = ',type
        print *,'mr    = '
        print 10, (mr(i),i=1,n)

c should yield the following values for the returned parameters:

c errl2 =   0.
c type  =   2
c mr    =
c             1.00000000000000   1.25000000000000
c             1.50000000000000   0.50000000000000
c             0.00000000000000   0.25000000000000
c             0.50000000000000   0.50000000000000
c             0.00000000000000   0.00000000000000

        print *,'** VERIFICATION TEST 1 completed **'
        print *,'   Check output above against values in'
        print *,'   program verify.'
      endif

c *******************
c VERIFICATION TEST 2
c *******************

c Subroutines tested:
c  qbpmkm, qbpmx
c *******************

c Note: the typical user will never need to call these
c       routines directly

c Since the transformation matrix M is defined by the
c product H*D*H, where H is a Householder matrix and
c D is a diagonal matrix, we can easily check subroutine
c qbpmkm (which constructs M) and qbpmx (that forms the
c product of M and a vector x).  We do this by forcing
c D to be the identity matrix (by setting lcondm=0) and
c setting x to the ones vector.  In this case, M should
c be the identity matrix and y=M*x should equal x.
c We then set y=y-x and form y'y which should equal 0.

c Note: n can be set to any integer in the range [1,maxn]
c       and non0 can be set to any integer in the range
c       [1,n]

      n=10
      non0=10
      lcondm=0
      call dload(n,one,x,1)
      call qbpmkm(lcondm,iseed)
      call qbpmx(x,y,.false.)
      call axpy(n,minus1,x,1,y,1)
      error=nrm2(n,y,1)
      print *,'** VERIFICATION TEST 2 completed **'
      print *,'   error = ',error
      print *,'   error should (approximately) equal 0.'

c *******************
c VERIFICATION TEST 3
c
c Subroutine tested:
c  qbpsx
c *******************

c Note: the typical user will never need to call this
c       routine directly

c Because of the special form of the matrix S we can
c easily check subroutine qbpsx (that forms the product
c of S and a vector x).  We do this by setting x to
c the ones vector and computing x=S*S*x.  We then
c set x=x-w, where the first nx components of w are
c zero and the last ny components are one, and form
c x'x which should equal 0.

c Note: nx can be set to any integer in the range
c       [1,maxn-ny] and ny can be set to any integer
c       in the range [1,maxn-nx]

      nx=6
      ny=4
      n=nx+ny
      m=min(nx,ny)
      call dload(n,one,x,1)
      call qbpsx(x,y)
      call qbpsx(y,x)
      call axpy(ny,minus1,one,0,x(nx+1),1)
      error=nrm2(n,x,1)
      print *,'** VERIFICATION TEST 3 completed **'
      print *,'   error = ',error
      print *,'   error should (approximately) equal 0.'

c *******************
c VERIFICATION TEST 4
c
c Subroutine tested:
c  qbpax
c *******************

c Note: the typical user will never need to call this
c       routine directly

c Because of the special form of the matrix A we can
c easily check subroutine qbpax (that forms the product
c of A and a vector x).  We do this by setting x to
c the ones vector and computing y=A*x.  The sum of the
c components of y should equal 0.

c Note: nx can be set to any integer in the range
c       [1,maxn-ny] and ny can be set to any integer
c       in the range [1,maxn-nx]

      nx=6
      ny=4
      n=nx+ny
      m=min(nx,ny)
      call dload(n,one,x,1)
      call qbpax(x,y)
      call dload(3*m,one,x,1)
c*****precision > double
      error=dot(3*m,x,1,y,1)
c*****end precision > double
c*****precision > single
c      error=dot(3*m,x,1,y,1)
c*****end precision > single
      print *,'** VERIFICATION TEST 4 completed **'
      print *,'   error = ',error
      print *,'   error should (approximately) equal 0.'

c format specifications

   10 format(9x,2f19.14)
      stop
c last card of program verify
      end
******************************************************
