replica nfl jerseysreplica nfl jerseyssoccer jerseyreplica nfl jerseys forums.silverfrost.com :: View topic - Problem: �Problem Array Section with /Checkmate�
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 

Problem: �Problem Array Section with /Checkmate�
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
KL



Joined: 16 Nov 2009
Posts: 155

PostPosted: Tue Nov 17, 2009 6:43 pm    Post subject: Problem: �Problem Array Section with /Checkmate� Reply with quote

The attached program looks terrible. However, it reflects the structure of a �real� program, where I found the problem. The problem occurs when running the program with the /Checkmate option, which I almost always use:

ftn95 Problem_Array_Section.f95 /Checkmate /underflow /Link >> comp.lis
sdbg Problem_Array_Section.exe

The error message is
�Attempt to call a routine with argument number two containing too few array elements�

The reason why I chose this form is because in the real problem the indices of array x (1,2,3..) in subroutine SubB correspond to indices 2,3,4 of array Data in subroutine SubA. For this transformation I need the array section as argument.

Is anything wrong with the program? Can anybody comment on this problem?

Many thanks,

Klaus Lassmann
[ Winapp

Program Problem_Array_Section


Implicit None
Integer :: i, n

Real , Dimension (400) :: Result

n = 3

! Subroutine SubA calculates with the help of SubB the field Result

Call SubA ( Result, n )
! #########

Write (*,*) ' Result (1,n)= ', ( Result (i), i=1,n )

Contains

Subroutine SubA (Data, m)

Implicit None
Integer :: i
Integer , Intent (in ) :: m
Real , Dimension (m), Intent (out) :: Data

! --- This call leads to an error when compiled with /Checkmate:

Call SubB ( m, Data (1:m) )

! --- This call seems to be OK

! Call SubB ( m, Data )

Write (*,*) ' Data (1,m) = ', ( Data (i), i=1,m )

End Subroutine SubA

End Program Problem_Array_Section

! --------------------------------------------------------------------

Subroutine SubB ( k,x )

Implicit None
Integer , Intent (in ) :: k
Real , Dimension (k), Intent (out) :: x
Integer :: i

Do i = 1, k
x(i) = i**2
End Do

End Subroutine SubB

]
Back to top
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Tue Nov 17, 2009 11:58 pm    Post subject: Reply with quote

Paul,
This second example shows that errors associated with array sections in subroutine arguments when compiled with /check are not limited to automatic arrays. The program works ok with /debug.
As I have found before, if I use array sections, I can not debug using /check.
Can this be investigated ?
Thanks John
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


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

PostPosted: Wed Nov 18, 2009 9:39 am    Post subject: Reply with quote

Yes this looks like a problem I need to look at but I may not be able to give you a quick response at the moment.
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


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

PostPosted: Thu Nov 19, 2009 9:02 am    Post subject: Reply with quote

I have identified the problem and expect to be able to fix it in one way or another.

The only short term solution is to use /inhibit_check 5 on the command line.
You could put subB in a separate file in order to apply this only to the subroutine.
Back to top
View user's profile Send private message AIM Address
KL



Joined: 16 Nov 2009
Posts: 155

PostPosted: Thu Nov 19, 2009 9:50 am    Post subject: Reply with quote

Paul,

thank you very much for your quick reaction. For me it is easy to circumvent this problem. I guess that this problem will be solved with the next update and I will wait for it.

Best wishes,

Klaus
Back to top
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Fri Dec 04, 2009 12:15 am    Post subject: Reply with quote

Paul,

Any update on this, as this bug has limited my use of both /check, SDBG and array sections for a number of years.
It would be a good one to clean up.

John
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


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

PostPosted: Fri Dec 04, 2009 9:10 am    Post subject: Reply with quote

I have been working on this but it is one of those tricky ones.
I am reasonably hopeful that it will be fixed for the next release.
Back to top
View user's profile Send private message AIM Address
IanLambley



Joined: 17 Dec 2006
Posts: 506
Location: Sunderland

PostPosted: Sat Dec 05, 2009 1:22 pm    Post subject: Reply with quote

I'm not sure why you ever need to use the form

Call SubB ( m, Data (1:m) )

If you are passing m as a variable, then the range (1:m) is redundant.

If you argue that you may want to pass another section of the array such as Data(i:j) then this can be done as:

i=5
j=10
m=j-i+1
call SubB(m,data(i))

for example if i=5 and j=10, then the following elements are required in the subroutine: 5, 6, 7, 8, 9, 10 which is six and m=10 - 5 + 1 = 6. This statement then passes 6 elements of array "data" starting with the 5th.

All you are passing for an array is the address of the start element and if that is the very first element, i.e. data(1) or data(1,1) then you only need to pass "data" and this you have done in the part of your example that worked. Even the shape of the array can be different from one program segment to another, but care is required if it is of rank 2 or higher.

The only reason that you might want to pass data(1:m) is if you also do not pass m and use a dummy dimension and the size finction to determine the passed size. See below:

Code:

winapp
integer*4 data1(10), i

do i=1,10
  data1(i) = i
enddo


call sub1(data1(2:4))


end


subroutine sub1(idata)
integer*4 idata(*),isize
isize = size(idata)

print *,'array contains ',isize,' elements'

print *,(idata(i),i=1,isize)

end

When compiling this with only /debug, the size of the array in the subroutine seems to be 538976289, which is ridiculous.

By adding /check, it partially works. I would have thought that it should work without the need to use any specific compiler switch. This might be in the documentation somewhere, but if not, it should be.

What happens is that the "size" function returns 9, which IS the size of the array starting at position2 to the end, i.e. position 10. I would have thought that it should have been of size 3.

I seems to be safer to go back to the old fashioned method as shown in sub2
Code:

winapp
integer*4 data1(10), i, m

do i=1,10
  data1(i) = i
enddo


m=4 - 2 + 1

call sub2(data1(2),m)


end



subroutine sub2(idata,m)
integer*4 idata(m),isize
isize = size(idata)

print *,'array contains ',isize,' elements'

print *,(idata(i),i=1,isize)

end



Comments please!!

Ian
Back to top
View user's profile Send private message Send e-mail
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Sat Dec 05, 2009 11:15 pm    Post subject: Reply with quote

Ian,

I have code which is of the form
Code:
call ends (data(6:7,n))
...
subroutine ends (end_data)
integer*4 end_data(2)
...

If I compile this with /debug, I think there is no problem, but if I compile it with /check, I get an error that the size of array is wrong. I can always overcome it by changing the code with a temporary array or not using /check. Unfortunately it is in a development project/hobby which at present I don't have much time to complete, so will have to wait till the bug goes. I've been trying to clean out old code patches and be more Fortran 95+ consistent.

John
Back to top
View user's profile Send private message
IanLambley



Joined: 17 Dec 2006
Posts: 506
Location: Sunderland

PostPosted: Sun Dec 06, 2009 12:00 am    Post subject: Reply with quote

Hi John,

I assume that data is a two dimensional array and that your intent is that the subroutine deals with the two elements in positions 6 & 7 on row n.

I think that it is only necessary to pass data(6,n) to the subroutine and as it is dimensioned to two in the subroutine, then it is treated within as a one dimensional array of two elements.

I have never understood the need for the array range format described whilst passing the info. I only use the start:end format for the dimensioning of arrays where the default start element is not 1.

But of course I'm an old fashioned guy and I might have missed the introduction of this method.
Multi dimensional arrays can be tricky to pass by the method described if one is hoping to refer to a small rectangular section which does not start at (1,1,1...) That is

Code:

consider a matrix containing values thus:
i----->
j   a b c d e f
|   g h i j k l
|   m n o p q r
v

This is stored in memory as a linear block of memory containing:
a b c d e f g h i j k l m n o p q r


Trying to pass the sub-array
i j and
o p using

call sub(data(3,2))

with
subroutine sub(data)
dimension data(2,2)


will just end up with the data in the subroutine containing:
i j
k l

That is, the call references the start element and the dimension of 2,2 takes the next 4 elements.

Using the start:end format for two-dim arrays would only make sense if one could pass:

data(3:4,2:3)

but then the compiler would have to extract the appropriate elements where it knows the original shape of the array, and reform these into separate linear storage and pass the pointer to this new grouping to the routine. On return, it would then have to reverse the process and set any new values which may have been changed in the subroutine. This is very messy, and I just don't think that Fortran does that. The time overhead would be excessive for large multi dimensional arrays.

Please confirm

Regards

Ian
Back to top
View user's profile Send private message Send e-mail
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Sun Dec 06, 2009 1:57 am    Post subject: Reply with quote

Ian,

My understanding is that when providing "data(3:4,2:3)" as an argument, then the compiler will provide a temporary array(2,2) and update it when it returns. I tested this on a recent post (see general>use of type arrays) by changing the argument, while the original array did not change, but was updated on return.
It's always difficult to stop using old Fortran, when it worked so well.

John[/quote]
Back to top
View user's profile Send private message
IanLambley



Joined: 17 Dec 2006
Posts: 506
Location: Sunderland

PostPosted: Sun Dec 06, 2009 10:05 am    Post subject: Reply with quote

John,

Wow - that is useful, I shall now have to rewrite all my software even though it works, well some of it works.

Test program where the array elements contain the subscripts in the form i*1000+j and the test subroutine negates the value so you can see the modification to the main routine data.
Code:

winapp
integer*4 i,data2(10,10),i1,i2,j1,j2,m12,n12

!set some data
do i=1,10
  do j=1,10
    data2(i,j) = i*1000 + j
  enddo   
enddo

!show the original contents
print *,'before call main data2 array contains '
do j=1,10
  print '(10i5)',(data2(i,j),i=1,10)
enddo
!define the sub array and its dimensions
i1  = 3
i2  = 6
m12 = i2 - i1 + 1
j1  = 2
j2  = 8
n12 = j2 - j1 + 1

!call  the test subroutine to negate the sub matrix values
call sub3(data2(i1:i2,j1:j2),m12,n12)

!display result of the action on the full matrix
print *,'after  call main data2 array contains '
do j=1,10
  print '(10i5)',(data2(i,j),i=1,10)
enddo

end

subroutine sub3(idata,m,n)
integer*4 idata(m,n),i,j,m,n

print *,'passed array contains '

do j=1,n
  print *,(idata(i,j),i=1,m)
  do i=1,m
    idata(i,j) = -idata(i,j)
  enddo
enddo
end

Thanks John!

Ian
Back to top
View user's profile Send private message Send e-mail
IanLambley



Joined: 17 Dec 2006
Posts: 506
Location: Sunderland

PostPosted: Sun Dec 06, 2009 10:50 am    Post subject: Reply with quote

But of course, I wan't happy about having to pass the dimensions, so using modules, interfaces and colons gives:

Code:

winapp
!create a module with interfaces for subroutines where necessary
module interfaces
INTERFACE
  SUBROUTINE SUB4(idata)
    INTEGER idata(:,:)
  END SUBROUTINE
END INTERFACE
end module interfaces

! add this statement wherever one of these subroutine is to be called
use interfaces

! create the test data
integer*4 i,j,data2(10,10),i1,i2,j1,j2
do i=1,10
  data1(i) = i
  do j=1,10
    data2(i,j) = i*1000 + j
  enddo   
enddo

! setup the range of the sub matrix
i1  = 3
i2  = 6
j1  = 2
j2  = 8

!  check the data content
print *,'before call main data2 array contains '
do j=1,10
  print '(10i5)',(data2(i,j),i=1,10)
enddo

! call the subroutine
call sub4(data2(i1:i2,j1:j2))

! show the changesprint *,'after  sub4 call main data2 array contains '
do j=1,10
  print '(10i5)',(data2(i,j),i=1,10)
enddo

end

subroutine sub4(idata)
! use blank place holders to show passed array is rank 2
integer*4 idata(:,:),i,j,m,n

m=size(idata,1)
n=size(idata,2)
print *,'array dimensions are',m,n
print *,'passed array contains '
do j=1,n
! show the sub matrix as passed
  print *,(idata(i,j),i=1,m)
! make some changes
  do i=1,m
    idata(i,j) = -idata(i,j)
  enddo
enddo
end


Now I understand, what you tried to say to me!
And how I suffered for my sanity.
etc.
Sorry about the corrupted song lyrics

And the following is also possible:
Code:

call sub4(data2(i1:i2,j1:j2:2))

Only alternate rows from data2 are passed, i.e. j1=start row, j2 = finish row and 2 is the row increment.

Regards

Ian
Back to top
View user's profile Send private message Send e-mail
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Sun Dec 06, 2009 1:19 pm    Post subject: Reply with quote

Ian,

I changed your program, using a module to access the original data2 array. The changed program shows (to me) that there must be a copy of the sectioned array data2, being used in sub4. It would appear that all sections are placed on the stack or heap, so we should be careful when specifying sections of large arrays,
for example with dot_product (a(i1:i2), b(j1:j2)); this could be very inefficient, in comparison to vecsum (a(i1), b(j1), i2-i1+1), when i2-i1 is large. I have made this mistake in the past! and now realise why the newish code did not work well.
Code:
!create a module with interfaces for subroutines where necessary
module all_data
integer*4 data1(10), data2(10,10)
end module all_data

module interfaces
INTERFACE
  SUBROUTINE SUB4(idata)
    INTEGER idata(:,:)
  END SUBROUTINE
END INTERFACE
end module interfaces

! add this statement wherever one of these subroutine is to be called
use all_data
use interfaces

! create the test data
integer*4 i,j
!
do i=1,10
  data1(i) = i
  do j=1,10
    data2(i,j) = i*1000 + j
  enddo   
enddo

!  check the data content
print *,'before call main data2 array contains '
do j=1,10
  print '(10i6)',(data2(i,j),i=1,10)
enddo

! call the subroutine
call sub4 ( data2(3:6,2:8) )

! show the changesprint *,'after  sub4 call main data2 array contains '
print *,'original array after return from sub4 contains '
do j=1,10
  print '(10i6)',(data2(i,j),i=1,10)
enddo

end

subroutine sub4 (idata)
use all_data
! use blank place holders to show passed array is rank 2
integer*4 idata(:,:),i,j,m,n

m=size (idata,1)
n=size (idata,2)
print *,'array dimensions are',m,n
print *,'passed array contains '
do j=1,n
! show the sub matrix as passed
  print *,(idata(i,j),i=1,m)
! make some changes
  do i=1,m
    idata(i,j) = -idata(i,j)
  enddo
enddo
!
print *,'passed array after changes contains '
do j=1,n
! show the sub matrix as passed
  print *,(idata(i,j),i=1,m)
enddo
!
print *,'original array after changes contains '
do j=1,10
  print '(10i6)',(data2(i,j),i=1,10)
enddo
end
Back to top
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Mon Dec 07, 2009 3:02 am    Post subject: Reply with quote

Ian,
I further changed the program to test both 2 dimension arrays and 1 dimension vectors. Based on the results, it may appear that the sub section is generated if the required array is not continuous in memory, as the 1 dimensional vector appears to change.
Code:
!create a module with interfaces for subroutines where necessary
module all_data
integer*4 data1(10), data2(10,10)
end module all_data

module interfaces
INTERFACE
  SUBROUTINE SUB4(jdata, idata)
    INTEGER jdata(:), idata(:,:)
  END SUBROUTINE
END INTERFACE
end module interfaces

! add this statement wherever one of these subroutine is to be called
use all_data
use interfaces

! create the test data
  integer*4 i,j
!
  do i=1,10
    data1(i) = i
    do j=1,10
      data2(i,j) = i*1000 + j
    enddo   
  enddo

!  check the data content
  print *,'before call main 10x10 array contains '
  do j=1,10
    print '(10i6)',(data2(i,j),i=1,10)
  enddo

! call the subroutine
  call sub4 ( data1(3:6), data2(3:6,2:8) )

! show the changes
  print *,'original 10x10 array after return from sub4 contains '
  do j=1,10
    print '(10i6)',(data2(i,j),i=1,10)
  enddo

  print *,'original vector data1 after return from sub4 contains '
  print '(10i6)',(data1(i),i=1,10)

end

subroutine sub4 (jdata, idata)
use all_data
! use blank place holders to show passed array is rank 2
  integer*4 jdata(:), idata(:,:),i,j,m,n
!
  m=size (idata,1)
  n=size (idata,2)
  print *,'array idata dimensions are',m,n
  print *,'passed array contains '
  do j=1,n
    print '(10i6)',(idata(i,j),i=1,m)
! make some changes
    do i=1,m
      idata(i,j) = -idata(i,j)
    enddo
  enddo
!
  print *,'passed array after changes contains '
  do j=1,n
    print '(10i6)',(idata(i,j),i=1,m)
  enddo
!
  print *,'original 10x10 array after changes contains '
  do j=1,10
    print '(10i6)',(data2(i,j),i=1,10)
  enddo
!
  m=size (jdata)
  print *,'vector jdata dimension is',m
  print *,'passed vector contains '
  print '(10i6)',(jdata(i),i=1,m)
! make some changes to vector
  do i=1,m
    jdata(i) = -jdata(i)
  end do
!
  print *,'passed vector after changes contains '
  print '(10i6)',(jdata(i),i=1,m)
!
  print *,'original vector after changes contains '
  print '(10i6)',(data1(i),i=1,10)
  print *,'NOTE ORIGINAL VECTOR HAS CHANGED, SO NO TEMPORARY VECTOR !!'
!
end

So my past experience with inefficiencies associated with sections of the form "data1(i1:i2)" are not due to temporary arrays.

John

ps : I also tried this program in SDBG, but got the asembler code window, rather than the source code to display. Don't know why. Linked with "ftn95 ian.f95 /check /link". I still can't drive SDBG !!
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 1, 2, 3  Next
Page 1 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