forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Access violation during compilation
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Tue Sep 29, 2020 11:07 am    Post subject: Reply with quote

John Campbell

I get the same failure when I run the code from your link.

I have added it to the list. At the moment I don't know how difficult it will be to fix.
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Wed Sep 30, 2020 12:16 pm    Post subject: Reply with quote

Here is an update on the original issue at the start of this thread.

The following code presents a modified version of qsort_int that runs correctly on my machine (i.e. using the current developers' version).

It illustrates the essence of what the compiler has to do on behalf of programmers when they call a function (that returns an array) from within an array constructor.

tmp1, tmp2 and tmp3 represent temporary arrays that the compiler must create in addition to those already provided to handle the PACK routine. Internal code must also be provided that allows the returned size (of the result of PACK) to be zero.

Code:
 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
    isize1 = count(data(2:) <  data(1))
    if(isize1 > 0) tmp1 = qsort_int(pack(data(2:), data(2:) <  data(1)))
    isize2 = count(data(1:) == data(1))
    tmp2 = pack(data(1:), data(1:) == data(1))
    isize3 = count(data(2:) >  data(1))
    if(isize3 > 0) tmp3 = qsort_int(pack(data(2:), data(2:) >  data(1)))
    if ( size(data) > 1 ) then
        sorted = (/ tmp1(1:isize1), tmp2(1:isize2), tmp3(1:isize3) /)
    else
        sorted = data
    endif
  end function qsort_int
Back to top
View user's profile Send private message AIM Address
JohnCampbell



Joined: 16 Feb 2006
Posts: 2239
Location: Sydney

PostPosted: Thu Oct 01, 2020 4:29 am    Post subject: Reply with quote

Paul,

Thanks for the change, although it does not run on my version of FTN95.

I am not sure where the restrictions are that required your changes.
Would be good to better understand the limitations.

Could the following change work with your version of FTN95 ?
Code:
 recursive function qsort_int (data) result(sorted)
    integer, dimension(:), intent(in) :: data
    integer, dimension(1:size(data))  :: sorted
    integer, dimension(1:size(data))  :: tmp1
    integer ilt,ieq,igt
!
    if ( size(data) > 1 ) then
        ilt = count(data(2:) <  data(1))
        if (ilt > 0) tmp1(1:ilt) = qsort_int(pack(data(2:), data(2:) <  data(1)))
        igt = count(data(2:) >  data(1))
        ieq = size(data) - ilt - igt
        if (igt > 0) tmp1(ilt+ieq+1:) = qsort_int(pack(data(2:), data(2:) >  data(1)))
        tmp1(ilt+1:ilt+ieq) = data(1)
!
        sorted = tmp1
    else
        sorted = data
    endif
  end function qsort_int
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Thu Oct 01, 2020 6:54 am    Post subject: Reply with quote

John

At the moment FTN95 can't parse code that calls a function from within an array constructor where the function returns a varying sized array.

This is not an exact description. The function qsort_int contains calls to a function of a function (i.e. PACK) and is also recursive.

PACK returns a varying sized array whilst qsort_int returns a fixed sized array.

At compiler level, PACK has a number of obvious arguments but also passes a temporary array that is the same size as the array to be packed. PACK fills the destination array and also returns the number of elements filled.

When PACK is called as an argument in another function call, the temporary array for PACK can be passed on to the calling function together with the information about the current value of its varying size.

Also, for a simple assignment ARRAY = PACK(...), the compiler can use ARRAY as the destination rather than create a temporary array. This means that the calls to COUNT in my code above become redundant when everything is done internally.


Last edited by PaulLaidler on Thu Oct 01, 2020 8:22 am; edited 1 time in total
Back to top
View user's profile Send private message AIM Address
JohnCampbell



Joined: 16 Feb 2006
Posts: 2239
Location: Sydney

PostPosted: Thu Oct 01, 2020 7:27 am    Post subject: Reply with quote

Paul,

Does the following variation address your comment, or is it worse ?
Code:
 recursive function qsort_int (data) result(sorted)
    integer, dimension(:), intent(in) :: data
    integer, dimension(1:size(data))  :: sorted
    integer, dimension(1:size(data))  :: tmp1
    integer ilt,ieq,igt
!
    if ( size(data) > 1 ) then
        ilt = count (data(2:) < data(1) )
        if (ilt > 0) then
          tmp1 = pack (data(2:), data(2:) < data(1) )
          sorted(1:ilt) = qsort_int ( tmp1(1:ilt) )
        end if
        igt = count (data(2:) >  data(1))
        ieq = size(data) - ilt - igt
        sorted(ilt+1:ilt+ieq) = data(1)
        if (igt > 0) then
          tmp1 = pack (data(2:), data(2:) > data(1) )
          sorted(ilt+ieq+1:) = qsort_int( tmp1(1:igt) )
        end if
!
    else
        sorted = data
    endif
  end function qsort_int

Is FTN95 Ver 8.65 the compiler you are using ?
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Thu Oct 01, 2020 8:32 am    Post subject: Reply with quote

John

I prefer not to get into a discussion about alternatives at the moment. There is still the possibility that the primary issue might be resolved.

I am using the developers' version of FTN95 that is post v8.65.
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Wed Oct 07, 2020 11:59 am    Post subject: Reply with quote

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.

Code:
 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
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Wed Oct 07, 2020 4:22 pm    Post subject: Reply with quote

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.
Back to top
View user's profile Send private message AIM Address
JohnCampbell



Joined: 16 Feb 2006
Posts: 2239
Location: Sydney

PostPosted: Thu Oct 08, 2020 11:32 am    Post subject: Reply with quote

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
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1429

PostPosted: Thu Oct 08, 2020 4:05 pm    Post subject: Reply with quote

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

Code:
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.
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Thu Oct 08, 2020 7:30 pm    Post subject: Reply with quote

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.
Back to top
View user's profile Send private message AIM Address
JohnCampbell



Joined: 16 Feb 2006
Posts: 2239
Location: Sydney

PostPosted: Fri Oct 09, 2020 12:42 am    Post subject: Reply with quote

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

Code:
    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.
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Fri Oct 09, 2020 6:56 pm    Post subject: Reply with quote

John

That is a very interesting idea (using auto allocate). I will investigate how this works out for FTN95.
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 6590
Location: Salford, UK

PostPosted: Thu Oct 15, 2020 11:43 am    Post subject: Reply with quote

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

Code:
 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...

http://forums.silverfrost.com/viewtopic.php?t=4245

Work on this issue is still ongoing.
Back to top
View user's profile Send private message AIM Address
JohnCampbell



Joined: 16 Feb 2006
Posts: 2239
Location: Sydney

PostPosted: Mon Oct 19, 2020 1:04 pm    Post subject: Reply with quote

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.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group