分配具有相互依赖维度的动态数组 [英] Allocate dynamic array with interdependent dimensions
问题描述
这有点复杂;我欢迎任何关于如何提高问题清晰度的意见。
好的,假设我有一个数组:
real,allocatable :: A(:,:,:)
,我想在分配它之前使用它。是否有可能第三维的大小取决于第二维的大小?
Eg
do i = 1,n
allocate(A(3,i,i ** 2))
end do
显然上述不起作用。我想最终得到一个具有形状的数组(或一组数组)。
(3, 1,1),(3,2,4),(3,3,9),...(3,n,n ^ 2)
其中第三维的大小是第二维的大小的平方。
我的尺寸规则的依赖维度是有点复杂,但如果可能的平方我可以做其余的。
这可能吗?如果是这样,我该如何在Fortran中实现它?
什么将 shape(A)
return?这很有趣。
我的另一种选择是分配到所需的最大尺寸,并且要小心只在计算中使用某些元素,即
allocate(A(3,n,n ** 2))
尽管目前我的记忆力并不强,但我希望有良好的编程习惯。这是一个有趣的问题。
谢谢。
编辑:
如何让维度的大小取决于另一维中元素的值?
在这两个维度下面的数组大小的答案取决于B的索引。我想要一些类似于
类型的行myarray
real :: coord(3)
整数,allocatable :: lev(:)
整数,allocatable :: cell(:)
endtype myarray
类型(myarray),allocatable :: data
allocate(data(m))
allocate(data%lev(n))
forall(j = 1:n)!现在简单,为了论点的缘故
lev(j)= j
endforall
!我正在考虑在这里使用FORALL循环,但错误返回
!建议编译器(gfortran)不要期望IF块和ALLOCATE
!语句在一个FORALL块中
do i = 1,m
do j = 1,n
allocate(data(i)%cell(lev(j)** 2))
enddo
enddo
你明白我的意思了吗?但是,当程序试图分配已经分配的变量时,程序就会失败。当 i = 1
时,它会分配 data(1)%cell(1)
,然后尝试分配 data(1)%cell(2)
...呃哦。我想要的是这样的:
$ b $ data(i)
有一个数组 lev (j)
值,其中 j
从1运行到n,并且对于每个 lev(j)
值,我们有一个 cell 大小
lev
^ 2。请注意,这些 cell 对于每个
数据(i)
和每个 lev
,并且该特定 cell
的大小取决于相应的 lev
值,并且可能相应的 data(i)
也是。
我必须在派生类型中使用派生类型吗?
是的,您可以使用派生类型完成此操作:
<$
REAL,DIMENSION(:,:,:),ALLOCATABLE :: A
ENDTYPE数组
$ INTEGER :: i
INTEGER,PARAMETER :: n = 10
TYPE(array),DIMENSION(:),ALLOCATABLE :: B
ALLOCATE(B(n))
$ b $ DO i = 1,n
ALLOCATE(B(i)%A(3,i,i * i))
WRITE(*,*)SHAPE(B(i) %A)
ENDDO
END
这种方法允许每个数组B的元素是一个不同形状的多维数组。
程序的输出如预期:
3 1 1
3 2 4
3 3 9
3 4 16
3 5 25
3 6 36
3 7 49
3 8 64
3 9 81
3 10 100
编辑:进一步回答OP的编辑问题。是的,你似乎需要做这样的事情,使用嵌套的派生类型(与你的代码示例比较,找出你做错了什么):
integer,parameter :: m = 3,n = 5
类型cellarray
整数,维(:),allocatable :: c
endtype cellarray
类型myarray
整数,allocatable :: lev(:)
类型(cellarray),维(:),allocatable :: cell
endtype myarray
type(myarray),dimension(:),allocatable :: B
allocate(B(m))
!分配和分配列表和单元格:
do i = 1,m
allocate(B(i)%lev(n))
allocate(B(i)%cell(n))
do j = 1,n
B(i)%lev(j)= j
enddo
enddo
!基于lev的值,分配B%cell c:
do i = 1,m
do j = 1,n
allocate(B(i)%cell(j)%c (B(i)%lev(j)** 2))
enddo
enddo
!打印出来检查它是否有效:
do j = 1,n
write(*,*)j,B(1)%lev(j),SIZE(B(1)%cell )%c)
enddo
end
gfortran 4.6.2。它产生了预期的产出:
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
This is a bit complicated; I'd welcome any comments on how to improve the clarity of the question.
Ok, say I have an array:
real, allocatable :: A(:,:,:)
and I want to allocate it before I use it. Is it possible for the size of third dimension to depend on the size of the second dimension?
E.g.
do i=1,n
allocate(A(3,i,i**2))
end do
Obviously the above doesn't work. I'd like to end up with an array (or a set of arrays) with the shape(s)
(3,1,1), (3,2,4), (3,3,9), ... (3, n, n^2)
where the size of the third dimension is the square of the size of the second dimension.
My rule for the size of the dependent dimension is a bit more complicated, but if squaring is possible I can do the rest.
Is this possible? If so, how might I implement it in Fortran?
What would shape(A)
return? That would be interesting.
My other alternative is to allocate to the maximum size required, and be careful to only use certain elements in calculations, i.e.
allocate(A(3,n,n**2))
Even though I'm not hard up on memory at the moment, I'd like to have good programming practices. This is an interesting problem anyway.
Thank you.
EDIT:
What about having the size of a dimension depend on the value of an element in another dimension?
In the answer below the size of array in both dimensions depended on the index of B. I'd like something along the lines of
type myarray
real :: coord(3)
integer,allocatable :: lev(:)
integer, allocatable :: cell(:)
endtype myarray
type(myarray), allocatable :: data
allocate(data(m))
allocate(data%lev(n))
forall (j=1:n) !simple now, for argument's sake
lev(j)=j
endforall
! I was thinking of using a FORALL loop here, but the errors returned
! suggested that the compiler (gfortran) didn't expect IF blocks and ALLOCATE
! statements in a FORALL block
do i=1,m
do j=1,n
allocate(data(i)%cell(lev(j)**2))
enddo
enddo
You get what I mean? But the program falls over as it tries to allocate already allocated variables, e.g. when i=1
it allocates data(1)%cell(1)
, and then tries to allocate data(1)%cell(2)
...uh oh. What I want is something like:
Each data(i)
has an array lev(j)
of values, with j
running from 1 to n, and for each lev(j)
value we have a cell
of size lev
^2. Note that these cell
's are unique for each data(i)
and each lev
, and that the size of that particular cell
depends on the corresponding lev
value, and possibly the corresponding data(i)
too.
Would I have to use a derived type within a derived type?
Yes, you can use a derived type to accomplish this:
TYPE array
REAL,DIMENSION(:,:,:),ALLOCATABLE :: A
ENDTYPE array
INTEGER :: i
INTEGER,PARAMETER :: n=10
TYPE(array),DIMENSION(:),ALLOCATABLE :: B
ALLOCATE(B(n))
DO i=1,n
ALLOCATE(B(i)%A(3,i,i*i))
WRITE(*,*)SHAPE(B(i)%A)
ENDDO
END
This approach allows each element of array B to be a multi-dimensional array of a different shape.
The output of the program is as expected:
3 1 1
3 2 4
3 3 9
3 4 16
3 5 25
3 6 36
3 7 49
3 8 64
3 9 81
3 10 100
EDIT: To further answer OP's edited question. Yes, it seems like you would need to do something like this, use nested derived type (compare to your code example to figure out what you did wrong):
integer,parameter :: m=3,n=5
type cellarray
integer,dimension(:),allocatable :: c
endtype cellarray
type myarray
integer,allocatable :: lev(:)
type(cellarray),dimension(:),allocatable :: cell
endtype myarray
type(myarray),dimension(:),allocatable :: B
allocate(B(m))
! Allocate and assign lev and cell:
do i=1,m
allocate(B(i)%lev(n))
allocate(B(i)%cell(n))
do j=1,n
B(i)%lev(j)=j
enddo
enddo
! Based on value of lev, allocate B%cell%c:
do i=1,m
do j=1,n
allocate(B(i)%cell(j)%c(B(i)%lev(j)**2))
enddo
enddo
! Print out to check that it works:
do j=1,n
write(*,*)j,B(1)%lev(j),SIZE(B(1)%cell(j)%c)
enddo
end
Tried this with gfortran 4.6.2. It produces expected output:
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
这篇关于分配具有相互依赖维度的动态数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!