Fortran DO 遍历通用索引集?

Fortran DO loop over generic set of indices?

我有一个 N 维数据集(比如实数),它存储为一个一维数组,带有一个额外的维度数组,它指定了原始维度。

此外,还给出了从 N 维索引推导出一维索引的函数,反之亦然。

我想弄清楚如何为通用 N 维索引(当然会转换为 1D 索引)从一组限制较低的索引到一组上指数。 所以我需要一个 "N-dimensional" 循环,它 不会遍历所有值 - 只是数组的一部分,因此做等效一维数组的线性索引是不相关的(至少没有修改)。

这是我的问题的示意图:

subroutine Test(Array,Dims,MinIndex,MaxIndex)

implicit none
real   , dimension(1:), intent(inout) :: Array
integer, dimension(1:), intent(in)    :: Dims,MinIndex,MaxIndex

integer, dimension(size(Dims)) :: CurrInd
integer :: 1Dindex

! size(Dims) can be 1, 2, 3 ,..., N
! size(MinIndex)==size(MaxIndex)==size(Dims)
! size(Array)==Product(Dims)
! 1Dindex=Get1dInd(NDindex,Dims)
! NDindex=GetNdInd(1Dindex,Dims)

! How do I actually preform this?
do CurrInd=MinIndex,MaxIndex
  1Dindex=Get1dInd(CurrInd,Dims)
  <Some operation>
enddo


end subroutine

我认为可以遍历 Dims 数组并使用内部循环,但我没能正确地写下这个过程。

另一个对我不起作用的选项(可能是因为我使用不当?)是 FORALL,因为它需要单独指定每个索引。

如果您在编译时知道数组的维度,您可以执行一系列嵌套的 DO 循环,每个循环 运行 在 MinIndexMaxIndex。因为你不知道尺寸,那是不可能的。

我能想到的最简单的策略是使用单个 DO 循环遍历所有一维索引。对它们每一个计算N维索引,检查是否在MinIndexMaxIndex提供的边界内:如果是,继续做你需要的;如果不是,则丢弃该 1D 索引并转到下一个。如果索引是连续的,您可以做一些更聪明的事情,跳过您知道自己不会感兴趣的索引块。

do OneDindex = 1, size(Array)
   CurrInd = GetNDInd(OneDindex, Dims)
   if ((any(CurrInd<MinIndex)) .or. (any(CurrInd>MaxIndex))) cycle
   ! <Some operation>
end do

请注意,就索引操作而言,此策略与并行化循环兼容。

另请注意,Fortran 变量必须以 字母开头1Dindex 不是有效的 Fortran 变量名。

这就是我最终完成的实际程序。 我已经验证过了,希望它对你有用,就像对我一样。 (我知道这没有得到很好的评论,但是这个问题包含了所有的细节而且我现在的时间非常短)

另外,感谢 ripero 的帮助! 我决定不使用 CYCLE 方法,因为我认为当只执行实际数量的循环时代码会更有效地工作。

  !-----------------------------------------------------------
  subroutine Test(Array,Rank,Dims,InitInd,FinInd)
    implicit none
    real,    dimension(1:), intent(inout) :: Array
    integer,                intent(in)    :: Rank
    integer, dimension(1:), intent(in)    :: Dims
    integer, dimension(1:), intent(in)    :: InitInd,FinInd
    !-----------------------------------------------------------    
    integer :: nOuter
    integer :: i,j, OneDInd
    integer, dimension(Rank) :: Curr
    !-----------------------------------------------------------

    ! Check how many repetition for the outer-loop
    Curr=FinInd-InitInd
    nOuter=1
    do i=2,Rank
       nOuter=nOuter*(Curr(i)+1)
    enddo

    !-----------------------------------------------------------
    ! Actual looping:
    Curr=InitInd
    do j=1,nOuter
       ! Update minor indices (>1):
       do i=1,Rank
          if (Curr(i).GT.FinInd(i)) then
             ! Update next index:
             Curr(i)=InitInd(i)
             Curr(i+1)=Curr(i+1)+1
          endif
       enddo

       ! Loop over major index:
       do i=InitInd(1),FinInd(1)
          !OneDInd=Get1dInd(Curr,Dims)
          !<operation>


          ! Advance major index:
          Curr(1)=Curr(1)+1
       enddo

    enddo

  end subroutine Test