2010-05-15 4 views
2

좋아요, 최근에이 숙제가있었습니다. (걱정하지 마세요, 이미 해봤지만 C++에서는)하지만 파이썬으로 어떻게 할 수 있는지 궁금합니다. 문제는 빛을 방출하는 약 2 개의 광원입니다. 나는 세부 사항 tho로 들어 가지 않을 것이다. 여기 파이썬 최적화 문제?

(나는 후반에 약간의 최적화 관리 한 것을) 코드입니다 : 나는 그것의 대부분을 최적화하기 위해 관리해야

import math, array 
import numpy as np 
from PIL import Image 

size = (800,800) 
width, height = size 

s1x = width * 1./8 
s1y = height * 1./8 
s2x = width * 7./8 
s2y = height * 7./8 

r,g,b = (255,255,255) 
arr = np.zeros((width,height,3)) 
hy = math.hypot 
print 'computing distances (%s by %s)'%size, 
for i in xrange(width): 
    if i%(width/10)==0: 
     print i,  
    if i%20==0: 
     print '.', 
    for j in xrange(height): 
     d1 = hy(i-s1x,j-s1y) 
     d2 = hy(i-s2x,j-s2y) 
     arr[i][j] = abs(d1-d2) 
print '' 

arr2 = np.zeros((width,height,3),dtype="uint8")   
for ld in [200,116,100,84,68,52,36,20,8,4,2]: 
    print 'now computing image for ld = '+str(ld) 
    arr2 *= 0 
    arr2 += abs(arr%ld-ld/2)*(r,g,b)/(ld/2) 
    print 'saving image...' 
    ar2img = Image.fromarray(arr2) 
    ar2img.save('ld'+str(ld).rjust(4,'0')+'.png') 
    print 'saved as ld'+str(ld).rjust(4,'0')+'.png' 

을하지만, 함께 부분에서 큰 성능 차이는 여전히있다 2 for-s, 그리고 일반적인 배열 작업을 사용하여 그 우회하는 방법을 생각하지 않는 것 ... 나는 제안에 개방적이다 : D

편집 : Vlad의 제안에 대한 응답으로, 문제의 세부 정보를 게시 할 것입니다 : 두 개의 광원이 있으며, 각각 빛을 사인파로 방출합니다. E1 = E을 단순화하기 위해, x1을 고려함으로써, omega1 = omega2 = omega = 2 * PI/T 및 phi01 = phi02 = phi0을 고려한다. 평면상의 점의 제 1 소스로부터의 거리, 그 점에서의 광의 강도는 이다 .Ep1 = E0 * sin (ω * time - 2 * PI * x1/λ + phi0) 여기서, λ = 속도 빛 * T (진동주기) 두 광원을 모두 고려할 때, 공식은 Ep = 2 * E0 * cos (PI * (x2-x1)/λ) sin (ω 시간 - PI * -x1)/λ + phi0) 이고, 이로부터 우리는 빛의 세기가 최대일 때, (x2-x1)/λ = (2 * k) * PI/2,최소 때 (X2-X1)/람다 = (2 * K + 1) * PI/2 k는 좌표의 소정의 정수 시간의 주어진 순간 용

에게, 여기서 사이 변화 광원 및 알려진 람다 및 E0에 대해 우리는 빛이 어떻게 보이는지 그리는 프로그램을 작성해야했습니다 IMHO 나는이 문제를 내가 수행 할 수있는만큼 최대한 최적화했다고 생각합니다 ...

+2

제 생각에는 문제의 세부 사항에 대해 알아야합니다. 알고리즘에서 최적화를 찾는 것이 더 쉽습니다. 코드를 게시하는 경우 코드를 읽고 코드에서 알고리즘을 찾아내어 최적화해야합니다. 그래서 원래의 문제와 해결책을 게시하십시오. – IVlad

답변

5

간섭 패턴이 재미있는가요?

그래서이 프로그램을 내 랩톱 컴퓨터에서 실행하는 데는 불과 12 초 밖에 걸리지 않으므로 처음에는 유용하지 않습니다.

하지만 numpy 배열 작업을 통해 첫 번째 비트를 수행하는 방법에 대해 알아 보겠습니다.ij되는 모든

arr[i][j] = abs(hypot(i-s1x,j-s1y) - hypot(i-s2x,j-s2y)) 

: 우리는 당신이 원하는 것을 기본적으로 가지고있다.

그래서 numpy에는 numpy 배열에서 작동하는 hypot 함수가 있으므로이를 사용합시다. 첫 번째 과제는 모든 요소가 i 인 모든 요소와 j 인 모든 요소로 올바른 크기의 배열을 얻는 것입니다. 그러나 이것은 너무 어렵지 않습니다. 사실, 대답은 아래 내가 그보다 먼저 몰랐던 멋진 numpy.mgrid에서 내 포인트 그냥이 :와 호환되도록 (width,height,3)(width, height) 2N 크기 배열을 만드는 약간의 문제가있다

array_i,array_j = np.mgrid[0:width,0:height] 

프로그램에

arr = (arr * np.ones((3,1,1))).transpose(1,2,0) 

그런 다음 우리는이 플러그, 사물이 배열 작업을 수행 할 수 있습니다 : 이미지 세대 문,하지만 꽤 쉽다는해야 할 일

import math, array 
import numpy as np 
from PIL import Image 

size = (800,800) 
width, height = size 

s1x = width * 1./8 
s1y = height * 1./8 
s2x = width * 7./8 
s2y = height * 7./8 

r,g,b = (255,255,255) 

array_i,array_j = np.mgrid[0:width,0:height] 

arr = np.abs(np.hypot(array_i-s1x, array_j-s1y) - 
      np.hypot(array_i-s2x, array_j-s2y)) 

arr = (arr * np.ones((3,1,1))).transpose(1,2,0) 

arr2 = np.zeros((width,height,3),dtype="uint8") 
for ld in [200,116,100,84,68,52,36,20,8,4,2]: 
    print 'now computing image for ld = '+str(ld) 
    # Rest as before 

그리고 새 시간은 ... 8.2 초입니다. 그래서 당신은 아마 4 초 전체를 저장할 것입니다. 반면에, 그것은 거의 독점적으로 이미지 생성 단계에 있으므로, 아마도 당신이 원하는 이미지를 생성하여 그들을 강화할 수 있습니다.

+0

글쎄, 당신의 대답과 남자 벨로우즈가 타이머의 멋진 30 초를 면도하는 것처럼 보입니다. (그래, 나는 엉뚱한 PC를 가지고 있습니다.하지만 이미지 저장 부분도 10 초입니다.) 그리고 나는 대답이 불확실합니다. 받아들이려면, 당신이 그것에 더 많은 노력을 기울인 것처럼 보이기 때문에 나는 당신을 위해 갈 것입니다. – LWolf

+0

우리의 대답은 똑같은 일을합니다. 당신은 설명을 중요하게 생각해야합니다. 그래서 우리는 stackoverflow에 대해 잘 설명합니다. 그리고 @LWolf, 당신은 당신이 받아들이는 대답을 upvote해야한다, 당신이 유용하다고 생각하기 때문에. – u0b34a0f6ae

+0

투표는 15 평판을 요구합니다 ^.^ 미안하지만 xD는 없습니다 – LWolf

1

내 마음에 와서 루프 밖으로 일부 작업을 이동하는 것입니다 :

for i in xrange(width): 
    if i%(width/10)==0: 
     print i,  
    if i%20==0: 
     print '.', 
    arri = arr[i] 
    is1x = i - s1x 
    is2x = i - s2x 
    for j in xrange(height): 
     d1 = hy(is1x,j-s1y) 
     d2 = hy(is2x,j-s2y) 
     arri[j] = abs(d1-d2) 

개선, if 어떤, 아마도 사소한 것입니다.

2

목록 내장은 루프보다 훨씬 빠릅니다. 예를 들어, 대신

for j in xrange(height): 
     d1 = hy(i-s1x,j-s1y) 
     d2 = hy(i-s2x,j-s2y) 
     arr[i][j] = abs(d1-d2) 

의 당신은 다른 한편으로

arr[i] = [abs(hy(i-s1x,j-s1y) - hy(i-s2x,j-s2y)) for j in xrange(height)] 

를 써서, 당신이 정말로 "최적화"하려는 경우, 당신은 C에서이 알고리즘을 구현할 할 수 있습니다, 그리고 SWIG 등을 사용하여 파이썬에서 호출하십시오.

+0

목록에 대한 충분한 개선 같은데, 나에게 준다 : ValueError : 모양 불일치 : 객체가 단일 모양으로 브로드 캐스팅 될 수 없음 아무리 노력해도 numpy 배열에서 시도 할 때 – LWolf

+0

kaizer의 대답을 참조하십시오. 당신은 파이썬 데이터 구조와 같은 NumPy 객체를 처리 할 수 ​​없습니다. –

3

루프 대신 배열 작업을 사용하면 훨씬 더 빠릅니다. 나에게 이미지 생성은 이제 오랜 시간이 걸린다. 대신 당신이 개 i,j 루프, 나는이 있습니다

I,J = np.mgrid[0:width,0:height] 
D1 = np.hypot(I - s1x, J - s1y) 
D2 = np.hypot(I - s2x, J - s2y) 

arr = np.abs(D1-D2) 
# triplicate into 3 layers 
arr = np.array((arr, arr, arr)).transpose(1,2,0) 
# .. continue program 

당신이 미래에 대한 기억 할 기본 사항은 다음과 같습니다이 최적화에 대한 하지이다; numpy에서 배열 폼을 사용하는 것은 사용되는 것처럼 사용하고 있습니다. 경험상, 미래의 프로젝트는 파이썬 루프를 우회해서는 안되며 배열 형태는 자연스러운 형식이어야합니다.

우리가 여기서 한 것은 정말 간단했습니다. math.hypot 대신 numpy.hypot을 찾았습니다. 이러한 numpy 함수와 마찬가지로 ndarrays를 인자로 받아들이고 우리가 원하는 것을 정확하게 수행합니다.

+0

"clumsy"라고하는 행을'arr = (arr * np.ones ((3,1,1)))로 바꿀 수 있습니다. transpose (1,2,0)' –

+0

감사합니다.곱셈은 ​​비용이 많이 드는 것처럼 보입니다. 이제는 아마도 np.array ((arr, arr, arr)) transpose (1,2,0)가 작동한다는 것을 알게되었습니다. – u0b34a0f6ae

+0

what * is * optimization입니까? 그것은 당신이해서는 안되는 일입니다! :-) 그것은 함수 안에 코드를 넣는 것과 같은 말도 안되는 일입니다. 그래서'hy = ..'는 for 루프에서 사용될 때 빠른 검색을 사용하는 지역 변수입니다. 지금은 관련이 없지만 어리석은 최적화의 본질을 보여줍니다. – u0b34a0f6ae