Fortran重塑 - N维转置

时间:2016-05-25 16:01:10

标签: 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)尝试了这个并找到相同的结果,所以我可能只是误解了重塑的工作方式。

任何人都可以了解我出错的地方以及如何实现目标吗?

2 个答案:

答案 0 :(得分:3)

order=中指定reshape时,使用置换下标顺序获取的结果元素对应于源数组的元素。这可能并不完全清楚。 Fortran 2008标准将此声明为(忽略关于pad=)的部分

  

以置换下标顺序ORDER(1),...,ORDER(n)取得的结果元素是正常数组元素顺序中SOURCE的元素。

这意味着从order=[3,2,4,1,5]的示例中可以看到

的映射
matA(1,1,1,1,1), matA(2,1,1,1,1), matA(3,1,1,1,1), matA(1,2,1,1,1), ...

matB(1,1,1,1,1), matB(1,1,2,1,1), matB(1,1,3,1,1), matB(1,1,4,1,1), ...

偏移在matB的第三个索引中变化最快,对应于matA的第一个中最快速变化的变化。 matB中的下一个最快变化是维度2,然后是4,依此类推。

因此,与matB(1,1,1:3,1,1)对应的元素matA(:,1,1,1,1)

我已明确了matB切片的范围,因为您对matB的形状存在问题:您希望matB的形状为order= implicit none integer, parameter :: n1=3, n2=5, n3=7, n4=11, n5=13 integer matA(n1,n2,n3,n4,n5) integer matB(n4,n2,n1,n3,n5) ! Inverse of permutation (3 2 4 1 5) integer i1, i2, i3, i4, i5 forall (i1=1:n1, i2=1:n2, i3=1:n3, i4=1:n4, i5=1:n5) & matA(i1,i2,i3,i4,i5)=i1+i2*10+i3*100+i4*10000+i5*1000000 print*,"Ad1 : ",matA(:,1,1,1,1),shape(matA) matB = reshape(matA, shape(matB), order = [3,2,4,1,5]) print*,"Bd3 : ",matB(1,1,:,1,1),shape(matB) end 说明符给出的排列的倒数。

您可以将您的示例编写为

matB

或者,如果它是您想要的 matB = reshape(matA, shape(matB), order = [4,2,1,3,5]) 形状,那么它就是要反转的顺序排列:

order=

乍一看,查看与源尺寸有关的顺序可能是很自然的。但是,下面的内容可能会澄清:无论源的形状如何,重塑的结果都是相同的(使用的是自然顺序的数组元素); shape=值的大小等于[1,2,3,4,5,6]值的大小。对于第一个来源,如果来源是order=(回想一下我们如何构建rank-2数组),则[1]永远不会产生任何影响(它必须是select * from table1 where column1 < column2 )如果在源头上使用它。

答案 1 :(得分:2)

因为我也觉得order对于多维数组的行为非常不直观,所以我在下面进行了一些代码比较,以使情况更加清晰(除了已经完整的@ francescalus&#39;回答)。首先,在一个简单的例子中,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()

的5维数组的order
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

的顺序视图
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的最后一行&#39;答案。

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