Re: array referencing

Re: array referencing

I think the only way (I wish I was wrong) to obtain a run-time equivalence is using Cray pointers. It's relatively easy for 3-d and 1-d arrays:

REAL, ALLOCATABLE:: a3(:,:,:) 
REAL:: a1(*); POINTER(pa1, a1) 

However, your exact sample for 3-d and 2-d arrays is still tougher to realize;
if the leading dimension of both is known at compile-time, you might write:
REAL:: a2(5000,*); POINTER(pa2, a2)
. Otherwise... I don't know.

Perhaps the cleanest way is to simply use 2-d array and to access it using varying second index when you need to "emulate" 3-d, i.e (a2(i, iStride*j+k)) where


3 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
! Shows how possibly standard-conforming code can point to
! a rank-1 array with a rank-2 pointer.
! Also has potentially dangerous code segment not in
! original posting.
! Posted to thread "Sparse matrix subblocks"
! 2001-09-10 12:52:12 PST

! main.f90 -- Contains the compiler-visible part of the code.

module block_mod
implicit none
type block_type
real, pointer :: array(:,:)
end type block_type
end module block_mod

module special_interfaces
use block_mod
implicit none
subroutine set_pointer(q)
implicit none

real, pointer :: q(:,:)
end subroutine set_pointer

subroutine serialize(block, x)
use block_mod
implicit none
type(block_type) block(:)
real, target :: x(:)

end subroutine serialize
end interface

external get_pointer
end module special_interfaces

program main
use block_mod
use special_interfaces
implicit none
type(block_type), allocatable :: block(:)
real, allocatable, target :: array(:)
integer N
integer i, j, k
character(80) fmt
logical, allocatable :: test(:)
real x1, x2
real, pointer :: p

N = 2
write(fmt,'(a,i0,a,i0,a,i0,a)') '(',N,'L3,2x,',N,'F6.1,2X',N,'F6.1)'
do k = 1, N
call get_pointer(array((k-1)*N**2+1), N)
call set_pointer(block(k)%array)
end do
array = (/(i,i=1,size(array))/)
call serialize(block, array)
do k = 1, N
write(*,'(a,i1,a,i0,a,i0,a)') repeat(' ',(3*N-5)/2)//'Assoc'// &
repeat(' ',9*N/2-4)//'Block(',k,')'//repeat(' ',6*N-8)// &
do i = 1, N
! write(*,fmt) (associated(block(k)%array(i,j), &
! array((k-1)*N**2+i+N*(j-1))), j = 1, N), &
! (block(k)%array(i,j), j = 1, N), &
! (array((k-1)*N**2+i+N*(j-1)), j = 1, N)
do j = 1, N
p => block(k)%array(i,j)
test(j) = associated(p, array((k-1)*N**2+i+N*(j-1)))
end do
write(*,fmt) (test(j), j = 1, N), &
(block(k)%array(i,j), j = 1, N), &
(array((k-1)*N**2+i+N*(j-1)), j = 1, N)
end do
end do
write(fmt,'(a,i0,a)') '(a,',N**3,'(f0.1:1x))'
write(*,fmt) 'array = ', array
array(7) = -1
x1 = array(7)
x2 = block(2)%array(1,2)
array = 42
write(*,'(/a,f0.1,a,f0.1/)') 'x1 = ', x1, '; x2 = ', x2
write(*,fmt) 'array = ', array
end program main
! Last line of main.f90

! separate.f90 -- Contains subroutines to map pointers
! to different ranks. Compile separately so the compiler
! has to generate its most general interfacing code.

module separate_temp
implicit none
real, pointer :: p(:,:)
end module separate_temp

subroutine get_pointer(x,n)
use separate_temp
implicit none
integer, intent(in) :: n
real, target :: x(n,n)

end subroutine get_pointer

subroutine set_pointer(q)
use separate_temp
implicit none

real, pointer :: q(:,:)
end subroutine set_pointer

subroutine serialize(block, x)
use block_mod

Only a little bit of the last subroutine was chopped (light a fire under their butts, Steve.) Here it is:

subroutine serialize(block, x) 
   use block_mod 
   implicit none 
   type(block_type) block(:) 
   real, target :: x(:) 
! Empty subroutine 
end subroutine serialize 
! Last line of separate.f90 

So, perhaps rather surprisingly, you didn't miss much. The idea of my program is that when, in Fortran, you pass an array element as an actual argument to a subroutine with an implicit interface that is invisible to the compiler, a reference to the array element pretty much has to be passed in order for sequence association to work like it has since 1960 or earlier. In the called subroutine, if the array element actual argument is explicitly dimensioned as an array dummy argument, the callee is actually looking at an array consisting of all the elements of the original array from the actual argument element to the end. It can, in the callee, be declared of any rank, and of course it can be a TARGET, so you can point a POINTER at it in the callee. On return, the standard considers it processor-dependent as to whether the POINTER you pointed at it has defined association status or not -- I'm not sure whether anybody at Compaq has even thought about whether this should be the case for their 'processor'. Thus I played a few tricks to keep the compiler in the dark about what I am doing (via separate compilation) and included the serialize subroutine that forces the compiler to reload all elements of the two arrays from memory because for all it knows they may have been changed by it (although, as you can see, the subroutine does nothing, but the comiler doesn't know that!)

I can't compose an example specific to your case because I don't know what the mapping between the two arrays has to be: for example the first dimension of a2 could be split into two dimensions in a3, or the second could be, or something even more complex could be in the offing.

Well, a student is begging me for help and since she's better looking than you I have to sign off now...

Leave a Comment

Please sign in to add a comment. Not a member? Join today