[Shootout-list] fannkuch.f90

Simon Geard simon@whiteowl.co.uk
Sun, 19 Dec 2004 18:15:04 +0000


This is a multi-part message in MIME format.
--------------020206060104030901030906
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

I have fixed the fannkuch.f90 program to use an efficient permutation 
generator. The result for N=9 on my machine is

[simon@fawkes f90]$ time -p fannkuch 9
 Pfannkuchen(9) = 30
real 0.21
user 0.20
sys 0.00


How are you getting on with installing the f90 compiler on your test 
machine?

Simon


--------------020206060104030901030906
Content-Type: text/plain;
 name="fannkuch.f90"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="fannkuch.f90"

! Fannkuch access function implementation
! Simon Geard, 1/12/04
!
! Building info.
! ==============
!
! Linux  - using the Intel Fortran90 compiler:
!
!          ifort fannkuch.f90 -O3 -static-libcxa -o fannkuch
!
! WinXP  - Compaq Visual Fortran 6.6c
!
!          f90 fannkuch.f90 /link /libpath:"d:\Program Files\Microsoft Visual Studio\df98\lib"
!
! Cygwin - g95 compiler
!
!          g95 fannkuch.f90 -O3 -o fannkuch.exe
!
!!$"Take a permutation of {1,...,n}, for example: {4,2,1,5,3}. Take the first element, here 4, and reverse the order of the first 4 elements: {5,1,2,4,3}. Repeat this until the first element is a 1, so flipping won't change anything more: {3,4,2,1,5}, {2,4,3,1,5}, {4,2,3,1,5}, {1,3,2,4,5}. Count the number of flips, here 5. Do this for all n! permutations, and record the maximum number of flips needed for any permutation. The conjecture is that this maximum count is approximated by n*log(n) when n goes to infinity.
!!$
!!$FANNKUCH is an abbreviation for the German word Pfannkuchen, or pancakes, in analogy to flipping pancakes."
!!$
!!$Correct output N = 7 is:
!!$
!!$Pfannkuchen(7) = 16
!!$
!!$
!!$Correct output N = 8 is:
!!$
!!$Pfannkuchen(8) = 22
!!$
!!$
!!$Correct output N = 9 is:
!!$
!!$Pfannkuchen(9) = 30
!!$
!!$
!!$Correct output N = 10 is:
!!$
!!$Pfannkuchen(10) = 38

program fannkuch
  implicit none
  integer count, i, num
  character(len=8) argv
  integer, dimension(:), allocatable :: data
  intrinsic max

  call getarg(1,argv)
  read(argv,*) num
  allocate(data(num))

  count = 0
  data = (/ (i,i=1,num) /) ! Must start with the smallest number
  do i=1,factorial(num)
     count = max(count,countFlips(data))
     call getNextPerm(data)
  end do
  
  deallocate(data)
  
  write(*,'(1X,A,I0,A,I2)') 'Pfannkuchen(',num,') = ',count

contains

  recursive integer function factorial(n) result(if)
    integer, intent(in) :: n
    if (n == 1) then
       if = 1
    else
       if = n*factorial(n-1)
    end if
  end function factorial

  ! Reverse an array
  subroutine reverse(data)
    integer, dimension(:), intent(inout) :: data
    integer, dimension(size(data)) :: work
    integer i
   ! print *,'reversing ',data
    forall (i=1:size(data))
       work(i) = data(size(data)-i+1)
    end forall
    data = work
  end subroutine reverse

  ! Count the number of flips in a permutation
  integer function countFlips(data)
    integer, dimension(:), intent(in) :: data
    integer, dimension(size(data)) :: work
    work = data
    countFlips = 0
    do
       if (work(1) <= 1) exit
       call reverse(work(1:work(1)))
       countFlips = countFlips + 1
    end do
  end function countFlips

  ! Get next permutation
  subroutine getNextPerm(data)
    integer, dimension(:), intent(inout) :: data
    integer :: i, kx, e, ci, ce, tmp, N

    ! Find largest k s.t. data(k) < data(k+1)
    N = size(data)
    kx = 0
    do i=1,N-1
       if (data(i) < data(i+1)) then
          kx = i
       end if
    end do

    ! Find smallest data(k+j) > data(k)
    e = data(kx)
    ci = kx
    do i=kx+1,N
       if (data(i) > e .and. (ci == kx .or. data(i) < ce)) then
          ci = i
          ce = data(i)
       end if
    end do

    ! Swap data(k) and data(k+j)
    tmp = data(kx)
    data(kx) = data(ci)
    data(ci) = tmp

    ! Reverse data(k+1) ... data(N)
    call reverse(data(kx+1:N))
    
  end subroutine getNextPerm

end program fannkuch

--------------020206060104030901030906--