如何简化复杂的嵌套 do 循环?
How to simplify complex nested do-loops?
我有一项非常繁琐的任务来优化一些古老的 Fortran77 代码。老实说,我根本不懂fortran。我知道循环是如何工作的以及如何乘以矩阵。我也知道这个循环可以优化为几个 3-4 嵌套循环:
do i = 1, nocca
do j = 1, nocca
do k = 1, noccb
do l = 1, noccc
do m = 1, nva
do n =1, nvb
saps = oab(j, n+noccb)
sbap = oab(j, k)
sac = oac(i, l)
scr = oac(m + nocca, l)
im = i + nocca*(m-1)
kn = k + noccb*(n-1)
imkn = im + oava*(kn-1)
vrsab = ovovab(imkn)
demp3 = demp3 + 2.0d0*vrsab*(2.0d0*saps*sbap*sac*scr)
end do
end do
end do
end do
end do
end do
我试图在单独的循环中计算 sapssac,类似地 sacscr:
c Calculate saps * sbap
do j = 1, nocca
do k = 1, noccb
do n = 1, nvb
saps = oab(j, n + noccb)
sbap = oab(j, k)
saps_sbap(j, k) = saps_sbap(j, k) + saps*sbap
end do
end do
end do
c Calculate sac_scr
do i = 1, nocca
do l = 1, noccc
do m = 1, nva
sac = oac(i, l)
scr = oac(m + nocca, l)
sac_scr(i, l) = sac_scr(i, l) + sac*scr
end do
end do
end do
最后我想写最后一部分来计算 demp3 但有 5 个索引而不是我预期的 4。也许我这样做完全错了?
有什么建议吗?提示?
提前致谢!
显然比试图理解一个问题更容易记下来。我自己找到了最佳解决方案。这是:
将大金额分成两部分。我们只考虑第一个:
demp3 = demp3 + 2.0d0*vrsab*(2.0d0*saps*sbap*sac*scr)
在两个单独的循环中乘以 sapssbap 和 sacscr。 (维度可以作为原始循环中的最大索引找到):
REAL*16, DIMENSION(nvb, noccb) :: saps_sbap
REAL*16, DIMENSION(nocca, nva) :: sac_scr
以下循环乘以 sapssbap 和 sacscr:
c Calculate saps * sbap
do k = 1, noccb
do n = 1, nvb
saps_sbap(n, k) = 0.0d0
do j = 1, nocca
saps = oab(j, n + noccb)
sbap = oab(j, k)
saps_sbap(n, k) = saps_sbap(n, k) + saps*sbap
end do
end do
end do
c Calculate sac * scr
do i = 1, nocca
do m = 1, nva
sac_scr(i, m) = 0.0d0
do l = 1, noccc
sac = oac(i, l)
scr = oac(m + nocca, l)
sac_scr(i, m) = sac_scr(i, m) + sac*scr
end do
end do
end do
最后把所有的东西放在这样一个循环中:
do i = 1, nocca
do k = 1, noccb
do m = 1, nva
do n = 1, nvb
im = i + nocca*(m-1)
kn = k + noccb*(n-1)
imkn = im +oava*(kn-1)
vrsab = ovovab(imkn)
demp3 = demp3 + 2.0d0 * vrsab * 2.0d0 *saps_sbap(n,k) * sac_scr(i,m)
end do
end do
end do
end do
以这种方式代替 O(N^6) 循环有两个 O(N^3) 和一个 O(N^4)
很抱歉最后一段格式,行尾没有用。
我有一项非常繁琐的任务来优化一些古老的 Fortran77 代码。老实说,我根本不懂fortran。我知道循环是如何工作的以及如何乘以矩阵。我也知道这个循环可以优化为几个 3-4 嵌套循环:
do i = 1, nocca
do j = 1, nocca
do k = 1, noccb
do l = 1, noccc
do m = 1, nva
do n =1, nvb
saps = oab(j, n+noccb)
sbap = oab(j, k)
sac = oac(i, l)
scr = oac(m + nocca, l)
im = i + nocca*(m-1)
kn = k + noccb*(n-1)
imkn = im + oava*(kn-1)
vrsab = ovovab(imkn)
demp3 = demp3 + 2.0d0*vrsab*(2.0d0*saps*sbap*sac*scr)
end do
end do
end do
end do
end do
end do
我试图在单独的循环中计算 sapssac,类似地 sacscr:
c Calculate saps * sbap
do j = 1, nocca
do k = 1, noccb
do n = 1, nvb
saps = oab(j, n + noccb)
sbap = oab(j, k)
saps_sbap(j, k) = saps_sbap(j, k) + saps*sbap
end do
end do
end do
c Calculate sac_scr
do i = 1, nocca
do l = 1, noccc
do m = 1, nva
sac = oac(i, l)
scr = oac(m + nocca, l)
sac_scr(i, l) = sac_scr(i, l) + sac*scr
end do
end do
end do
最后我想写最后一部分来计算 demp3 但有 5 个索引而不是我预期的 4。也许我这样做完全错了?
有什么建议吗?提示?
提前致谢!
显然比试图理解一个问题更容易记下来。我自己找到了最佳解决方案。这是:
将大金额分成两部分。我们只考虑第一个:
demp3 = demp3 + 2.0d0*vrsab*(2.0d0*saps*sbap*sac*scr)
在两个单独的循环中乘以 sapssbap 和 sacscr。 (维度可以作为原始循环中的最大索引找到):
REAL*16, DIMENSION(nvb, noccb) :: saps_sbap REAL*16, DIMENSION(nocca, nva) :: sac_scr
以下循环乘以 sapssbap 和 sacscr:
c Calculate saps * sbap
do k = 1, noccb
do n = 1, nvb
saps_sbap(n, k) = 0.0d0
do j = 1, nocca
saps = oab(j, n + noccb)
sbap = oab(j, k)
saps_sbap(n, k) = saps_sbap(n, k) + saps*sbap
end do
end do
end do
c Calculate sac * scr
do i = 1, nocca
do m = 1, nva
sac_scr(i, m) = 0.0d0
do l = 1, noccc
sac = oac(i, l)
scr = oac(m + nocca, l)
sac_scr(i, m) = sac_scr(i, m) + sac*scr
end do
end do
end do
最后把所有的东西放在这样一个循环中:
do i = 1, nocca do k = 1, noccb do m = 1, nva do n = 1, nvb im = i + nocca*(m-1) kn = k + noccb*(n-1) imkn = im +oava*(kn-1) vrsab = ovovab(imkn) demp3 = demp3 + 2.0d0 * vrsab * 2.0d0 *saps_sbap(n,k) * sac_scr(i,m) end do end do end do end do
以这种方式代替 O(N^6) 循环有两个 O(N^3) 和一个 O(N^4)
很抱歉最后一段格式,行尾没有用。