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

时间:2011-12-19 04:31:47

标签: multidimensional-array fortran dynamic-memory-allocation

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

好的,我说我有一个阵列:

real, allocatable :: A(:,:,:)

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

E.g。

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)会返回什么?那会很有趣。

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

allocate(A(3,n,n**2))

即使我现在并不努力记忆,我也希望有良好的编程习惯。无论如何,这是一个有趣的问题。

谢谢。

编辑:

维度的大小取决于另一维度中元素的怎么样?

在下面的答案中,两个维度中数组的大小取决于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

你理解我的意思?但是当程序试图分配已经分配的变量时,程序就会失败,例如:当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)

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

2 个答案:

答案 0 :(得分: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

这种方法允许数组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

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

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

       1           1           1
       2           2           4
       3           3           9
       4           4          16
       5           5          25

答案 1 :(得分:1)

我认为你可以通过分配/解除分配数组

来做到这一点
Program test
    Implicit none
    Real, dimension(:,:,:), allocatable :: A
    Integer  :: i,N
    Write(*,*)"Enter N"; Read(*,*)N
    Do i = 1, N
    if(Allocated(A)) then 
    deallocate(A);Allocate(A(i,i,i*i))
    else
    allocate(A(i,i,i*i))
    end if
    Write(*,*)Shape(A)
    End do
end program test

使用gfortran编译程序给出:

 Enter N
5
           1           1           1
           2           2           4
           3           3           9
           4           4          16
           5           5          25