Python优化问题?

Python优化问题?,python,optimization,numpy,for-loop,physics,Python,Optimization,Numpy,For Loop,Physics,好吧,我最近做了这个作业(别担心,我已经做了,但是用c++),但是我很好奇我怎么能用python来做。问题是大约有两个光源发出光。我不会详细讨论这些 下面是代码(我在后面的部分中对其进行了一些优化): 我已经设法优化了它的大部分,但是在与2 for-s的部分中仍然存在巨大的性能差距,而且我似乎想不出一种方法来绕过使用普通阵列操作的方法。。。我愿意接受建议:D 编辑: 根据Vlad的建议,我将发布问题的详细信息: 有2个光源,每个光源以正弦波的形式发光: E1=E0*sin(ω1*time+phi

好吧,我最近做了这个作业(别担心,我已经做了,但是用c++),但是我很好奇我怎么能用python来做。问题是大约有两个光源发出光。我不会详细讨论这些

下面是代码(我在后面的部分中对其进行了一些优化):

我已经设法优化了它的大部分,但是在与2 for-s的部分中仍然存在巨大的性能差距,而且我似乎想不出一种方法来绕过使用普通阵列操作的方法。。。我愿意接受建议:D

编辑: 根据Vlad的建议,我将发布问题的详细信息: 有2个光源,每个光源以正弦波的形式发光: E1=E0*sin(ω1*time+phi01) E2=E0*sin(ω2*time+phi02) 我们考虑Ωa1=Ωa2=ω=2×π/t和pI001=pI002=pII0。 通过将x1视为距平面上某点的第一个光源的距离,该点的光强为 Ep1=E0*sin(ω*时间-2*PI*x1/lambda+phi0) 哪里 λ=光速*T(振荡周期) 考虑到平面上的两个光源,公式变为 Ep=2*E0*cos(PI*(x2-x1)/lambda)sin(omegatime-PI*(x2-x1)/lambda+phi0) 从中我们可以看出,当 (x2-x1)/lambda=(2*k)*PI/2 最短时间 (x2-x1)/lambda=(2*k+1)*PI/2 并且在这两者之间变化,其中k是一个整数

对于给定的时刻,给定光源的坐标,对于已知的λ和E0,我们必须制作一个程序来绘制光线的外观
我认为我已经尽可能地优化了这个问题…

我想到的唯一变化是将一些操作移出循环:

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)

不过,如果有改进的话,可能会很小。

列表理解比循环快得多。例如,代替

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之类的语言从python中调用它。

干涉模式很有趣,不是吗

所以,首先,这将是次要的,因为在我的笔记本电脑上运行这个程序只需要12.5秒

但是让我们看看通过numpy数组操作执行第一位可以做些什么,好吗?我们基本上有您想要的:

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

因此,既然numpy有一个
hypot
函数可以在numpy数组上工作,那么我们就使用它。我们的第一个挑战是获得一个大小合适的数组,每个元素都等于
i
,另一个数组的每个元素都等于
j
。但这并不难;事实上,下面的一个答案指向了我以前不知道的奇妙的
numpy.mgrid
,它就是这样做的:

array_i,array_j = np.mgrid[0:width,0:height]
(宽度,高度)
大小的数组设置为
(宽度,高度,3)
以与图像生成语句兼容是一件小事,但这很容易做到:

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秒。所以你可以节省整整四秒钟。另一方面,这几乎完全是在图像生成阶段,所以也许你可以通过只生成你想要的图像来收紧它们。

如果你使用数组操作而不是循环,速度会快得多。对我来说,图像生成现在需要很长时间。我没有使用两个
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中使用数组形式只是像应该使用的那样使用它。根据经验,您未来的项目不应该绕道python循环,数组形式应该是自然形式


我们在这里做的很简单。我们找到并使用了
numpy.hypot
而不是
math.hypot
。像所有这样的numpy函数一样,它接受ndarray作为参数,并且做我们想要的事情。

我认为您应该深入了解问题的细节。在算法中寻找优化比较容易。如果您只发布代码,我们必须阅读代码,从代码中找出算法,然后尝试优化它。因此,发布您的原始问题和解决方案,而不是一堆代码。您可以用
arr=(arr*np.ones((3,1,1)))替换您称为“笨拙”的行。转置(1,2,0)
谢谢。不过,这种倍增似乎代价高昂。我现在意识到可能
np.array((arr,arr,arr)).transpose(1,2,0)
有效。什么是优化?这是你不应该做的事!:-)将代码放在函数中,这样在循环中使用时,
hy=..
就是一个局部变量,在for循环中使用时使用快速查找。现在不相关,但它说明了愚蠢优化的本质。更好的改进是使用更好的算法(如此答案)和做更少的工作(使您的代码使用灰度,删除3个重复层)。对于列表来说,这似乎是一个足够好的改进,然而,它给了我:ValueError:形状不匹配:当我在numpy数组上尝试时,对象无法广播到单个形状,无论我如何尝试它,请参见kaizer的答案;你不能像对待Python数据结构那样对待NumPy对象。好吧,看来你的答案和盖伊·贝娄(guy bellow)的计时器都缩短了30秒(是的,我有一台蹩脚的pc,但图像保存部分对我来说也是10秒),虽然我不确定接受谁的答案,我会支持你的,因为你似乎在我的答案上投入了更多的精力,做了完全相同的事情。不过,您必须重视解释,这就是为什么我们在这里讨论stackoverflow,做得很好。和@LWolf,你应该投票给你接受的答案,因为你觉得它很有用。我明白了:-)欢迎来到stackoverflow!
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