NAG Library Manual, Mark 30.1
Interfaces:  FL   CL   CPP   AD 

NAG FL Interface Introduction
Example description
    Program e04rnfe

!     E04RNF Example Program Text
!     Mark 30.1 Release. NAG Copyright 2024.

!     Compute E-optimal experiment design via semidefinite programming,
!     this can be done as follows
!       max {lambda_min(A) | A = sum x_i*v_i*v_i^T, x_i>=0, sum x_i = 1}
!     where v_i are given vectors.

!     Use nag_library

!     .. Use Statements ..
      Use, Intrinsic                   :: iso_c_binding, Only: c_null_ptr,     &
                                          c_ptr
      Use nag_library, Only: e04raf, e04rff, e04rhf, e04rjf, e04rnf, e04rzf,   &
                             e04svf, e04zmf, nag_wp
!     .. Implicit None Statement ..
      Implicit None
!     .. Parameters ..
      Real (Kind=nag_wp), Parameter    :: big = 1E+20_nag_wp
      Integer, Parameter               :: nin = 5, nout = 6
!     .. Local Scalars ..
      Type (c_ptr)                     :: h
      Real (Kind=nag_wp)               :: tol
      Integer                          :: dima, i, idblk, idlc, idx, ifail,    &
                                          inform, j, k, m, nblk, nnzasum,      &
                                          nnzb, nnzc, nnzu, nnzua, nnzuc,      &
                                          nvar, p
!     .. Local Arrays ..
      Real (Kind=nag_wp), Allocatable  :: a(:), b(:), bl(:), bu(:), c(:),      &
                                          v(:,:), x(:)
      Real (Kind=nag_wp)               :: rdummy(1), rinfo(32), stats(32)
      Integer, Allocatable             :: blksizea(:), icola(:), icolb(:),     &
                                          idxc(:), irowa(:), irowb(:), nnza(:)
      Integer                          :: idummy(1)
!     .. Intrinsic Procedures ..
      Intrinsic                        :: repeat
!     .. Executable Statements ..

      Write (nout,*) 'E04RNF Example Program Results'
      Write (nout,*)
      Flush (nout)

!     Skip heading in data file.
      Read (nin,*)

!     Read in the number of vectors and their size.
      Read (nin,*) m
      Read (nin,*) p

      Allocate (v(p,m))

!     Read in the vectors v_j.
      Do j = 1, m
        Read (nin,*)(v(i,j),i=1,p)
      End Do

!     Initialize handle.
      h = c_null_ptr

!     Variables of the problem will be x_1, ..., x_m (weights of the vectors)
!     and t (artificial variable for minimum eigenvalue).
      nvar = m + 1

!     Initialize an empty problem handle with NVAR variables.
      ifail = 0
      Call e04raf(h,nvar,ifail)

!     Add the objective function to the handle: max t.
      nnzc = 1
      Allocate (idxc(nnzc),c(nnzc))
      idxc(:) = (/m+1/)
      c(:) = (/1._nag_wp/)

      ifail = 0
      Call e04rff(h,nnzc,idxc,c,0,idummy,idummy,rdummy,ifail)

      Allocate (bl(nvar),bu(nvar))
      bl(1:m) = 0.0_nag_wp
      bl(m+1) = -big
      bu(1:m+1) = big

!     Add simple bounds on variables, x_i>=0.
      ifail = 0
      Call e04rhf(h,nvar,bl,bu,ifail)

      nnzb = m
      Allocate (irowb(nnzb),icolb(nnzb),b(nnzb))
      irowb(:) = 1
      icolb(:) = (/(j,j=1,m)/)
      b(:) = 1.0_nag_wp

!     Add the linear constraint: sum x_i = 1.
      idlc = 0
      ifail = 0
      Call e04rjf(h,1,(/1.0_nag_wp/),(/1.0_nag_wp/),nnzb,irowb,icolb,b,idlc,   &
        ifail)

!     Generate matrix constraint as:
!       sum_{i=1}^m x_i*v_i*v_i^T - t*I >=0

      nblk = 1
      dima = p

!     Total number of nonzeros
      nnzasum = p + m*(p+1)*p/2

      Allocate (nnza(nvar+1),irowa(nnzasum),icola(nnzasum),a(nnzasum),x(nvar))
!     A_0 is empty
      nnza(1) = 0
!     A_1, A_2, ..., A_m are v_i*v_i^T
      nnza(2:m+1) = (p+1)*p/2
      idx = 0
      Do k = 1, m
        Do i = 1, p
          Do j = i, p
            idx = idx + 1
            irowa(idx) = i
            icola(idx) = j
            a(idx) = v(i,k)*v(j,k)
          End Do
        End Do
      End Do
!     A_{m+1} is the -identity
      nnza(m+2) = p
      Do i = 1, p
        idx = idx + 1
        irowa(idx) = i
        icola(idx) = i
        a(idx) = -1.0_nag_wp
      End Do

!     Add the constraint to the problem formulation.
      Allocate (blksizea(nblk))
      blksizea(:) = (/dima/)

      idblk = 0
      ifail = 0
      Call e04rnf(h,nvar,dima,nnza,nnzasum,irowa,icola,a,nblk,blksizea,idblk,  &
        ifail)

!     Set optional arguments of the solver.
      ifail = 0
      Call e04zmf(h,'Task = Maximize',ifail)
      ifail = 0
      Call e04zmf(h,'Initial X = Automatic',ifail)

!     Pass the handle to the solver, we are not interested in
!     Lagrangian multipliers.
      nnzu = 0
      nnzuc = 0
      nnzua = 0

      ifail = 0
      Call e04svf(h,nvar,x,nnzu,rdummy,nnzuc,rdummy,nnzua,rdummy,rinfo,stats,  &
        inform,ifail)

!     Print results
      Write (nout,*)
      tol = 0.00001_nag_wp
      Write (nout,*) '  Weight        Row of design matrix'
      Write (nout,*) repeat('-',13+p*8)
      Do j = 1, m
        If (x(j)>tol) Then
          Write (*,99999) x(j), v(1:p,j)
        End If
      End Do
      Write (nout,99998) 'only those rows with a weight > ', tol, ' are shown'

!     Destroy the handle.
      ifail = 0
      Call e04rzf(h,ifail)

99999 Format (1X,F7.2,5X,10(1X,F7.2))
99998 Format (1X,A,E8.1,A)
    End Program e04rnfe