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

Question regarding "-assume realloc_lhs"

victorht
Beginner
977 Views

Dear all,

Could I ask a question regarding resizing an allocatable array? Thank you very much for all your help!

Here is an example:

========================================================

[bash]        Module mod1
        
        type a
          integer, allocatable :: a1(:)
        end type a
        
        type(a), allocatable :: b(:)
                
        End Module mod1
        
        Program main
        
        Use mod1
        
        type(a) b1, b2

        allocate(b1%a1(2))
        allocate(b2%a1(2))

        do i = 1, 2
          b1%a1(i) = i
          b2%a1(i) = i + 20
        end do

        b = (/ b1 /)
        
        write(*,*) 'SIZE(b) = ', SIZE(b)

        write(*,*) 'b(1)%a1 = ', b(1)%a1

        b = (/ b, b2 /)
        
        write(*,*) 'SIZE(b) = ', SIZE(b)

        write(*,*) 'b(1)%a1 = ', b(1)%a1
        write(*,*) 'b(2)%a1 = ', b(2)%a1

        End
[/bash]


========================================================

I compile it with ifort 11.1:

ifort -g -assume realloc_lhs resize_array.f90

Here is the result:

========================================================

SIZE(b) = 1

b(1)%a1 = 1 2

SIZE(b) = 2

b(1)%a1 = 0 0

b(2)%a1 = 21 22

========================================================

b(1)%a1 should still be "1 2". I am not sure what I did wrong. Thanks a lot for your attention.

Best regards,

Victor

0 Kudos
8 Replies
Steven_L_Intel1
Employee
977 Views
This is a compiler bug described here. It is not yet fixed. The issue ID is DPD200166796. The developers are working to fix this but I don't expect the fix to appear until a future major version.
0 Kudos
victorht
Beginner
977 Views

Dear Steve,

Thank you very much for your so quick response!

We have a major project now to restructure a very old Fortran program. We need to be able to resize an allocatable array such that we can insert/remove an entry to/from an array. I am wondering do you have any suggestions for a workaround at this time?

Thank you again very much for your help!

Best regards,

Victor

0 Kudos
Steven_L_Intel1
Employee
977 Views
Yes - use a second temporary allocatable array to hold the new value and then call MOVE_ALLOC to "move" the value to the original array. This is effectively what you are doing with the original syntax and is just as fast. For example:

[fortran]       Module mod1
        
        type a
          integer, allocatable :: a1(:)
        end type a
        
        type(a), allocatable :: b(:)
                
        End Module mod1
        
        Program main
        
        Use mod1
        
        type(a) b1, b2
        type(a), allocatable :: btmp(:)
        allocate(b1%a1(2))
        allocate(b2%a1(2))

        do i = 1, 2
          b1%a1(i) = i
          b2%a1(i) = i + 20
        end do

        b = (/ b1 /)
        
        write(*,*) 'SIZE(b) = ', SIZE(b)

        write(*,*) 'b(1)%a1 = ', b(1)%a1

        btmp = (/ b, b2 /)

        call move_alloc (btmp, b)
        
        write(*,*) 'SIZE(b) = ', SIZE(b)

        write(*,*) 'b(1)%a1 = ', b(1)%a1
        write(*,*) 'b(2)%a1 = ', b(2)%a1

        End
[/fortran]
After the move_alloc, btmp is deallocated and the old storage associated with b is also deallocated. I'm not sure how you're removing items, but the same principle could be used assuming you're referencing a slice of b in the array constructor.
0 Kudos
victorht
Beginner
977 Views

Dear Steve,

Thank you so much for your kind help! This will help us a lot!

I am using the following statement to remove the m-th element from a SIZE-n array a:

atmp = (/(a(j),j=1,m-1), (a(j),j=m+1,n)/)

call move_alloc (atmp, a)

Thanks again very much!

Best regards,

Victor

0 Kudos
Steven_L_Intel1
Employee
977 Views
Yes, that will work, and the code is still standard F2003.
0 Kudos
victorht
Beginner
977 Views
Thank you again very much, Steve!

Best regards,
Victor
0 Kudos
Hirchert__Kurt_W
New Contributor II
977 Views
Steve already hit the high points about MOVE_ALLOC, but I will offer some other small suggestions:

1. The readability of

atmp = (/(a(j),j=1,m-1), (a(j),j=m+1,n)/)

might be improved by writing it as

atmp = [a(1:m-1),a(m+1:n)]

2. On the other hand, the nominal semantics of this statement is to first create the constructor value, and then allocate atmp and copy the values from the constructor to atmp. If the generated code actually does that, each value is first copied to the compiler temp holding the constructor value and then copied a second time to atmp. Optimizing compilers should be clever enough to avoid this double copying, but I don't like to depend on compilers being clever, so I would choose to explicitly copy values directly from a to atmp:

allocate(atmp(n-1))
atmp(1:m-1)=a(1:m_1)
atmp(m:n-1)=a(m+1:n)

Because the allocate is explicit here, this does not require "-assume realloc_lhs", and it will work in some cases where the standard does not provide for automatic allocation (e.g., when intrinsic assignment has been overridden by a user-defined assignment procedure). I suspect it is also more readable in cases where you are doing reallocation of an array with more than one dimension (because the constructors for multi-dimensional arrays tend to be very messy).

3. Finally, I would choose to write the call to MOVE_ALLOC using keyword argument association:

call move_alloc(from=atmp, to=a)

Even though I am the person who actually proposed MOVE_ALLOC to J3 during the development of F2003, I can never remember (without looking at the documentation) whether the source array or the destination array comes first in the argument list. I suspect others might have the same problem. Rather than making them consult the documentation when trying to understand this statement, I would would use the keywords to make the statement self-documenting on this point.


With the Intel compiler, it is quite likely that none of the above suggestions have any noticeable effect on the speed of compilation or the speed of the running code, so these are really just a matter of style. You will have to decide for yourself whether any of these are an improvement in things like the readability of your code, the maintainability of your code, or the ease with which your code can be transported to a new platform.

-Kurt
0 Kudos
victorht
Beginner
977 Views

Dear Kurt,

Thank you very much for your valuable suggestions!

I totally agree with your points 1 and 3. For your point 2, using atmp is only a temporary solution (until the bug is fixed) and it will be eventually replaced by

a = [a(1:m-1),a(m+1:n)]

Thanks again for your help!

Best regards,

Victor

0 Kudos
Reply