Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29277 Discussions

Two dimension allocatable array with one dimension fixed

jim_dempsey
Beginner
2,039 Views

Two dimension array with one dimension fixed

I have an allocatable array of vectors. The index range of one of the dimensions is fixed at 3. The other is variable. The array is declared as:

real, pointer :: array( : ,: ) ! or real, allocatable if you wish

When I allocate an array of n vectors I use something like:

allocate(array(3,n))

So far so good.

The allocate in this manner is such that the three components of the vector are in adjacent memory. Supposedly for faster access.

The reason I say supposedly is that when I have optimizations enabled that the compiler cannot be certain as to the size of the extent of the first subscript. i.e. it cannot know it is always 3. The consequence of this is the compiler generates code to look at the in memory descriptor for the allocatable array. This causes unnecessary computations.

I know I can pass the array into a subroutine or function and then use a DIMENSION on the dummy argument. This adds additional overhead and requires I manufacture an additional subroutine.

Is there a way to define an allocatable array with one of the dimensions fixed?

Jim Dempsey

0 Kudos
7 Replies
Paul_Curtis
Valued Contributor I
2,039 Views
Code:
TYPE vector
    INTEGER, DIMENSION(3) :: val
END TYPE vector


ALLOCATE (vector(n))


0 Kudos
jim_dempsey
Beginner
2,039 Views

That would work for a new program, but for an old program with 100's of source files it will not work.

Reason being it requires changing statements like

Code:
        dest(1,n) = src(1,n)
to

        dest(n)%vec(1) = src(n)%vec(1)



The editscan be hidden with a #define macro
#define dest(i,,j) test(j)%vec(i)
And similar #defines for the other vector arrays.
I have about 35 such arrays and that is not too much editing considering I have about 700 source modules. The only remaining issue is the allocation. And that is done in one place.
What would be preferable is to have an attribute that declares a constant range for a particular index. DIMENSION does this, but not for allocatable arrays.
The other way do do this would be to have a null named array
! something like this
type vector
real :: (3)
end type
0 Kudos
jim_dempsey
Beginner
2,039 Views

Code:

type vector
real :: (3)
end type vector

type(vector), pointer :: foo(:)
...
allocate(foo(n))
val =foo(i,j) ! i is 1:3, j is 1:n



0 Kudos
emc-nyc
Beginner
2,039 Views
I've found this will work:




integer,dimension(:,:),allocatable :: two_d




integer,parameter :: fixed_dimension =


integer :: variable_dimension




variable_dimension =




allocate(two_d(fixed_dimension, variable_dimension))
0 Kudos
jim_dempsey
Beginner
2,039 Views
emc,
The problem is when the program consists of multiple source files and for example a module (xxx.MOD) file contains a pointer to the two or more dimensioned and allocatable array. (i.e. does not contain the allocate). Then the compiler has to generate code that is dimension ignorant.
Arrays contain a hidden internal structure which contain the size of each element, the location of the first element, the number of indicies and the extents of each indicy. If an array is declared as
real :: array(:,:)
And in a different program source file allocated to array(1:3,1:N)
And then referenced in a different program source file as array(I,J).
The compiler, when generating the above source file that references array(I,J) will not have sufficient information to know the range of the indices. It must figure out the range of the indicies by generating code that access the hidden array structure that contains the extents of each index. This code is larger than and more compute intensive than the code necessary to index the array when the compiloer knows the extents of the first dimension (3), the base of the first dimension (1) and the base of the second dimension (1).
Without this information the pseudo code is something like

address = ad.base + (( (ad.sub(1)%ub-ad.sub(1)%lb)+1) * (J-ad.sub(2)%lb) + I - ad.sub(1).lb))*ad.esz
where
address is used in the FORTRAN expression
ad is the hidden array descriptor
base is the base of the allocated array
sub is a member of ad and is an array of a 2 entry structure containing
lb lower bound
ub upper bound
esz is the element size
The compiler writer could elect to contain the extent of the indicies in the hidden array descriptor and to maintain a consistant element size (i.e. know that the element size is the sum of the members or the sum of the members rounded up to a fixed alignment size)
ad is the hidden array descriptor
base is the base of the allocated array
sub is a member of ad and is an array of a 2 entry structure containing
lb lower bound
ub upper bound
ex extent (ub-lb+1)
esz is the element size
Thus reducing the address computation to

address = ad.base + ((ad.sub(2).ex * (J-ad.sub(2)%lb) + I - ad.sub(1).lb))*4! e.g. 4 for REAL(4)
If, on the other hand, the compiler knows the array is of the format array(1:3,1:*)
then it knows everything except for the number of rows (*). The computation then becomes
address = ad.base + (3 * (J-1) + I - 1)*4
And as a further optimization perform the -1's by fudging the base address in the array descriptor to point at a location preceeding the actual base address and as if the array were 0 based indexed.
i.e. contains base-4-12 to account for "I-1", "J-1" (which is *3*4'd)
The new reduced address expression is now

address = ad.base-16 + (3 * J + I)*4! if ad.base containes the actual base
or
address = ad.base + (3 * J + I)*4! if ad.base containes the fudged base

The code necessary to compute the address into the array is greatly simplified.
Note,
By passing the array as an argument into a subroutine, thus becomming a dummy argument for the subroutine, you can use a DIMENSION statement to supply the constants for the compiler to use.
call foo(array)
subroutine foo(a)
real :: a
dimension a(3,1:*)
... = .. + a(I,J)
In this case the compiler knows the bounds and can use the faster coding.

My original post requested if there were a way to declare the constant portions of an allocatable array.
Unfortunately you cannot use DIMENSION to redefine the characteristics of the array (for the compiler to use).
Thanks for your response though.
Jim Dempsey
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,039 Views
Jim,
I don't have an answer to your question (I think it's impossible apart from cludges you already discovered yourself). However, have you actually measured the difference in performance between fixed-dimension and unknown-dimension? I think there's a fairly big possibility that we're discussing a strawman here -- modern compilers are known for good handling of assumed-shape arrays, and sometimes they even outperform plain vanilla fixed-size/assumed-size ones. (I wouldn't bet it for pointers though, as more attention must be paid when processing them).

Jugoslav
0 Kudos
jim_dempsey
Beginner
2,039 Views

I have looked at the code and there is a noticeable amount of difference. A few percent. In a computational intensive situation a few percent is significant. In a program that runs 200 hours or more every little bit helps. I can work around the problem using dummy variables or using hacked in inline function/subroutines.

There are two opposing forces in effect here. The object model purest who would like to bury DIMENSION of dummy arguments (i.e. all calls must extract dimension info from the caller) and the pragmatist who is capable of telling the compiler what they want.

In most cases I can get around the problem by using a derived type and then allocate only one dimension. But then this requires what some would consider offensive,A #define statement to convert the double subscripted array references into a single subscripted arraywith member reference.

I do not mind inserting a kludge here and there. I do mind having to edit 100's of working modules and having to re-debug the edits due to the invariable editing mestake here and there.

Jim Dempsey

0 Kudos
Reply