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

NAG FL Interface Introduction
Example description
    Program g02aafe

!     G02AAF Example Program Text

!     Mark 29.2 Release. NAG Copyright 2023.

!     .. Use Statements ..
      Use nag_library, Only: f06rcf, g02aaf, nag_wp, x04caf
!     .. Implicit None Statement ..
      Implicit None
!     .. Parameters ..
      Integer, Parameter               :: nin = 5, nout = 6
!     .. Local Scalars ..
      Real (Kind=nag_wp)               :: dist, errtol, nrmgrd
      Integer                          :: feval, i, ifail, iter, j, lda, ldg,  &
                                          ldx, maxit, maxits, n
      Character (1)                    :: uplo
!     .. Local Arrays ..
      Real (Kind=nag_wp), Allocatable  :: a(:,:), g(:,:), work(:), x(:,:)
      Integer, Allocatable             :: iwork(:)
!     .. Executable Statements ..

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

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

!     Read in the problem size
      Read (nin,*) n

      lda = n
      ldg = n
      ldx = n
      Allocate (a(lda,n),g(ldg,n),iwork(n),work(n),x(ldx,n))

!     Read in the matrix G
      Read (nin,*)(g(i,1:n),i=1,n)

      uplo = 'L'
!     Copy G into A to compute a bound on the distance to the NCM
!     We assume G is symmetric and copy only the lower triangle
      Do j = 1, n
        Do i = j, n
          a(i,j) = g(i,j)
        End Do
      End Do

      Call compute_bound(dist,uplo,n,g,ldg,a,lda,work,iwork,ifail)
      Write (nout,*)
      Write (nout,99999) 'Upper bound on the distance to the NCM:', dist
      Write (nout,*)

!     A was overwritten by compute_bound. In order to compute the actual
!     distance to the nearest correlation matrix, store another copy of G in A
      Do j = 1, n
        Do i = j, n
          a(i,j) = g(i,j)
        End Do
      End Do

!     Use the defaults for ERRTOL, MAXITS and MAXIT
      errtol = 0.0E0_nag_wp
      maxits = 0
      maxit = 0

!     Calculate nearest correlation matrix
      ifail = 0
      Call g02aaf(g,ldg,n,errtol,maxits,maxit,x,ldx,iter,feval,nrmgrd,ifail)

!     Compute distance between the original input matrix and the nearest
!     correlation matrix
      Do j = 1, n
        Do i = j, n
          a(i,j) = a(i,j) - x(i,j)
        End Do
      End Do

      dist = f06rcf('F',uplo,n,a,lda,work)

!     Display results
      ifail = 0
      Call x04caf('General',' ',n,n,x,ldx,'Nearest Correlation Matrix',ifail)
      Write (nout,*)
      Write (nout,99999) 'Distance between G and X:', dist
      Write (nout,99998) 'Number of Newton steps taken:', iter
      Write (nout,99997) 'Number of function evaluations:', feval

99999 Format (1X,A,F15.3)
99998 Format (1X,A,I11)
99997 Format (1X,A,I9)

    Contains
      Subroutine compute_bound(bound,uplo,n,g,ldg,a,lda,offdiag,ipiv,ifail)
!       Compute a bound on the distance between G and the nearest
!       correlation matrix using the modified Cholesky factorization.

!       .. Use Statements ..
        Use nag_library, Only: f01mdf, f01mef
!       .. Implicit None Statement ..
        Implicit None
!       .. Scalar Arguments ..
        Real (Kind=nag_wp), Intent (Out) :: bound
        Integer, Intent (Out)          :: ifail
        Integer, Intent (In)           :: lda, ldg, n
        Character (1), Intent (In)     :: uplo
!       .. Array Arguments ..
        Real (Kind=nag_wp), Intent (Inout) :: a(lda,n)
        Real (Kind=nag_wp), Intent (In) :: g(ldg,n)
        Real (Kind=nag_wp), Intent (Out) :: offdiag(n)
        Integer, Intent (Out)          :: ipiv(n)
!       .. Local Scalars ..
        Real (Kind=nag_wp)             :: delta
        Integer                        :: i, j
!       .. Local Arrays ..
        Real (Kind=nag_wp)             :: work(1)
!       .. Intrinsic Procedures ..
        Intrinsic                      :: sqrt
!       .. Executable Statements ..

        delta = 1.0E-7_nag_wp
!       Compute the modified Cholesky factorization of G
        ifail = 0
        Call f01mdf(uplo,n,a,lda,offdiag,ipiv,delta,ifail)

!       Compute the perturbed matrix G + E and store in A
        ifail = 0
        Call f01mef(uplo,n,a,lda,offdiag,ipiv,ifail)

!       Overwrite A with D^(-1/2)(G + E)D^(-1/2) - G
!       where D = diag(G + E)
        Do j = 1, n
          Do i = j + 1, n
            a(i,j) = a(i,j)/sqrt(a(i,i)*a(j,j)) - g(i,j)
          End Do
          a(j,j) = 1.0E0_nag_wp - g(j,j)
        End Do

!       Bound is given by ||D^(-1/2)(G + E)D^(-1/2) - G||
        bound = f06rcf('F',uplo,n,a,lda,work)

      End Subroutine compute_bound
    End Program g02aafe