! *****************************************************************
! *****************************************************************

program analyse

  implicit none

  ! SCALAR PARAMETERS
  integer, parameter :: nmeth = 2, nprob = 740
  real(kind=8) :: epsfeas = 1.0d-08
  
  ! LOCAL SCALARS
  logical :: ldum
  integer :: i,j,jmin,jmax,k,idum,pos
  real(kind=8) :: btol,ftol,tau,ddum
  
  ! LOCAL ARRAYS
  logical :: comparable(nprob),compandeqf(nprob),ignore(nprob)
  integer :: istop(nmeth,nprob),xtype(nmeth,nprob),n(nmeth,nprob),m(nmeth,nprob),howmany(nmeth), &
       vec(0:20),counters(nmeth,nprob,1:9)
  real(kind=8) :: f(nmeth,nprob),csupn(nmeth,nprob),bdsvio(nmeth,nprob),time(nmeth,nprob), &
       metric(nmeth,nprob),bestfun(nprob)
  character(len=23) :: mname(nmeth,nprob),pname(nmeth,nprob)

  character(len=500) :: line
  character(len=100) :: sdum
  
  i = 1

  write(*,*) 'reading table-nlp-without-acc.txt ...'
  
  open(unit=10,file='table-nlp-without-acc.txt')

  do j = 1,nprob
     read(10,'(A)') line
     do while ( line(1:1) .eq. '#' )
        read(10,'(A)') line
     end do
     
     open(unit=20,file='tempo.txt',status='new')
     write(20,*) line
     
     rewind(20)
     
     read(20,*) mname(i,j),pname(i,j),time(i,j),idum,istop(i,j),xtype(i,j),ldum, &
             n(i,j),m(i,j),f(i,j),csupn(i,j),ddum,ddum,bdsvio(i,j),counters(i,j,1:9)

     close(20,status='delete')
  end do
  
  close(10)

  i = 2

  write(*,*) 'reading table-nlp-without-acc-modified.txt ...'
  
  open(10,file='table-nlp-without-acc-modified.txt')

  do j = 1,nprob
     read(10,'(A)') line
     do while ( line(1:1) .eq. '#' )
        read(10,'(A)') line
     end do
     
     open(unit=20,file='tempo.txt',status='new')
     write(20,*) line
     
     rewind(20)

     read(20,*) mname(i,j),pname(i,j),time(i,j),idum,istop(i,j),xtype(i,j),ldum, &
             n(i,j),m(i,j),f(i,j),csupn(i,j),ddum,ddum,bdsvio(i,j),counters(i,j,1:9)

     close(20,status='delete')
        
     if ( pname(i,j) .ne. pname(1,j) .or. n(i,j) .ne. n(1,j) .or. m(i,j) .ne. m(1,j) ) then
        write(*,*) 'Error in the input file.',pname(i,j),n(i,j),m(i,j),pname(1,j),n(1,j),m(1,j)
        stop
     end if
  end do

  do j = 1,nprob
     if ( istop(1,j) .ne. istop(2,j) .or. xtype(1,j) .ne. xtype(2,j) .or. f(1,j) .ne. f(2,j) .or. &
          csupn(1,j) .ne. csupn(2,j) .or. bdsvio(1,j) .ne. bdsvio(2,j) .or. any( counters(1,j,1:9) .ne. counters(2,j,1:9) ) ) then
        ignore(j) = .false.
        if ( istop(1,j) .eq. 99 .or. istop(2,j) .eq. 99 ) then
        write(*,*) j,pname(1,j),istop(1,j),xtype(1,j),f(1,j),csupn(1,j),bdsvio(1,j),counters(1,j,1:9)
        write(*,*) j,pname(2,j),istop(2,j),xtype(2,j),f(2,j),csupn(2,j),bdsvio(2,j),counters(2,j,1:9)
        write(*,*)
        end if
     else
        ignore(j) = .true.
!!$        write(*,*) j,pname(1,j),istop(1,j),xtype(1,j),f(1,j),csupn(1,j),bdsvio(1,j),counters(1,j,1:9)
!!$        write(*,*) j,pname(2,j),istop(2,j),xtype(2,j),f(2,j),csupn(2,j),bdsvio(2,j),counters(2,j,1:9)
!!$        write(*,*)
     end if
  end do
  
  write(*,*) 'Sequences generated by both methods are identical in ',count( ignore(1:nprob) ),' problems over a total of ',nprob
  write(*,*) 'This problems are ignored in everything that follows below.'
  
  vec(0:20) = 0
  
  do j = 1,nprob
     if ( .not. ignore(j) ) then
        if ( istop(1,j) .eq. 99 ) then
           vec(12) = vec(12) + 1
        else if ( istop(1,j) .eq. 20 ) then
           vec(11) = vec(11) + 1
        else
           if ( istop(1,j) .lt. 0 .or. istop(1,j) .gt. 10 ) then
              write(*,*) 'In problem ',j,' Algencan istop = ',istop(1,j)
           else
              vec(istop(1,j)) = vec(istop(1,j)) + 1
           end if
        end if
     end if
  end do
  
  write(*,*)
  write(*,*) 'Algencan stopping criteria summary:'
  write(*,*) 'vec = ',vec(0:12),' sum = ',sum(vec(0:12))
  
  vec(0:20) = 0
  
  do j = 1,nprob
     if ( .not. ignore(j) ) then
        if ( istop(2,j) .eq. 99 ) then
           vec(12) = vec(12) + 1
        else if ( istop(2,j) .eq. 20 ) then
           vec(11) = vec(11) + 1
        else
           if ( istop(2,j) .lt. 0 .or. istop(2,j) .gt. 10 ) then
              write(*,*) 'In problem ',j,' (modified) Algencan istop = ',istop(2,j)
           else
              vec(istop(2,j)) = vec(istop(2,j)) + 1
           end if
        end if
     end if
  end do
  
  write(*,*)
  write(*,*) '(modified) Algencan stopping criteria summary:'
  write(*,*) 'vec = ',vec(0:12),' sum = ',sum(vec(0:12))

  write(*,*)
  write(*,*) 'Satisfaction of constraints with tolerance 1e-8 and bound constraints with tolerance 1e-1, 1e-2, ..., 1e-16, 0'
  do i = 1,nmeth
     do k = 1,17
        if ( k .eq. 1 ) then
           btol = 0.1d0
        else if ( 2 .le. k .and. k .le. 16 ) then
           btol = 0.1d0 * btol
        else ! if ( btol .eq. 17 ) then
           btol = 0.0d0
        end if
        vec(k) = count( .not. ignore(1:nprob) .and. csupn(i,1:nprob) .le. epsfeas .and. bdsvio(i,1:nprob) .le. btol )
     end do
     write(*,*) mname(i,1),vec(1:17)
  end do

  comparable(1:nprob) = .not. ignore(1:nprob) .and. &
                        csupn(1,1:nprob) .le. epsfeas .and. bdsvio(1,1:nprob) .le. epsfeas .and. &
                        csupn(2,1:nprob) .le. epsfeas .and. bdsvio(2,1:nprob) .le. epsfeas

  do j = 1,nprob
     if ( .not. ignore(j) .and. &
          ( ( csupn(1,j) .le. epsfeas .and. bdsvio(1,j) .le. epsfeas ) .and. &
          .not. ( csupn(2,j) .le. epsfeas .and. bdsvio(2,j) .le. epsfeas ) .or. &
          ( csupn(2,j) .le. epsfeas .and. bdsvio(2,j) .le. epsfeas ) .and. &
          .not. ( csupn(1,j) .le. epsfeas .and. bdsvio(1,j) .le. epsfeas ) ) ) then
        write(*,*) j,pname(1,j),istop(1,j),xtype(1,j),f(1,j),csupn(1,j),bdsvio(1,j),counters(1,j,1:9)
        write(*,*) j,pname(2,j),istop(2,j),xtype(2,j),f(2,j),csupn(2,j),bdsvio(2,j),counters(2,j,1:9)
        write(*,*)
     end if
  end do
  
  write(*,*)
  write(*,*) 'We assume that performances are comparable if the methods found a point with equivalent feasibilities.'
  write(*,*) 'And we say feasibilities are equivalent if constraints (as originally formulated) are satisfied with '
  write(*,*) 'precision 1e-8 and bounds are satisfied with precision 1e-8 as well. There are ',count( comparable(1:nprob) ), &
       ' that satisfy these conditions.'

  write(*,*) 'Among comparable problems: '
  write(*,*) 'Algencan xtype=1: ',count( comparable(1:nprob) .and. xtype(1,1:nprob) .eq. 1 )
  write(*,*) '(modified) Algencan xtype=1: ',count( comparable(1:nprob) .and. xtype(2,1:nprob) .eq. 1 )

  do j = 1,nprob
     if ( comparable(j) ) then
        bestfun(j) = minval( f(1:nmeth,j) )
     end if
  end do

  write(*,*)
  write(*,*) 'Among comparable problems, number of best solutions found as a function o ftol: 1e-1, 1e-2, 1e-3, ..., 1e-8, 0'

  do i = 1,nmeth
     ftol = 1.0d0
     do k = 1,9
        if ( k .eq. 1 ) then
           ftol = 0.1d0
        else if ( 2 .le. k .and. k .le. 8 ) then
           ftol = 0.1d0 * ftol
        else ! if ( k .eq. 9 )
           ftol = 0.0d0
        end if
        vec(k) = count( comparable(1:nprob) .and. &
             f(i,1:nprob) .le. bestfun(1:nprob) + ftol * max( 1.0d0, abs( bestfun(1:nprob) ) ) )
     end do
     write(*,*) mname(i,1),vec(1:9)
  end do
  
  ftol = 1.0d-08

  write(*,*)
  write(*,*) 'Problems with comparable feasibility in which f differs (CONSIDERING FTOL=1e-8).'
  do j = 1,nprob
     if ( comparable(j) ) then
        if ( all( f(1:nmeth,j) .le. bestfun(j) + ftol * max( 1.0d0, abs( bestfun(j) ) ) ) ) then
           compandeqf(j) = .true.
        else
           compandeqf(j) = .false.
!!$           write(*,100) pname(1,j),f(1,j),csupn(1,j),bdsvio(1,j),f(2,j),csupn(2,j),bdsvio(2,j)
        end if
     else
        compandeqf(j) = .false.
     end if
  end do

  write(*,*)
  write(*,*) 'CONSIDERING FTOL=1e-8, all methods found comparable points with equivalent f in ', &
       count( compandeqf(1:nprob) ),' problems.'
  write(*,*) 'Efficiency will be evaluated considering these problems only.'

  write(*,*)
  write(*,*) 'This is the performance profile in terms of number of CPU time'
  
  do j = 1,nprob
     if ( compandeqf(j) ) then
!!$        write(*,*) j,pname(1,j),time(1,j),istop(1,j),xtype(1,j),f(1,j),csupn(1,j),bdsvio(1,j),counters(1,j,1:9)
!!$        write(*,*) j,pname(2,j),time(2,j),istop(2,j),xtype(2,j),f(2,j),csupn(2,j),bdsvio(2,j),counters(2,j,1:9)
!!$        write(*,*)

        metric(1:nmeth,j) = ( 1.0d0 * time(1:nmeth,j) ) / minval( time(1:nmeth,j) )
        if ( all( time(1:nmeth,j) .ge. 1.0d0 ) .and. any( metric(1:nmeth,j) .ge. 10.0d0 ) ) then
           write(*,*) pname(1,j),time(1,j),metric(1,j),time(2,j),metric(2,j)
        end if
     else
        metric(1:nmeth,j) = huge( 1.0d0 )
     end if
  end do
  
  open(900,file='pptime.dat')
  
  tau = 1.0d0
  do while ( tau .le. 2.0d+04 )
     do i = 1,nmeth
        howmany(i) = count( metric(i,1:nprob) .le. tau )
     end do

     write(900,200) tau,( 1.0d0 * howmany(1:nmeth) ) / count( compandeqf(1:nprob) )

     if ( abs( tau -     1.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.1d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.2d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.3d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.4d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.5d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.6d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.7d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.8d0 ) .le. 5.0d-02 .or. &
          abs( tau -     1.9d0 ) .le. 5.0d-02 .or. &
          abs( tau -     2.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -     3.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -     4.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -     5.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -    10.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -    15.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -    20.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -    30.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -    40.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -    50.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -   100.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -   500.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -  1000.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -  1500.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -  5000.0d0 ) .le. 5.0d-02 .or. &
          abs( tau -  7500.0d0 ) .le. 5.0d-02 .or. &
          abs( tau - 10000.0d0 ) .le. 5.0d-02 .or. &
          abs( tau - 15000.0d0 ) .le. 5.0d-02 .or. &
          abs( tau - 20000.0d0 ) .le. 5.0d-02 ) then
        write(*,200) tau,( 1.0d0 * howmany(1:nmeth) ) / count( compandeqf(1:nprob) )
     end if
     
     tau = tau + 1.0d-01
  end do

  close(900)

  stop

!!$100 format(1X,A10,2(1X,1P,D24.16,2(1X,1P,D7.1)))
200 format(F8.2,16(1X,F10.6))
  
end program analyse
