优化六个嵌套循环

时间:2017-12-06 16:27:09

标签: arrays optimization fortran

我需要优化三次嵌套循环。操作 在循环内基本上是调用l1m1l2m2l3m3的函数 并将其添加到(它有点复杂,有更多的总和)。 在我的计算中,我需要运行这个循环以获得大量不同的东西 k值(见下面的代码)。优化我所用代码的第一步是在程序开始时创建一次数组,然后读取它们。这意味着每次嵌套循环执行时都不必评估函数。我的lmax介于20-60之间,我希望尽可能大。

我的一个优点是数组中的大多数值都是零。这使得可以在不耗尽内存的情况下进行此计算。我已经这样做了,所以数组只包含非零值,然后我创建了一个函数,它有一组if条件来评估索引是否应该迭代。选择规则是 有些复杂,但并不过分。

这样做的原因是现在循环包括按顺序读取N个数组,而且应该相当快。交易是我需要评估一堆if语句。

以下Fortran伪代码原则上显示了它是如何完成的。

do l1 = 0,lmax       
   do m1 = -l1,l1
      do l2 = 0,lmax
         do m2 = -l2,l2
            do l3 = 0,lmax
               do m3 = -l3,l3
                  tmp1 = 0.0d0
                  j1 = incr(l1, m1, l2, m2, l3, m3,i1)
                  if(j1 .gt.i1) then 
                     i1=j1
                     tmp1 = array1(i1)
                  endif
                  .....
                  a = a + k1*tmp1 + k2*tmp2 ....
               end do
            end do
         end do             
      end do
   end do
end do

我的问题是:有没有人看到改善这种情况的方法?我在哪里浪费时间,甚至可以希望改进它?

我应该注意到,我正在运行OpenMP。循环的不同执行是独立的,我可以并行执行。他们唯一要分享的是数组array1array2等等。

1 个答案:

答案 0 :(得分:1)

我认为这可能是一个好的开始。但是需要更多信息。 基本上,将6个循环重写为2个循环。一个超过L值,一个超过M值。您可以使用整数运算来重建原始(l1,l2,l3)(m1,m2,m3)

lim = lmax+1
l_loop : DO l_idx = 0,lim**3-1
   l1 = l_idx/(lim*lim)
   l2 = MOD(l_idx,lim*lim)/lim
   l3 = MOD(MOD(l_idx,lim*lim),lim)
   ! implement quick return
   m_loop : DO m_idx = 0,(2*l1+1)*(2*l2+1)*(2*l3+1)-1
      m1 = m_idx / ((2*l2+1)*(2*l3+1)) - l1
      m2 = MOD(m_idx,(2*l2+1)*(2*l3+1))/(2*l3+1) - l2
      m3 = MOD(MOD(m_idx,(2*l2+1)*(2*l3+1)),(2*l3+1)) - l3
      ! implement quick return

      tmp1 = 0.0d0
      j1 = incr(l1, m1, l2, m2, l3, m3,i1)
      IF(j1 .GT.i1) THEN 
         i1=j1
         tmp1 = array1(i1)
      ENDIF
      ...
      a = a + k1*tmp1 + k2*tmp2 ...
   END DO m_loop
END DO l_loop