[J3] Increasing the size of an array
Malcolm Cohen
malcolm at nag-j.co.jp
Tue Dec 14 06:13:51 UTC 2021
Hi folks,
BTW Van, I sent you some replies on your other message, but you won’t have seen them as they were blocked...
Anyway, to the topic at hand
Given
Class(t),Allocatable :: a(:)
And say we want to double its size,
With the first half being the existing value,
And we don’t care much about the rest (but the elements have to have some value),
a = Reshape(a, [ Size(a)*2 ], Pad=a)
works fine. If we want to, say, replicate a(1) into the extra elements instead,
a = Reshape(a, [ Size(a)*2 ], Pad=Spread(a(1),1,Size(a)))
works for that. No need for MOVE_ALLOC in either case, unless we want to have lower bounds other than one.
Admittedly there’s currently no way to do the polymorphic assignment without giving “all the extra” elements some valid value. But I don’t think that’s much of a problem – if you’re using allocatable components or default initialisation, the compiler would have to initialise them anyway, so having to provide a value to initialise them to doesn’t seem very onerous or expensive.
Cheers,
--
..............Malcolm Cohen, NAG Oxford/Tokyo.
From: J3 <j3-bounces at mailman.j3-fortran.org> On Behalf Of Van Snyder via J3
Sent: Saturday, December 11, 2021 9:52 AM
To: j3 <j3 at j3-fortran.org>
Cc: Van Snyder <van.snyder at sbcglobal.net>
Subject: [J3] Increasing the size of an array
One of the use cases for MOVE_ALLOC was increasing the size of an array. Something like this is frequently used:
subroutine Expand ( A, N )
! Make sure A has at least N elements, and double its size if not.
type(t), allocatable, intent(inout) :: A(:)
integer, intent(in) :: N
integer :: M
type(t), allocatable :: Temp(:)
if ( .not. allocated(A) ) then
allocate ( a(n) )
else if ( n > size(a) ) then
m = size(a)
allocate ( temp(max(n,2*m)) )
temp(1:m) = a
call move_alloc ( temp, a )
end if
end subroutine Expand
This doesn't work for polymorphic arrays because the LHS of the assignment -- temp(1:m) -- is not allocatable.
One solution is to provide a type-bound ASSIGNMENT ( = ) generic binding. That procedure has to assign component-by-component, or use SELECT TYPE. This is an ugly solution, not least because it's required in every extension.
One might believe that another solution is to use SOURCE=
allocate ( temp(max(n,2*m)), source = [ a(1:m), [ ( a(1), i = m+1, max(n,2*m) ) ] )
but this doesn't work because the dynamic type of the array constructor, without a type specifier, is the declared type of the items. If iit worked, assigning to a(m+1:2m) is pointless if they're going to get new values anyway. And it depends upon the previous size of A not being zero (if you have bounds checking turned on).
Another solution is to have a type-bound ALLOCATE subroutine for each extension that can provide a type specifier in the array constructor, and use that in the EXPAND subroutine instead of an ALLOCATE statement.
Another solution is to have a SELECT TYPE construct in the EXPAND subroutine, but that needs to be revised every time an extension type is added.
Another solution is to have a different type-bound EXPAND routine for every extension type.
Are there other less traumatic solutions?
One change to the standard that would be useful is to relax the requirement that a polymorphic variable in an intrinsic assignment be allocatable. This would require to define what happens if they have different dynamic types, essentially "only the smaller part of variable and expr is copied." An alternative is "if their dynamic types differ, an error condition exists." We don't have exceptions, so that's not a nice solution. Several years ago, I proposed to re use the ASSIGN keyword to provide a wrapper for assignment statements that could have STAT= and ERMSG= specifiers:
assign ( temp(1:m) = a, stat=myStat, ermsg=myMsg )
but that was greeted with laughter. Another is to relax the prohibition against both allocate-shape-spec-list and array source-expr appearing. If both appear, the allocate-shape-spec-list prevails. Require a section-subscript-list on SOURCE (not source-expr) that specifies which elements of the allocation get values from source-expr. The section-subscript-list would be required to specify a shape compatible with source-expr.
allocate ( temp((max(n,2*m)), source(1:m) = a )
This is more general, and more useful, than something like "if source-expr has fewer elements than the allocation, elements of source are assigned to elements of the allocation in array element order."
Disclaimer
The Numerical Algorithms Group Ltd is a company registered in England and Wales with company number 1249803. The registered office is: 30 St. Giles, Oxford, OX1 3LE, United Kingdom. Please see our <https://www.nag.co.uk/content/privacy-notice> Privacy Notice for information on how we process personal data and for details of how to stop or limit communications from us.
This e-mail has been scanned for all viruses and malware, and may have been automatically archived by Mimecast Ltd, an innovator in Software as a Service (SaaS) for business.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.j3-fortran.org/pipermail/j3/attachments/20211214/545fd918/attachment.htm>
More information about the J3
mailing list