Silverfrost Forums

Welcome to our forums

Access violation during compilation

7 Oct 2020 10:59 #26448

I have further investigated the failure of FTN95 to handle the recursive function qsort_int. You will recall that qsort_int takes PACK as an argument and is called from within an array constructor.

For the time being I am not able to provide a fix for this failure but I will keep it on the list of things to do.

In the mean time, I have added a new function to the library called IPACKED_SIZE@ that allows you to recode qsort_int in a way that avoids any additional computational overhead. The code below demonstrates how this will work when using the next release. Naturally IPACKED_SIZE@ will only work for FTN95. The alternative is to call COUNT using the second argument of PACK.

 recursive function qsort_int ( data ) result ( sorted )
    integer, dimension(:), intent(in) :: data
    integer, dimension(1:size(data))  :: sorted
    integer, dimension(1:size(data))  :: tmp1,tmp2,tmp3
    integer isize1,isize2,isize3

    if ( size(data) > 1 ) then
!$$$$$$         sorted = (/ qsort_int(pack(data(2:), data(2:) <  data(1))), &
!$$$$$$                                 pack(data(1:), data(1:) == data(1)),  &
!$$$$$$                     qsort_int(pack(data(2:), data(2:) >  data(1))) /)
      tmp1 = pack(data(2:), data(2:) <  data(1))
      isize1 = ipacked_size@()
      tmp1(1:isize1) = qsort_int(tmp1(1:isize1))
      tmp2 = pack(data(1:), data(1:) == data(1))
      isize2 = ipacked_size@()
      tmp3 = pack(data(2:), data(2:) >  data(1))
      isize3 = ipacked_size@()
      tmp3(1:isize3) = qsort_int(tmp3(1:isize3))
      sorted = (/ tmp1(1:isize1), tmp2(1:isize2), tmp3(1:isize3) /)
    else
        sorted = data
    endif
  end function qsort_int
7 Oct 2020 3:22 #26449

John Campbell

I have looked at your program mecej4_sort_test.f90.

There is a real*8 divide-by-zero runtime error. After fixing it, the code runs OK for me although I don't know what it is doing.

If it fails for you in some other way then you will need to wait for the next release of FTN95.

There was some other issue that you asked about and I can look at it now if you will remind me what it was.

8 Oct 2020 10:32 #26452

Paul,

Thanks for looking at this test. The only real*8 calculations relate to timing and timing ratios. This could indicate the use of system_clock is giving a zero time difference between two calls.

The main purpose of the test related to the recursive use of memory allocations and how PACK could be used in array sections. With the compiler I am using and further changes to the code, I am getting a virtual stack error, so I should wait for the next release of FTN95.

Thanks for your help and I look forward to the new release.

I will review what is the other issue and post to that.

John

8 Oct 2020 3:05 #26453

Paul's plan to provide a new function, ipacked_size@(), is a step in the right direction; however, it is associated with a problem that needs to be overcome.

The arrays tmp1, tmp2 and tmp3 are automatic arrays of declared size n_data = size(data). However, the sum of the active sizes of tmp1, tmp2 and tmp3 must equal n_data. Thus, in general, the three sizes will each be less than n_data. A special case with one of the three arrays containing n_data active elements by itself, the other two arrays will be effectively empty.

Therefore, assignments such as

tmp1 = pack(data(2:), data(2:) <  data(1))

violate the requirement of the language that the array on the l.h.s. and the array expression on the r.h.s. must be conformable.

In addition, there is the rule, 'The evaluation of expressions within variable shall neither affect nor be affected by the evaluation of expr'. This rule precludes the addition of a new, optional argument to the PACK function to obtain the size of the array produced by PACK and use that size in a subscript expression for the variable being assigned to.

8 Oct 2020 6:30 #26454

mecej4

If the statement that you quote is not valid Fortran then it must be regarded as an FTN95 extension to the standard. Logically, since PACK returns an array whose size is not known beforehand, all the programmer can do is provide a destination that is large enough for the worst case. In this case the size of the array happens to be one larger than it needs to be. Perhaps, for good Fortran, the vector argument ought to be added (but then a call to COUNT is required).

IPACKED_SIZE@ is clearly non-standard. PACK has been modified so that it remembers the size at the end of a call and this value is accessible via IPACKED_SIZE@. It is introduced simply to avoid the need to recount the number of items that have been packed.

The logic of the algorithm ensures that the final array constructor assignment is conformable.

My aim was to provide code that replicates what the compiler would do anyway if it were able to do it internally in one statement. As such it is, as you say, a step forward and hopefully will be helpful.

8 Oct 2020 11:42 #26455

With F2003 and auto allocate, the use of PACK can be used without the need for COUNT and I think is standard compatible.

    recursive function do_real_sort_03 (data) result(sorted)
!
!  this requires F2003 for auto allocation
!
      real, dimension(:), intent(in) :: data
      real, dimension(1:size(data))  :: sorted
!
      real, allocatable, dimension(:) :: LT, GT
      real    :: pivot
      integer :: n, nLT, nLE, nGT

      n = size(data)
      if ( n > bubble_size ) then
        pivot = select_good_pivot ( data )
        LT  = PACK ( data, data < pivot )
        GT  = PACK ( data, data > pivot )
        nLT = size ( LT )
        nGT = size ( GT )
        nLE = n - nGT
!
        sorted(1:nLT)     = do_real_sort_03 ( LT )
        sorted(nLT+1:nLE) = pivot
        sorted(nLE+1:n)   = do_real_sort_03 ( GT )
      else
        sorted = data
        if ( n > 1 ) call real_bubble_sort ( sorted )
      end if
!
    end function do_real_sort_03

'A special case with one of the three arrays containing n_data active elements by itself' This special case would fail, as the recursion would not terminate. It would indicate a poor selection of pivot.

9 Oct 2020 5:56 #26458

John

That is a very interesting idea (using auto allocate). I will investigate how this works out for FTN95.

15 Oct 2020 10:43 #26473

Here is an update on this issue together with a better work-around.

 recursive function qsort_int ( data ) result ( sorted )
    integer, dimension(:), intent(in) :: data
    integer, dimension(1:size(data))  :: sorted
    integer, allocatable,dimension(:) :: tmp1,tmp2,tmp3
    if ( size(data) > 1 ) then
      tmp1 = pack(data(2:), data(2:) <  data(1))
      tmp1 = qsort_int(tmp1)
      tmp2 = pack(data(1:), data(1:) == data(1))
      tmp3 = pack(data(2:), data(2:) >  data(1))
      tmp3 = qsort_int(tmp3)
      sorted = (/ tmp1, tmp2, tmp3 /)
    else
      sorted = data
    endif
  end function qsort_int
 end module

This requires v8.66 of FTN95 that is available here...

https://forums.silverfrost.com/Forum/Topic/3780

Work on this issue is still ongoing.

19 Oct 2020 12:04 #26485

Paul,

This support for auto allocate is a very interesting extension to FTN95. I was not aware that it had been included and shall test it's use. I thought this would have been a difficult extension.

19 Oct 2020 12:13 #26486

John

The initial coding for auto allocate was not as difficult as I expected but then the above Fortran was not anticipated and there will no doubt be other similar omissions.

Please login to reply.