如何在Cython中运行我的python代码



我目前用python编写了相当大的代码,当我运行它时,它需要大约3分钟才能完成完整的计算。最终,我想将N增加到400左右,并将for循环中的m更改为更大的数字-这可能需要花费数小时来计算,我想要减少。

步骤1-6需要很长时间。

当尝试使用cython运行此命令时(即导入pyximport然后导入我的文件)我得到以下错误FDC。Pyx:49:19: 'range'不是一个有效的cython语言结构FDC。Pyx:49:19: 'range'不是有效的cython属性或使用不正确

from physics import *
from operator import add, sub
import pylab


################ PRODUCING CHARGES AT RANDOM IN r #############
N=11 #Number of point charges
x = zeros(N,float) #grid
y = zeros(N,float)
i=0
while i < N: #code to produce values of x and y within r 
    x[i] = random.uniform(0,1)
    y[i] = random.uniform(0,1)
    if x[i] ** 2 + y[i] ** 2 <= 1:
        i+=1

print x, y
def r(x,y): #distance between particles
    return sqrt(x**2 + y**2)   
o = 0; k = 0; W=0        #sum of energy for initial charges 
for o in range(0, N):
    for k in range(0, N):
        if o==k:
            continue
        xdist=x[o]-x[k]
        ydist=y[o]-y[k]
        W+= 0.5/(r(xdist,ydist))
print "Initial Energy:", W

##################### STEPS 1-6 ######################
d=0.01 #fixed change in length
charge=(x,y)
l=0; m=0; n=0
prevsW = 0.
T=100
for q in range(0,100):
    T=0.9*T
    for m in range(0, 4000): #steps 1 - 6 in notes looped over
        xRef = random.randint(0,1)      #Choosing x or y
        yRef = random.randint(0,N-1)      #choosing the element of xRef
        j = charge[xRef][yRef]           #Chooses specific axis of a charge and stores it as 'j'
        prevops = None #assigns prevops as having no variable
        while True: #code to randomly change charge positions and ensure they do not leave the disc
            ops =(add, sub); op=random.choice(ops)
            tempJ = op(j, d)
            #print xRef, yRef, n, tempJ
            charge[xRef][yRef] = tempJ
            ret = r(charge[0][yRef],charge[1][yRef])
            if ret<=1.0:
                j=tempJ
                #print "working", n
                break
            elif prevops != ops and prevops != None: #!= is 'not equal to' so that if both addition and subtraction operations dont work the code breaks 
                break
            prevops = ops #####
        o = 0; k = 0; sW=0        #New energy with altered x coordinate
        for o in range(0, N):
            for k in range(0, N):
                if o==k:
                    continue
                xdist = x[o] - x[k]
                ydist = y[o] - y[k]
                sW+=0.5/(r( xdist , ydist )) 

        difference = sW - prevsW
        prevsW = sW
        #Conditions:
        p=0
        if difference < 0: #accept change
            charge[xRef][yRef] = j
            #print 'step 5'
        randomnum = random.uniform(0,1) #r
        if difference > 0: #acceptance with a probability 
            p = exp( -difference / T )
            #print 'step 6', p
            if randomnum >= p:
                charge[xRef][yRef] = op(tempJ, -d) #revert coordinate to original if r>p
                #print charge[xRef][yRef], 'r>p'
        #print m, charge, difference   
o = 0; k = 0; DW=0        #sum of energy for initial charges 
for o in range(0, N):
    for k in range(0, N):
        if o==k:
            continue
        xdist=x[o]-x[k]
        ydist=y[o]-y[k]
        DW+= 0.5/(r(xdist,ydist))
print charge
print 'Final Energy:', DW
################### plotting circle ###################
# use radians instead of degrees
list_radians = [0]

for i in range(0,360):
    float_div = 180.0/(i+1)
    list_radians.append(pi/float_div)
# list of coordinates for each point
list_x2_axis = []
list_y2_axis = []
# calculate coordinates 
# and append to above list
for a in list_radians:
    list_x2_axis.append(cos(a))
    list_y2_axis.append(sin(a))

# plot the coordinates
pylab.plot(list_x2_axis,list_y2_axis,c='r')
########################################################
pylab.title('Distribution of Charges on a Disc') 
pylab.scatter(x,y)
    pylab.show()

耗时的似乎是:

for q in range(0,100):
    ...
    for m in range(0, 4000): #steps 1 - 6 in notes looped over
        while True: #code to randomly change charge positions and ensure they do not leave the disc
            ....
        for o in range(0, N):      # <----- N will be brought up to 400
            for k in range(0, N):
                ....
            ....            
        ....
    ....

100 × 4000 × (while loop) + 100 × 4000 × 400 × 400 = [400,000 × while loop] + [64,000,000,000]

在寻找更快的语言之前,也许有更好的方法来构建你的模拟?

除此之外,如果您:- shift到numpy数组I/O python列表。-使用xrange i/o range

[编辑试图回答评论中的问题]:

import numpy as np, random
N=11 #Number of point charges
x = np.random.uniform(0,1,N)  
y = np.random.uniform(0,1,N)
z = np.zeros(N)
z = np.sqrt(x**2 + y**2)   # <--- this could maybe replace r(x,y) (called quite often in your code)
print x, y, z

你还可以查看所有在主循环中被多次赋值或重新计算的变量(上面描述的那个),并将所有这些变量拉出循环,这样它就不会被反复赋值或重新计算。

例如,

ops =(add, sub); op=random.choice(ops)

可以用

代替
ops = random.choice(add, sub)

最后,这里我是在一个边缘,因为我从来没有使用过它自己,但它可能会更简单一点,你使用像Numba或Jit包相对于cython;它们允许您修饰代码的关键部分,并在执行之前对其进行预编译,而无需进行任何更改或非常小的更改。

相关内容

  • 没有找到相关文章

最新更新