Как упростить сложные вложенные циклы? - PullRequest
0 голосов
/ 23 февраля 2020

У меня очень утомительная задача оптимизировать какой-то древний код Fortran77. Честно говоря, я вообще не знаю фортран. Я знаю, как работают циклы и как умножать матрицы. Я также знаю, что этот l oop можно оптимизировать для нескольких 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

Я пытался вычислить saps sa c в отдельных l oop и аналогично sa c scr:

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 Ответ

0 голосов
/ 27 февраля 2020

Понятно, что проще сказать, чем попытаться понять проблему. Я нашел оптимальное решение сам. Вот оно:

  1. Разделите большую сумму на две составляющие. Давайте рассмотрим только первый:

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

  2. Умножаем saps sbap и sa c scr в двух отдельных циклах. (Размеры можно найти как максимальные индексы в исходном l oop):

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

следующие циклы умножают saps sbap и sa c 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

В конце концов соберите все вещи вместе в такие oop:

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 ) l oop есть два O (N ^ 3) и один O (N ^ 4)

Извините за формат последнего фрагмента, конец строки не работал.

...