2013-10-30 37 views
1

這段代碼片段是我的一個項目的瓶頸。有函數調用可以替代for循環並加速嗎?是否有函數調用可以替換此代碼中的for循環?

D = np.zeros((nOcc,nOcc,nVir,nVir)) 
for i in range(nOcc): 
    for j in range(i+1): 
     tmp = Ew[i] + Ew[j] 
     for a in range(nVir): 
     tmp2 = tmp - Ew[a+nOcc] 
     for b in range(a+1): 
      tmp3 = 1.0/(tmp2 - Ew[b+nOcc]) 
      D[i,j,a,b] = Iiajb[i,a,j,b]*tmp3 
      D[i,j,b,a] = Iiajb[i,b,j,a]*tmp3 
      D[j,i,a,b] = D[i,j,b,a] 
      D[j,i,b,a] = D[i,j,a,b] 
+0

應該做什麼功能? 「nOcc」和「nVir」有多大? – GWW

+0

什麼是nOcc,nVir,Ew,Iiajb ... – voithos

+2

可能更多的codereview問題 – samrap

回答

3

要開始讓產生一些任意的數據,這就是服從少數需要原則:

nOcc = 30 
nVir = 120 
Ew = np.random.rand(nOcc+nVir) 
Ew[:nOcc]*=-1 
Ia = np.random.rand(nOcc) 
Ib = np.random.rand(nVir) 
I = np.einsum('a,b,c,d->abcd',Ia,Ib,Ia,Ib) 

讓包裝你的基本代碼爲例:

def oldcalc_D(Iiajb,nOcc,nVir,Ew): 
    D = np.zeros((nOcc,nOcc,nVir,nVir)) 
    for i in range(nOcc): 
     for j in range(i+1): 
      tmp = Ew[i] + Ew[j] 
      for a in range(nVir): 
      tmp2 = tmp - Ew[a+nOcc] 
      for b in range(a+1): 
       tmp3 = 1.0/(tmp2 - Ew[b+nOcc]) 
       D[i,j,a,b] = Iiajb[i,a,j,b]*tmp3 
       D[i,j,b,a] = Iiajb[i,b,j,a]*tmp3 
       D[j,i,a,b] = D[i,j,b,a] 
       D[j,i,b,a] = D[i,j,a,b] 
    return D 

以整體對稱的優點是一般一個好策略;然而,僅在numpy的是不值得的成本,所以我們會忽略這一點,簡單地向量化代碼:

def newcalc_D(I,nOcc,nVir,Ew): 
    O = Ew[:nOcc] 
    V = Ew[nOcc:] 
    D = O[:,None,None,None] - V[:,None,None] + O[:,None] - V 
    return (I/D).swapaxes(1,2) 

一些計時:

np.allclose(oldcalc_D(I,nOcc,nVir,Ew),newcalc_D(I,nOcc,nVir,Ew)) 
True 

%timeit newcalc_D(I,nOcc,nVir,Ew) 
1 loops, best of 3: 142 ms per loop 

%timeit oldcalc_D(I,nOcc,nVir,Ew) 
1 loops, best of 3: 15 s per loop 

所以只有大約〜100倍的速度更快,因爲我說這是一個相當簡單的過關,讓你知道該怎麼做。這可以做得好得多,但應該是計算的一個微不足道的部分,因爲整數變換是(O)N^5而在(O)N^4處是這個。對於這些操作,我使用numba的autojit功能:

from numba import autojit 

numba_D = autojit(oldcalc_D) 

%timeit numba_D(I,nOcc,nVir,Ew) 
10 loops, best of 3: 55.1 ms per loop 
+0

正是我想要的,非常感謝Ophion! –

0

,除非這是Python3,您可能希望通過與xrange更換range啓動:前創建整個列表,而後者僅僅是一個迭代器,這是你在這種情況下需要。
對於大型N s,速度差異應該是顯而易見的。

此外,看作爲你的使用numpy,可能有一個向量化的方法來實現算法。如果是這樣的話,矢量化的實現應該快幾個數量級。但除非你解釋變量和算法,否則我們無法幫助你朝那個方向發展。