如何简化复杂的嵌套 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。也许我这样做完全错了?

有什么建议吗?提示?

提前致谢!

显然比试图理解一个问题更容易记下来。我自己找到了最佳解决方案。这是:

  1. 将大金额分成两部分。我们只考虑第一个:

    demp3 = demp3 + 2.0d0*vrsab*(2.0d0*saps*sbap*sac*scr)

  2. 在两个单独的循环中乘以 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
  1. 最后把所有的东西放在这样一个循环中:

    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)

很抱歉最后一段格式,行尾没有用。