I’m trying to find the most compact/clear way to reallocate an array to a different size, keeping both boilerplate and allocations to a minimum and am looking at SOURCEd allocation.
In the example, with gfortran:
if the new array is longer, all data is copied from a, and the trailing elements are not initialized (nice)
if the new array is shorter, sourcing it to a longer array leads to a segfault.
program compact_resize
implicit none
integer :: i,j
integer, allocatable :: a(:),longer(:),shorter(:)
a = [(i,i=1,10)]
print *, 'a=',a
! works
allocate(longer(20), source = a)
print *, 'b=',longer
! segfault
allocate(shorter(5), source = a)
print *, 'c=',shorter
end program compact_resize
Is what I’m doing violating any standards? the Intel documentation says " If object is an array, s-spec must appear and the number of s-specs must equal the rank of object, or source-expr must appear and have the same rank as object and the shape of object is that of source-expr". In other words, it seems like the option of BOTH specifying the size of the array and an array source-expr is not considered.
On Metcalf/Reid/Cohen it states that “if allocation is for an array, source-expr may be an array of the same rank, otherwise source-expr must be scalar”. also “because the bounds and shape of the allocated item are not taken from the source, making a clone of an array has to be done [by specifying its bounds]”, like
allocate(a(lbound(b,1):ubound(b,1)), source = b)
So apparently there’s a constraint on the rank, but not on their size, gfortran is doing it right, but of course it’s overflowing the copy when the new array is shorter than the former…
This program demonstrates an array constructor with an implied do loop and also reshape with pad to grow an array:
program main
implicit none
real, allocatable :: x(:), y(:), z(:)
integer :: i
x = [10.0, 20.0]
y = [x, (0.0,i=1,3)]
z = reshape(x, shape=[5], pad=[0.0])
print "(*(f4.1,1x))", y,z
end program main
! output: 10.0 20.0 0.0 0.0 0.0 10.0 20.0 0.0 0.0 0.0
I have tweeted about using move_alloc to do so more efficiently.
Nice alternatives, thank you both. So I’m guessing the best option is still the sourced allocation, but unfortunately, more bound checking lines will always be necessary like
Hi Federico, I was looking for how to resize an array, and I found this thread. At first I thought that using source was a neat solution, but then I started wondering: where will this memory go? Maybe at the beginning of the new array? At its end? Somewhere in the middle? I might be wrong, but this sounds like undefined behavior.
Then I found this StackOverlow answer, where the author says that it’s not allowed to have a source smaller than the new array.
Moving on, I checked the Intel documentation, where they only require that the two arrays have the same rank. And finally I checked the draft of Fortran 2023 standard, where in 9.7.1.1-3 it’s written that source-expr shall not depend on the bounds of any allocate-object in that statement.
I think it’s pretty clear that sourced allocation from a different-size array is non standard conforming. So, to achieve the one liner I was suggesting in the first place, @Beliavsky’s example is the way to go.
But I’m not sure about the overall safety/speed of this approach.
Unfortunately, the Fortran standard does not offer the much-desired flexibility with array resizing, refilling, rebinding, and rebinding + refilling (which by merging them, I call it rebilling). Frustrated with explaining user needs to the Fortran committee members (only to have the suggestions dismissed a day after with one stroke), a few years ago, we wrote four extensive multi-precision, multi-dimensional, fully generic modules specifically for the allocation tasks you described. These are:
This module contains procedures and generic interfaces for resizing allocatable arrays of various types, relocating their contents, and rebinding (re-indexing) their lower and upper bounds, and refilling the newly added elements.
This module contains procedures and generic interfaces for resizing allocatable arrays of various types, relocating their contents and rebinding (re-indexing) their lower and upper bounds.
This module contains procedures and generic interfaces for resizing allocatable arrays of various types, relocating their contents and filling the newly added elements with specific values.
This module contains procedures and generic interfaces for resizing allocatable arrays of various types and relocating their contents, without initializing or filling the newly added elements with specific values.
It’s hard to exaggerate how useful and time-saving these modules have been in subsequent developments. We paid careful attention to the design of interfaces to ensure flexibility and performance simultaneously. If you want to try the examples supplied with any of the above generic interfaces follow the QuickStart instructions here and the extra build flag exam to enable the example build and run for the specific module. For example,
./install.sh --exam pm_arrayResize
If you try any of the modules, we would appreciate your feedback and suggestions for improvement.
Just about everyone that has had to deal with Fortran allocatable arrays since F90 has wanted an intrinsic procedure to resize/reallocate and a dynamically varying array (like C++ vector classes) etc. Like most folks I ended up writing my own but they are limited to just my use cases and don’t cover the entire spectrum of potential use cases. I think that you have summed up the frustration of that many of us have with the Committee. We have legitimate needs that aren’t addressed by the current standard that potentially impacts the entire spectrum of Fortran users but the Committee appears to spend its time implementing things that experience has shown are only beneficial to a handful of users (even though the Committee appears to think otherwise). My personal opinion is that this “write it yourself” attitude is one of the major reasons people have migrated to other languages.
What is even more frustrating here is that implementing it both in the standard and in the compilers doesn’t look complicated: in my demo code, the C part that does the core of the job by manipulating the array descriptors is less than 100 lines. We could have the best of the Fortran arrays (multi-dimensions, arbitrary lower bounds…) and of the C++ vectors (resizeability…) at a little cost. It’s one or two orders below implementing a fully new type or a new data structure.
And anyway it can’t cover the the entire spectrum: resizing an allocatable array without moving the content is not possible at all with a standard-conforming code.
Yes. MOVE_ALLOC is a useful feature in the context of the current standard but if you want to keep the current contents of an array you are forced to use a temporary which can have a potential big impact on performance. People forget that one of the things that saved C++ and made it viable as a language for scientific computing is the introduction of expression templates that provided the compiler with more opportunities to optimize away some of the temporaries needed for things like operator overloading as well as a dynamic polymorphism etc. I read somewhere that a lot of the performance problems in the early days of C++ (more so than the OOP constructs) was due to the compiler creating a lot of temporaries when it tried to overload operators. I think an intrinsic facility for reallocation etc would also remove the need for the creation of temporaries you still have to use with MOVE_ALLOC. As I’ve stated in previous posts, if you don’t need save the contents of an array, the addition of an optional DEALLOCATE logical option to ALLOCATE that would tell the compiler to let ALLOCATE deallocate an existing array and resize it without throwing an error would go a long way to remove some of the frustration involved with just changing the size of an existing array. All current compilers will throw an error if you try to ALLOCATE an already allocated array without explicitly DEALLOCATEing it first.