multidimensional-array - Fortran reshape - N 维转置

标签 multidimensional-array fortran reshape transpose memory-layout

我正在尝试在 Fortran 中编写一些代码,这需要对 n 维数组进行重新排序。我以为 reshape内在结合 order论点应该允许这样做,但是我遇到了困难。

考虑以下最小示例

program test
    implicit none
    real, dimension(:,:,:,:,:), allocatable :: matA, matB
    integer, parameter :: n1=3, n2=5, n3=7, n4=11, n5=13
    integer :: i1, i2, i3, i4, i5

    allocate(matA(n1,n2,n3,n4,n5)) !Source array
    allocate(matB(n3,n2,n4,n1,n5)) !Reshaped array

    !Populate matA
    do i5=1, n5
       do i4=1, n4
          do i3=1, n3
             do i2=1, n2
                do i1=1, n1
                   matA(i1,i2,i3,i4,i5) = i1+i2*10+i3*100+i4*10000+i5*1000000
                enddo
             enddo
          enddo
       enddo
    enddo

    print*,"Ad1 : ",matA(:,1,1,1,1),shape(matA)
    matB = reshape(matA, shape(matB), order = [3,2,4,1,5])
    print*,"Bd4 : ",matB(1,1,1,:,1),shape(matB) !Leading dimension of A is the fourth dimension of B
end program test

我希望这会导致
Ad1 : 1010111.00       1010112.00       1010113.00               3           5           7          11          13

Bd4 : 1010111.00       1010112.00       1010113.00               7           5          11           3          13

但相反,我发现:
Ad1 : 1010111.00       1010112.00       1010113.00               3           5           7          11          13

Bd4 : 1010111.00       1010442.00       1020123.00               7           5          11           3          13

我用 gfortran 试过这个(4.8.3 和 4.9)和 ifort (11.0)并找到相同的结果,所以我很可能只是误解了 reshape 的工作原理。

任何人都可以阐明我哪里出错以及如何实现我的目标吗?

最佳答案

因为我也感受到了order的行为对于多维数组非常不直观,我在下面进行了一些代码比较以使情况更加清楚(除了已经完整的@francescalus'答案)。首先,在一个简单的例子中,reshape()有和没有order给出以下内容:

mat = reshape( [1,2,3,4,5,6,7,8], [2,4] )

=> [ 1  3  5  7  ;
     2  4  6  8  ]

mat = reshape( [1,2,3,4,5,6,7,8], [2,4], order=[2,1] )

=> [ 1  2  3  4  ;
     5  6  7  8  ]

这个例子表明没有 order元素以通常的列主要方式填充,而 order=[2,1]第二维运行得更快,因此元素按行填充。这里的关键点是 order指定 LHS 的哪个维度(而不是源数组)运行得更快(如上述答案中所强调的)。

现在我们将相同的机制应用于更高维的情况。一、reshape()没有 order 的 5 维数组的
matB = reshape( matA, [n3,n2,n4,n1,n5] )

对应于显式循环
k = 0
do i5 = 1, n5   !! (5)-th dimension of LHS
do i1 = 1, n1   !! (4)
do i4 = 1, n4   !! (3)
do i2 = 1, n2   !! (2)
do i3 = 1, n3   !! (1)-st dimension of LHS
    k = k + 1
    matB( i3, i2, i4, i1, i5 ) = matA_seq( k )
enddo;enddo;enddo;enddo;enddo

在哪里 matA_seqmatA 的顺序 View
real, pointer :: matA_seq(:)
matA_seq( 1 : n1*n2*n3*n4*n5 ) => matA(:,:,:,:,:)

现附上order=[3,2,4,1,5]reshape() ,
matB = reshape( matA, [n3,n2,n4,n1,n5], order = [3,2,4,1,5] )

然后改变 DO 循环的顺序,使得
k = 0
do i5 = 1, n5   !! (5)-th dim of LHS
do i3 = 1, n3   !! (1)
do i1 = 1, n1   !! (4)
do i2 = 1, n2   !! (2)
do i4 = 1, n4   !! (3)-rd dim of LHS
    k = k + 1
    matB( i3, i2, i4, i1, i5 ) = matA_seq( k )
enddo;enddo;enddo;enddo;enddo

这意味着 matB 的第三维(因此 i4 )运行速度最快(对应于上述答案中的第二行)。但是OP想要的是
k = 0
do i5 = 1, n5   !! (5)-th dim of LHS
do i4 = 1, n4   !! (3)
do i3 = 1, n3   !! (1)
do i2 = 1, n2   !! (2)
do i1 = 1, n1   !! (4)-th dim of LHS
    k = k + 1
    matB( i3, i2, i4, i1, i5 ) = matA_seq( k )
enddo;enddo;enddo;enddo;enddo

对应于
matB = reshape( matA, [n3,n2,n4,n1,n5], order = [4,2,1,3,5] )

即,francescalus 答案的最后一行。

希望这个比较能进一步澄清情况......

关于multidimensional-array - Fortran reshape - N 维转置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37442346/

相关文章:

php - 我怎样才能从这个数组中提取值?

c++ - 从 C++ 访问 Fortran 模块的变量

fortran - 使用 MPI-2 的 RMA 函数的 Fortran 程序中的段错误

Matlab audioread double 而不是单打

r - 如何通过R中的其他变量将一列分成多列

macros - 初始内容由函数确定的数组

c++ - 在 C/C++ 中分配给 int[][4]

c - C 中复制 3d 数组的函数?

fortran - 在 Fortran 90/95 中是否有检查 Infinite 和 NaN 的标准方法?

R:堆叠多打洞问题数据