如何简化复杂的嵌套do循环?

时间:2020-02-23 17:21:46

标签: optimization fortran matrix-multiplication do-loops

我有繁琐的任务来优化一些古老的Fortran77代码。老实说,我一点都不了解fortran。我知道循环的工作原理以及如何将矩阵相乘。我也知道可以将此循环优化为几个3-4个嵌套循环:

type

我试图在单独的循环中计算saps sac,同样地计算sac scr:

    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

最后,我想写最后一部分来计算demp3,但是有5个索引而不是4。也许我这样做完全错误?

有什么建议吗?提示?

谢谢!

1 个答案:

答案 0 :(得分:0)

显然,相比于试图理解一个问题,低俗的说法容易得多。我自己找到了最佳解决方案。在这里:

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

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

  2. 将saps sbap和sac scr分别乘以两个循环。 (维可以在原始循环中找到为最大索引):

    REAL*16, DIMENSION(nvb, noccb) :: saps_sbap
    REAL*16, DIMENSION(nocca, nva) :: sac_scr
    

以下循环将sap sbap和sac scr相乘:

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)

对不起,最后一种格式,行尾无效。