Discussion:
A question on reallocation
(too old to reply)
GianLuigi Piacentini
2023-11-15 18:40:00 UTC
Permalink
Hi all,

I have a perhaps silly question, that puzzles me before committing to
write actual code.

Please consider a data structure which is basically an array of arrays
type element
integer, allocatable :: element_core(:)
end type
...
type(elements), allocatable :: array_of_elements(:)
...
allocate ( array_of_elements(some_size) )

(this is not a matrix, each element may significantly differ in size,
and someone may be long (and subjected to reallocation cycles, but his
is plain reallocation).

Now I have to increase size of previously allocated array_of_elements,
using the usual pattern (at least I think it's usual)

type(elements), allocatable :: tmp(:)

allocate ( tmp(new_size) )
tmp(1:some_size) = array_of_elements ! ***
call move_alloc(from = tmp, to = array_of_elements)

Seems to me that during the operation marked with the *** comment the
various elements are also copied, and this seems vasteful.
Is there a way to avoid such copying, if it really happens ?

Perhaps making array_of_elements an array of pointers to allocated
elements ?

Thanks in advance
Gigi Piacentini
gah4
2023-11-16 04:19:01 UTC
Permalink
Post by GianLuigi Piacentini
Hi all,
I have a perhaps silly question, that puzzles me before committing to
write actual code.
Please consider a data structure which is basically an array of arrays
type element
  integer, allocatable :: element_core(:)
end type
...
type(elements), allocatable :: array_of_elements(:)
...
allocate ( array_of_elements(some_size) )
(snip)
Post by GianLuigi Piacentini
type(elements), allocatable :: tmp(:)
allocate ( tmp(new_size) )
tmp(1:some_size) = array_of_elements                   ! ***
call  move_alloc(from = tmp, to = array_of_elements)
I think you want something like:

allocate(tmp(new_size))

do i=1, old_size
call move_alloc(from=array_of_elements(i), to=tmp(i))
end do

call move_alloc(from = tmp, to = array_of_elements)

So, move all the subarrays over, then move the array of arrays.

Since only the, fairly small, array_of_elements is being reallocated,
it should be pretty fast.

Before move_alloc, you had to create a temporary, copy them over,
reallocate the original one, and copy them back. Lots of copying!
m_b_metcalf
2023-11-18 09:29:31 UTC
Permalink
GianLuigi,

Does this do what you wanted?

Mike

P.S. This is also for me a trial posting using nemoweb.

type elements
integer, allocatable :: element_core(:)
end type

type(elements), allocatable :: array_of_elements(:)

type(elements), allocatable :: tmp(:)

allocate ( array_of_elements(3) )

allocate(array_of_elements(3)%element_core(3))

array_of_elements(3)%element_core(3) = 3


allocate ( tmp(4) )

call move_alloc(from=array_of_elements(1:3), to=tmp(1:3)) !<------

call move_alloc(from = tmp, to = array_of_elements)
print*, array_of_elements(3)%element_core(3)
end
GianLuigi Piacentini
2023-11-20 00:10:41 UTC
Permalink
Post by GianLuigi Piacentini
Hi all,
I have a perhaps silly question, that puzzles me before committing to
write actual code.
Please consider a data structure which is basically an array of arrays
type element
  integer, allocatable :: element_core(:)
end type
...
type(elements), allocatable :: array_of_elements(:)
...
allocate ( array_of_elements(some_size) )
(this is not a matrix, each element may significantly differ in size,
and someone may be long (and subjected to reallocation cycles, but his
is plain reallocation).
Now I have to increase size of previously allocated array_of_elements,
using the usual pattern (at least I think it's usual)
type(elements), allocatable :: tmp(:)
allocate ( tmp(new_size) )
tmp(1:some_size) = array_of_elements                   ! ***
call  move_alloc(from = tmp, to = array_of_elements)
Seems to me that during the operation marked with the *** comment the
various elements are also copied, and this seems vasteful.
Is there a way to avoid such copying, if it really happens ?
Perhaps making array_of_elements an array of pointers to allocated
elements ?
Thanks in advance
Gigi Piacentini
Thanks to all replier.

I ewconsidered the problem in light of the whole project, coming with 2
possible solutions:

1) since data come from analysis of several files, which do not change
during program execution, I can do a 1st pass counting dimensions, then
allocate, then do a 2nd pass reading data into the data structure.

2) as suggested, I could do
type element
integer, allocatable :: element_core(:) ! an array of integers
end type
type element_pointer
type(element), pointer :: e_p => null() ! pointer to the above
end type element_pointer

type(element_pointer), allocatable :: array_of_elements(:)

allocate( array_of_elements(3) ) ! an array of 3 pointers
do i = 1, size(array_of_elements)
allocate (array_of_elements(i)%e_p%element_core(n))
! where n is the size required for the ith array of integers
end do
... ! loading integers

Now when reallocating

type(element_pointer), allocatable :: tmp(:)

allocate( tmp(new size for array of array of integers) )

! copying pointers:
tmp(1:size(array_of_elements))%e_p => array_of_elements%e_p
! during this copy, in my intention, the underlying element_cores will
not be moved
call move_alloc (from = tmp, to = array_of_elements)

However, at the moment I cannot test the above machinery, I will do it
as soon as I can restart my hobby project, which will happen in some days.
But I am still interested in the subject, and in your comments, if any.

Thanks
Gigi

Loading...