Fortran 如何避免包含`a(i)=b(i,c(i))``的显式循环?

Fortran 如何避免包含`a(i)=b(i,c(i))``的显式循环?,fortran,vectorization,Fortran,Vectorization,您可以将运行向量加法编码为do循环,使用符号:index或根本不使用index(在F95中)。我想这对编译器没有任何影响。不幸的是,我有一个嵌套语句,如: do i=1,n a(i)=b(i,c(i)) end do 当然a=b(c)是非法的。有没有摆脱显式do循环的想法 当然有可能。您可以使用EOSHIFT或CSSHIFT将适当的元素放入第一列,然后使用“重塑”提取第一列。但是它的效率很低,因为编译器可能会在数组的所有元素上移动,而不仅仅是大小(b,1)。这是我的例子,我很难理解 pro

您可以将运行向量加法编码为do循环,使用符号:index或根本不使用index(在F95中)。我想这对编译器没有任何影响。不幸的是,我有一个嵌套语句,如:

do i=1,n
  a(i)=b(i,c(i))
end do

当然
a=b(c)
是非法的。有没有摆脱显式do循环的想法

当然有可能。您可以使用EOSHIFT或CSSHIFT将适当的元素放入第一列,然后使用“重塑”提取第一列。但是它的效率很低,因为编译器可能会在数组的所有元素上移动,而不仅仅是大小(b,1)。这是我的例子,我很难理解

program permute
   implicit none
   integer, parameter :: N = 5
   dimension b(N,N)
   integer i
! Initialize matrix to arbitrary value
   character :: b = reshape([(achar(i+96),i=1,size(b))],shape(b),order=[2,1])
   character(30) fmt
   integer c(size(b,1))
! Output matrices
   character a(size(b,1)),z(size(b,1))
   write(fmt,'(*(g0))') '(a/(',size(b,2),'(a)))'
! Print out input matrix
   write(*,fmt) 'b =',transpose(b)
! A sample permutation
   c = [1,3,4,5,2]
   write(fmt,'(*(g0))') '(a/(',size(b,1),'(a)))'
! Matrix a will have the output we want to emulate
   do i = 1, size(b,1)
      a(i) = b(i,c(i))
   end do
   write(*,fmt) 'a =',a
! Matrix z gets its result as specified in text. Is it correct?
   z = reshape(eoshift(b,c-1,dim=2),shape(z))
   write(*,fmt) 'z =',z
end program permute

更新:仔细考虑之后,您实际上可以使用隐含的do数组构造函数(它不是显式的)。这就是

a = (/ (b(i,c(i)), i=1,SIZE(c)) /)

请参阅标准的第1部分

下面使用重塑和指针的原始答案

它可以不用循环完成,但它是。。。如果这是一种好的做法,那就很值得怀疑了

首先,您需要知道数组存储在中

这意味着在大小为
(/n,m/)
的数组中,元素
(i,j)
位于内存位置
i+n*(j-1)
。因此,您所需要做的就是重塑和提取,您可以通过以下方式完成:

  d = RESHAPE(b,(/ SIZE(b) /))                    ! reshape
  a = d((/ (i,i=1,SIZE(c)) /) + (c(:)-1)*SIZE(c)) ! extract
它不需要循环,但您必须分配多一点内存。除非你把你的方式侵入记忆。这可以通过指针来完成

  TYPEOFB, POINTER, DIMENSION(:) :: p
  p(1:SIZE(b)) => b(:,1)             ! just close your eyes
  a = p((/ (i,i=1,SIZE(c)) /) + (c(:)-1)*SIZE(c))
示例程序:

PROGRAM reshape
  IMPLICIT NONE
  !-- declaration of variables -----------------------------
  INTEGER, DIMENSION(4,3),TARGET :: b  !< target for pointer
  INTEGER, DIMENSION(4) :: c,a,a2
  INTEGER, DIMENSION(12) :: d
  INTEGER, DIMENSION(:), POINTER :: p  !< ugly pointer
  INTEGER :: i,j
  !-- setup of the test case ------------------------------
  c(1)=3; c(2)=2; c(3)=1; c(4)=2
  DO i=1,4
     DO j=1,3
        b(i,j) = i + 4*(j-1)
     END DO
  END DO
  !-- reshape and extract ---------------------------------
  d = RESHAPE(b,(/ SIZE(b) /))                    ! reshape
  a = d((/ (i,i=1,SIZE(c)) /) + (c(:)-1)*SIZE(c)) ! extract
  !-- ugly pointer hack -----------------------------------
  p(1:SIZE(b)) => b(:,1)             ! just close your eyes
  a2 = p((/ (i,i=1,SIZE(c)) /) + (c(:)-1)*SIZE(c))
  !-- print output ----------------------------------------
  DO i=1,4
     PRINT *, i, b(i,c(i)), a(i), a2(i)
  END DO
END PROGRAM reshape
 % ./a.out 
 1 9 9 9
 2 6 6 6
 3 3 3 3
 4 8 8 8

这可能会有所帮助,具体取决于
c
矩阵的设置方式:。我觉得循环很好。可读性很好。没有理由进行复杂的单线压缩。我改了标题。欢迎您调整它,但请让它描述实际问题,而不是一些广泛的主题。此外,我不确定
b
是什么。它是一个数组吗?它是一个函数吗?仅仅一行代码样本通常是不够的。所有变量都应该正确声明。你建议的向量赋值根本没有意义。类似于
a=diagonal(b(:,c))
(假设一个假设的内在函数提取对角线)。不管怎么说,
forall
可能会让您感到高兴。理论上,您可以在表达式内部使用隐含循环,而不是外部显式循环。但这只会让事情变得更丑陋。当然,你可以使用隐含循环,我在评论中已经提到过。不过,它并不比原始代码好多少,也肯定不是问题想要的“完全没有索引”。它只是将索引移动到其他地方。还有一些可能会使计算速度变慢。很酷,我因为是唯一一张写着回答问题的海报而被否决。
 % ./a.out 
 1 9 9 9
 2 6 6 6
 3 3 3 3
 4 8 8 8