使用相互依赖的维度分配动态数组

Sam*_*Tan 5 fortran multidimensional-array dynamic-memory-allocation

这有点复杂; 我欢迎任何关于如何提高问题清晰度的意见.

好吧,说我有一个数组:

real, allocatable :: A(:,:,:)
Run Code Online (Sandbox Code Playgroud)

我想在使用它之前分配它.第三维的大小是否可能取决于第二维的大小?

例如

do i=1,n
allocate(A(3,i,i**2))
end do
Run Code Online (Sandbox Code Playgroud)

显然以上都行不通.我想最终得到一个带有形状的数组(或一组数组)

(3,1,1), (3,2,4), (3,3,9), ... (3, n, n^2)
Run Code Online (Sandbox Code Playgroud)

其中第三维的大小是第二维的大小的平方.

我对依赖维度大小的规则有点复杂,但如果可以进行平方,我可以做其余的事情.

这可能吗?如果是这样,我如何在Fortran中实现它?

会有什么shape(A)回报?那会很有趣.

我的另一种选择是分配到所需的最大尺寸,并注意只在计算中使用某些元素,即

allocate(A(3,n,n**2))
Run Code Online (Sandbox Code Playgroud)

虽然我现在对记忆并不苛刻,但我希望有良好的编程习惯.无论如何,这是一个有趣的问题.

谢谢.

编辑:

如果维度的大小取决于另一维度中元素的

在下面的答案中,两个维度中数组的大小取决于B的索引.我想要的是某些东西

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
Run Code Online (Sandbox Code Playgroud)

你理解我的意思?但是当程序试图分配已经分配的变量时,例如当i=1它分配时,程序就会崩溃data(1)%cell(1),然后尝试分配data(1)%cell(2)...呃哦.我想要的是:

每个data(i)都有一个lev(j)值数组,j从1到n运行,对于每个lev(j)值,我们有一个cell大小为lev^ 2的值.请注意,这些cell的是为每一个独特data(i)和每个lev,而特定的大小cell取决于相应lev的值,并可能相应data(i)也.

我是否必须在派生类型中使用派生类型?

mil*_*cic 9

是的,您可以使用派生类型来完成此任务:

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
Run Code Online (Sandbox Code Playgroud)

该方法允许阵列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
Run Code Online (Sandbox Code Playgroud)

编辑:进一步回答OP的编辑问题.是的,看起来你需要做这样的事情,使用嵌套派生类型(比较你的代码示例来弄清楚你做错了什么):

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
Run Code Online (Sandbox Code Playgroud)

用gfortran 4.6.2尝试了这个.它产生预期的输出:

       1           1           1
       2           2           4
       3           3           9
       4           4          16
       5           5          25
Run Code Online (Sandbox Code Playgroud)

  • 它适用于我遇到的任何最近的gfortran(4.1.2完全过时). (5认同)