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
循环,每个循环 运行 在 MinIndex
和 MaxIndex
。因为你不知道尺寸,那是不可能的。
我能想到的最简单的策略是使用单个 DO
循环遍历所有一维索引。对它们每一个计算N维索引,检查是否在MinIndex
和MaxIndex
提供的边界内:如果是,继续做你需要的;如果不是,则丢弃该 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
我有一个 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
循环,每个循环 运行 在 MinIndex
和 MaxIndex
。因为你不知道尺寸,那是不可能的。
我能想到的最简单的策略是使用单个 DO
循环遍历所有一维索引。对它们每一个计算N维索引,检查是否在MinIndex
和MaxIndex
提供的边界内:如果是,继续做你需要的;如果不是,则丢弃该 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