Fortran重塑 - N维转置 [英] Fortran reshape - N-dimensional transpose

查看:354
本文介绍了Fortran重塑 - N维转置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Fortran中编写一些需要重新排序n维数组的代码。我认为重塑内在结合订单参数应该允许这样做,但是我遇到了困难。



考虑以下最简单的示例

 程序测试
隐式无
实数,维(:,:,:,:,:),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))!源数组
allocate(matB(n3,n2,n4,n1,n5))!重构数组

!填充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)!A的前导维是B
结束程序测试的第四维

我预计这会导致

  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)一个d找到相同的结果,所以很可能我只是误解了重塑如何工作。

任何人都可以告诉我哪里出错,我如何实现目标?

解决方案当在 reshape 中指定 order = 时,排列的下标顺序对应于源数组的元素。这可能不完全清楚。 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,依此类推。

所以,它是元素<:code> matB(1,1,1:3,1,1)对应于 matA(:,1,1,1,1) code>。



我已经明确了 matB 切片的范围,因为您已经形状为 matB 的问题:您希望 matB 的形状成为由 order = 说明符。



您可以将您的示例写为

 隐式无
整数,参数:: n1 = 3,n2 = 5,n3 = 7,n4 = 11,n5 = 13
整数matA(n1 ,n2,n3,n4,n5)
整数matB(n4,n2,n1,n3,n5)! (3 2 4 1 5)
整数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])


I'm trying to write some code in Fortran which requires the re-ordering of an n-dimensional array. I thought the reshape intrinsic combined with the order argument should allow this, however I'm running into difficulties.

Consider the following minimal example

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

I would expect this to result in

Ad1 : 1010111.00       1010112.00       1010113.00               3           5           7          11          13

Bd4 : 1010111.00       1010112.00       1010113.00               7           5          11           3          13

But instead I find:

Ad1 : 1010111.00       1010112.00       1010113.00               3           5           7          11          13

Bd4 : 1010111.00       1010442.00       1020123.00               7           5          11           3          13

I've tried this with gfortran (4.8.3 and 4.9) and ifort (11.0) and find the same results, so it's likely that I am simply misunderstanding something about how reshape works.

Can anybody shed any light on where I'm going wrong and how I can achieve my goal?

解决方案

When order= is specified in reshape the elements of the result taken with permuted subscript order correspond to the elements of the source array. That probably isn't entirely clear. The Fortran 2008 standard states this as (ignoring the part about pad=)

The elements of the result, taken in permuted subscript order ORDER (1), ..., ORDER (n), are those of SOURCE in normal array element order ..

What this means is that from your example with order=[3,2,4,1,5] there is the mapping to

matA(1,1,1,1,1), matA(2,1,1,1,1), matA(3,1,1,1,1), matA(1,2,1,1,1), ...

of

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

with offset changing most rapidly in the third index of matB corresponding to most rapidly varying in the first of matA. The next fastest varying in matB being dimension 2, then 4, and so on.

So, it's the elements matB(1,1,1:3,1,1) that correspond the matA(:,1,1,1,1).

I've been explicit in the extent of that matB slice because you've a problem with the shape of matB: you want the shape of matB to be the inverse of the permutation given by the order= specifier.

You could write your example as

  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

Alternatively, if it's the shape of matB that you want, then it's the order permutation that wants inverting:

  matB = reshape(matA, shape(matB), order = [4,2,1,3,5])

这篇关于Fortran重塑 - N维转置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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