分配具有相互依赖维度的动态数组 [英] Allocate dynamic array with interdependent dimensions

查看:199
本文介绍了分配具有相互依赖维度的动态数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



好的,假设我有一个数组:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆