2013-11-23 4 views
3

OpenGL 시뮬레이션을 더 빨리 실행하려고 할 때이 함수를 최적화해야합니다. Parakeet을 사용하고 싶지만, 그렇게하기 위해 아래 코드를 수정해야하는 방법을 이해할 수 없습니다. 내가해야 할 일을 볼 수 있니?Parakeet으로 파이썬 함수 최적화

def distanceMatrix(self,x,y,z): 
    " ""Computes distances between all particles and places the result in a matrix such that the ij th matrix entry corresponds to the distance between particle i and j"" " 
    xtemp = tile(x,(self.N,1)) 
    dx = xtemp - xtemp.T 
    ytemp = tile(y,(self.N,1)) 
    dy = ytemp - ytemp.T 
    ztemp = tile(z,(self.N,1)) 
    dz = ztemp - ztemp.T 

    # Particles 'feel' each other across the periodic boundaries 
    if self.periodicX: 
     dx[dx>self.L/2]=dx[dx > self.L/2]-self.L 
     dx[dx<-self.L/2]=dx[dx < -self.L/2]+self.L 
    if self.periodicY: 
     dy[dy>self.L/2]=dy[dy>self.L/2]-self.L 
     dy[dy<-self.L/2]=dy[dy<-self.L/2]+self.L 
    if self.periodicZ: 
     dz[dz>self.L/2]=dz[dz>self.L/2]-self.L 
     dz[dz<-self.L/2]=dz[dz<-self.L/2]+self.L 

    # Total Distances 
    d = sqrt(dx**2+dy**2+dz**2) 

    # Mark zero entries with negative 1 to avoid divergences 
    d[d==0] = -1 

    return d, dx, dy, dz 

내가 말할 수있는 것부터, 앵무새가 수정없이 위의 기능을 사용할 수 있어야합니다. 단지 Numpy와 수학 만 사용합니다. 앵무새의 일종 JIT 래퍼에서 함수를 호출 할 때, 나는 항상 다음과 같은 오류가 발생합니다 :

AssertionError: Unsupported function: <bound method Particles.distanceMatrix of <particles.Particles instance at 0x04CD8E90>> 
+1

하나의 가능한 최적화는'self.L/2'의 12 가지 사용을 단일 로컬 변수로 대체하는 것입니다. 그것은 뭔가를 할 수 있습니다. :-) (비록 이것이 앵무새의 문제에 도움이되지 않지만 ... 미안) –

+1

나는 부울 인덱스가 지원되지 않는다고 생각 하겠지만 확실하지는 않습니다. 나는'xtemp'와'dx> L/2' 같은 중간 배열을 할당하는 것이 낭비라는 것을 알고 있습니다. 벡터화 된 코드는 보통 numpy에서 빠르지 만 JIT 컴파일러를 사용하면 무딘 for-loops를 사용하는 것이 좋습니다! –

답변

4

앵무새의 일종 여전히 젊은, 그 NumPy와 지원이 불완전하고, 코드가 아직 작동하지 않는 몇 가지 기능에 감동.

1) 메서드를 래핑하는 반면, Parakeet은 함수 처리 방법 만 알고 있습니다. 일반적인 해결 방법은 @jit 래핑 된 도우미 함수를 만들고 필요한 모든 멤버 데이터가있는 메서드를 호출하는 것입니다. 메소드가 작동하지 않는 이유는 'self'에 의미있는 타입을 할당하는 것이 중요하지 않기 때문입니다. 불가능한 것은 아니지만, 매달린 열매가 뽑힐 때까지는 방법이 Parakeet으로 들어 가지 않습니다. 낮은 매달린 과일이라고하면 ...

2) 부울 색인. 아직 구현되지 않았지만 다음 릴리스에서 제공 될 예정입니다.

3) np.tile : 또한 작동하지 않으며 다음 릴리스에 포함될 수도 있습니다. 어떤 기본 제공 함수와 NumPy 라이브러리 함수가 작동하는지 보려면, Parakeet의 mappings 모듈을 살펴보십시오. 내 컴퓨터에

@jit 
def parakeet_dist(x, y, z, L, periodicX, periodicY, periodicZ): 
    # perform all-pairs computations more explicitly 
    # instead of tile + broadcasting 
    def periodic_diff(x1, x2, periodic): 
    diff = x1 - x2 
    if periodic: 
     if diff > (L/2): diff -= L 
     if diff < (-L/2): diff += L 
    return diff 
    dx = np.array([[periodic_diff(x1, x2, periodicX) for x1 in x] for x2 in x]) 
    dy = np.array([[periodic_diff(y1, y2, periodicY) for y1 in y] for y2 in y]) 
    dz = np.array([[periodic_diff(z1, z2, periodicZ) for z1 in z] for z2 in z]) 
    d= np.sqrt(dx**2 + dy**2 + dz**2) 

    # since we can't yet use boolean indexing for masking out zero distances 
    # have to fall back on explicit loops instead 
    for i in xrange(len(x)): 
    for j in xrange(len(x)): 
     if d[i,j] == 0: d[i,j] = -1 
    return d, dx, dy, dz 

이는 = 2000 (앵무새의 일종에 대한 NumPy와 대 0.14s에 대한 0.39s) N에 대한 NumPy와보다 빠르게 만 ~ 3 배를 실행합니다

나는 앵무새의 일종에 약간 우호적으로 코드를 재 작성 . 좀 더 명시 적으로 루프를 사용하여 배열 순회를 다시 작성할 경우 성능 (~ 0.06s에서 앵무새의 일종 실행) 빠른 NumPy와 이상 ~ 6 배까지 진행됩니다

@jit 
def loopy_dist(x, y, z, L, periodicX, periodicY, periodicZ): 
    N = len(x) 
    dx = np.zeros((N,N)) 
    dy = np.zeros((N,N)) 
    dz = np.zeros((N,N)) 
    d = np.zeros((N,N)) 

    def periodic_diff(x1, x2, periodic): 
    diff = x1 - x2 
    if periodic: 
     if diff > (L/2): diff -= L 
     if diff < (-L/2): diff += L 
    return diff 

    for i in xrange(N): 
    for j in xrange(N): 
     dx[i,j] = periodic_diff(x[j], x[i], periodicX) 
     dy[i,j] = periodic_diff(y[j], y[i], periodicY) 
     dz[i,j] = periodic_diff(z[j], z[i], periodicZ) 
     d[i,j] = dx[i,j] ** 2 + dy[i,j] ** 2 + dz[i,j] ** 2 
     if d[i,j] == 0: d[i,j] = -1 
     else: d[i,j] = np.sqrt(d[i,j]) 
    return d, dx, dy, dz 

을 창조적 조금 당신은 또한 위의 코드를 얻을 수 있습니다 재 작성으로 Numba에서 실행되지만 NumPy (0.25 초)보다 1.5 배 빠릅니다. 컴파일 시간은 Parakeet w/comprehensions : 1 초, Parakeet w/loops : 0.5 초, Numba w/loops : 0.9 초.

다음 몇 가지 버전을 사용하면 NumPy 라이브러리 함수를 더 관용적으로 사용할 수 있지만 현재는 이해 또는 루프가 자주 사용됩니다.

+1

감사합니다! 나는 당신의 대답을 upvote하기 위해이 계정을 부활시켰다. 비록 당신이 reddit에서도 그것에 응답했다하더라도. 안하는 것보다 늦게하는 것이 낫다. – bogdan