Efficient way to pass different shaped arrays? 
Author Message
 Efficient way to pass different shaped arrays?

I'm attempting to use an array argument of a subroutine for two
different purposes. One, which works fine, has the caller declare an
identical explicit shape array. The other, shown below, has the caller
(A) passing a small number of reals in the same memory space.
Subroutine B knows, via other arguments not shown, which kind of array
argument is being received.

In subroutine A:

REAL, DIMENSION(3) :: array
CALL B(array)

SUBROUTINE B(array)
REAL, DIMENSION(28,0:10001), INTENT(INOUT) :: array

Under CVF6, this worked as expected, but using IVF9, the compiler flags
an error because the extent of 'array' as a dummy argument for B
exceeds the size of the real argument 'array' in A; presumably this is
an error because B could write memory beyond the size of 'array'
declared by the caller.

So, my question is, what is a simple and efficient way to pass in the
3-element array? I don't really want to create a huge 28x10002 array in
the caller, and for efficiency it would be better not to add another
argument (subroutine B gets called many times).



Mon, 15 Dec 2008 05:00:45 GMT  
 Efficient way to pass different shaped arrays?


Quote:
> I'm attempting to use an array argument of a subroutine for two
> different purposes. One, which works fine, has the caller declare an
> identical explicit shape array. The other, shown below, has the caller
> (A) passing a small number of reals in the same memory space.
> Subroutine B knows, via other arguments not shown, which kind of array
> argument is being received.

> In subroutine A:

> REAL, DIMENSION(3) :: array
> CALL B(array)

> SUBROUTINE B(array)
> REAL, DIMENSION(28,0:10001), INTENT(INOUT) :: array

> Under CVF6, this worked as expected, but using IVF9, the compiler flags
> an error because the extent of 'array' as a dummy argument for B
> exceeds the size of the real argument 'array' in A; presumably this is
> an error because B could write memory beyond the size of 'array'
> declared by the caller.

> So, my question is, what is a simple and efficient way to pass in the
> 3-element array? I don't really want to create a huge 28x10002 array in
> the caller, and for efficiency it would be better not to add another
> argument (subroutine B gets called many times).

Well, you could use an assumed-shape array. This would require an explicit
interface and also the ranks to be identical. Thus, it might look like:

REAL, DIMENSION(3,1) :: array   ! dummy second dimension
CALL B(array)

 SUBROUTINE B(array)     ! in a module or as an internal procedure
REAL, DIMENSION(:, 0:), INTENT(INOUT) :: array

You can use the lbound and ubound intrinsics to find out the actual bounds
at run time.

This looks like legacy code, so maybe a more extensive makeover would be
useful.

Does that help?

Mike Metcalf



Mon, 15 Dec 2008 06:16:11 GMT  
 Efficient way to pass different shaped arrays?

Quote:

>> Well, you could use an assumed-shape array. This would require an explicit
> interface and also the ranks to be identical. Thus, it might look like:

> REAL, DIMENSION(3,1) :: array   ! dummy second dimension
> CALL B(array)

>  SUBROUTINE B(array)     ! in a module or as an internal procedure
> REAL, DIMENSION(:, 0:), INTENT(INOUT) :: array

> You can use the lbound and ubound intrinsics to find out the actual bounds
> at run time.

Efficiency is paramount here, because B is called millions of times. So
I am reluctant to use any method which adds execution time. I guess
that for an assumed-shape array, the address computations are more
time-consuming, since the dimensions are not compile-time constants,
but run-time variables.

The bounds of the array are being passed as separate arguments now.



Mon, 15 Dec 2008 06:31:51 GMT  
 Efficient way to pass different shaped arrays?

Quote:

> Efficiency is paramount here, because B is called millions of times. So
> I am reluctant to use any method which adds execution time. I guess
> that for an assumed-shape array, the address computations are more
> time-consuming, since the dimensions are not compile-time constants,
> but run-time variables.

While that might be so, it sounds a lot like a guess. (The explicit use
of the word "guess" makes it easy for me to guess that.  :-)). If
efficiency is really paramount, I advise testing instead of guessing.
History is full of people making guesses about how to improve
performance and turning out to be very, very wrong. I've done it myself.
(In the distant past, I used to have explicit tests for zero values in
order to "save time" by branching around needless multiplications; I was
thinking of multiplications as the main measure of computational cost.
Of course, the test and branch killed my performance, effectively
costing far more than the multiplication would have).

I'm not saying that your guess is wrong. I'm just suggesting that you
get real data if it really matters. Many people here (myself included at
times) are prone to generalizations about performance issues, but that's
no substitute for testing. Best to do both. Make the guesses about what
ought to work well; but then test it.

--
Richard Maine                    | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle           |  -- Mark Twain



Mon, 15 Dec 2008 07:10:53 GMT  
 Efficient way to pass different shaped arrays?

Quote:

> I'm attempting to use an array argument of a subroutine for two
> different purposes. One, which works fine, has the caller declare an
> identical explicit shape array. The other, shown below, has the caller
> (A) passing a small number of reals in the same memory space.
> Subroutine B knows, via other arguments not shown, which kind of array
> argument is being received.
> In subroutine A:
> REAL, DIMENSION(3) :: array
> CALL B(array)
> SUBROUTINE B(array)
> REAL, DIMENSION(28,0:10001), INTENT(INOUT) :: array
> Under CVF6, this worked as expected, but using IVF9, the compiler flags
> an error because the extent of 'array' as a dummy argument for B
> exceeds the size of the real argument 'array' in A; presumably this is
> an error because B could write memory beyond the size of 'array'
> declared by the caller.

I am pretty sure passing a one dimensional array to a two dimensional
dummy is allowed, definitely the other way around is allowed.

The standard since F66 would be that the dimensions of the dummy
array (in the called routine) should be variables, either passed as
arguments or in COMMON.  I believe newer standards allow a subset of
expressions in subscripts.

Quote:
> So, my question is, what is a simple and efficient way to pass in the
> 3-element array? I don't really want to create a huge 28x10002 array in
> the caller, and for efficiency it would be better not to add another
> argument (subroutine B gets called many times).

You say that other arguments not shown make the distinction.
Standard back to F66, is if those arguments are the actual array
dimensions, where one should be 1 in the one dimensional case.

I believe since F77 the last subscript of the dummy array can be *,
indicating that the actual value isn't given, but the program is
still required to stay within bounds.  In your case, (28,0:*)
should allow an array dimensioned (28), not excessively large.

It might be possible to compute the actual array bounds.
Since fortran doesn't have a conditional operator, it might be that
you could use a trick I saw once in a discussion about how NOT to
write Fortran code.  Consider:

       DO 1 I=1,100
       DO 1 J=1,100
1     A(I,J)=(I/J)*(J/I)

It seems that someone actually used this to initialize an identity
matrix, with much more multiplication and division than needed.

If multiply and divide are allowed in dummy array dimensions, and I
don't actually know that they are, you might be able to use a similar
trick to compute the appropriate dimensions.  The rules for
specification expression are complicated enough that I won't go into
more detail.  If (28,0:*) doesn't work then I or someone else can figure
out what can actually be done.

-- glen



Mon, 15 Dec 2008 07:13:46 GMT  
 Efficient way to pass different shaped arrays?

(snip)

Quote:
> Efficiency is paramount here, because B is called millions of times. So
> I am reluctant to use any method which adds execution time. I guess
> that for an assumed-shape array, the address computations are more
> time-consuming, since the dimensions are not compile-time constants,
> but run-time variables.

For an assumed shape array the rank must match, but (3,0:0) isn't
that much more work.  For assumed size it is something like second
subscript times 28 plus first subscript plus some constant.

For assumed shape it has to do two multiplies, as the array could
be in non-contiguous storage, loading the multipliers from the
descriptor.  As Richard indicates, that may or may not make a big
difference.  If you make the first subscript constant and 32, it
might be able to use a shift instead of a multiply, but it will
also take somewhat more memory, and not as much of the array will
stay in the cache.  Most likely that doesn't help.

Quote:
> The bounds of the array are being passed as separate arguments now.

If the bounds are being passed, use either the passed bounds or
a * (or 0:*) for the second subscript.  With assumed size, even
without a constant first subscript you might still do a little
better than assumed shape.

Or keep it the first at 28 and pass a 28 element array.

I agree with Richard that the only way to be sure is to time it.

-- glen



Mon, 15 Dec 2008 08:28:52 GMT  
 Efficient way to pass different shaped arrays?


Quote:

> I am pretty sure passing a one dimensional array to a two dimensional
> dummy is allowed, definitely the other way around is allowed.

It is ("Fortran 95/2003 Explained", Section 20.3). What is not allowed, in
the case given, is to address the fourth and subsequent elements of 'array'.

Regards,

Mike Metcalf



Mon, 15 Dec 2008 08:38:42 GMT  
 Efficient way to pass different shaped arrays?

Quote:

> I'm attempting to use an array argument of a subroutine for two
> different purposes. One, which works fine, has the caller declare an
> identical explicit shape array. The other, shown below, has the caller
> (A) passing a small number of reals in the same memory space.
> Subroutine B knows, via other arguments not shown, which kind of array
> argument is being received.

> In subroutine A:

> REAL, DIMENSION(3) :: array
> CALL B(array)

> SUBROUTINE B(array)
> REAL, DIMENSION(28,0:10001), INTENT(INOUT) :: array

How about
   real, dimension(28,0:*), intent(inout) :: array

You'll have to do the right thing with the array, but I
think the subscripting might be legal.  Unfortunately, I've
got to leave the office and can't think now.

Dick Hendrickson

Quote:

> Under CVF6, this worked as expected, but using IVF9, the compiler flags
> an error because the extent of 'array' as a dummy argument for B
> exceeds the size of the real argument 'array' in A; presumably this is
> an error because B could write memory beyond the size of 'array'
> declared by the caller.

> So, my question is, what is a simple and efficient way to pass in the
> 3-element array? I don't really want to create a huge 28x10002 array in
> the caller, and for efficiency it would be better not to add another
> argument (subroutine B gets called many times).



Mon, 15 Dec 2008 22:51:56 GMT  
 Efficient way to pass different shaped arrays?


Quote:

>> SUBROUTINE B(array)
>> REAL, DIMENSION(28,0:10001), INTENT(INOUT) :: array
...
>Since Fortran doesn't have a conditional operator, it might be that
>you could use a trick I saw once in a discussion about how NOT to
>write Fortran code.  Consider:

>       DO 1 I=1,100
>       DO 1 J=1,100
>1     A(I,J)=(I/J)*(J/I)

Peter's INTENT(INOUT) shows that he isn't restricted to f77. In f95
I admit MERGE is not an operator, but it is a conditional function
useful for things like Glen's. Also, FORALL saves 2 lines, allowing

       FORALL(I=1:100,J=1:100) A(I,J) = MERGE(1.0, 0.0, I==J)

-- John Harper, School of Mathematics, Statistics and Computer Science,
Victoria University, PO Box 600, Wellington 6140, New Zealand



Tue, 16 Dec 2008 06:24:22 GMT  
 Efficient way to pass different shaped arrays?

(snip)

Quote:
>        FORALL(I=1:100,J=1:100) A(I,J) = MERGE(1.0, 0.0, I==J)

OK, but can you do something like:

SUBROUTINE B(array,X)
LOGICAL X
REAL, DIMENSION(MERGE(3,28,X),0:MERGE(0,10001,X)),INTENT(INOUT)::array
to select the appropriate dimensions?

My previous suggestion would look something like

SUBROUTINE B(array,X)
INTEGER X
REAL, DIMENSION(3+25*(1/X),0:10001*(1/X)),INTENT(INOUT)::array

where X is either 1 or greater than 1 to select between (28,0:10001)
and (3,0:0).

I would say both are pretty ugly, though.

-- glen



Tue, 16 Dec 2008 07:06:39 GMT  
 Efficient way to pass different shaped arrays?


Quote:

>(snip)
>>        FORALL(I=1:100,J=1:100) A(I,J) = MERGE(1.0, 0.0, I==J)

>OK, but can you do something like:

>SUBROUTINE B(array,X)
>LOGICAL X
>REAL, DIMENSION(MERGE(3,28,X),0:MERGE(0,10001,X)),INTENT(INOUT)::array
>to select the appropriate dimensions?

>(snip)>
>I would say both [that and another suggestion] are pretty ugly, though.

True! IMHO that use of MERGE is an extension to f95 that's OK in
f2003. BTW, both g95 -std=f95 and Sun f95 -ansi allow it, printing
 T 666. 666. 666.
with this program:

REAL:: d(3,0:0) = 333.0
CALL B(d,.TRUE.)
END
SUBROUTINE B(array,X)
  LOGICAL X
  REAL,INTENT(INOUT)::array(MERGE(3,28,X),0:MERGE(0,10001,X))
  array = 2*array
  PRINT "(L2,(3F5.0))",X,array
END SUBROUTINE B

Presumably Andy and Sun don't want to spend time implementing something
they'd just have to take out again from their f2003 compilers.

-- John Harper, School of Mathematics, Statistics and Computer Science,
Victoria University, PO Box 600, Wellington 6140, New Zealand



Tue, 16 Dec 2008 11:12:42 GMT  
 
 [ 11 post ] 

 Relevant Pages 

1. Efficient ways to pass arrays, contd.

2. Object3D.Shape - ways to access/control multiple shapes?

3. passing assumed-shape arrays from C or C++ programs

4. Passing allocatable arrays as a assumed shape argument?

5. An efficient way to pass 3-D arrays to functions

6. Efficient way of passing arrays

7. Passing arrays of different types

8. building efficient shapes

9. array shape analysis for array languages

10. BUTTONS--Graphic--different shapes and sizes

11. same shape different color

12. NEWBIE TIP: Reading a file two different ways...from ENGSOL

 

 
Powered by phpBB® Forum Software