跳池法的程序设计与优化

2024-10-02 08:18:34 发布

您现在位置:Python中文网/ 问答频道 /正文

所以我正在编程一个盆,希望从零开始找到相互作用粒子系统的潜在极小值,到目前为止我已经获得了很好的结果,但是由于我增加了系统的粒子数,代码需要更多的时间来运行。我正在使用scipy共轭梯度来寻找局部极小值。我没有收到任何错误消息,程序似乎运行良好,但我想知道如何优化代码以减少计算时间

我将盆地跳跃定义为一个函数,给出:

def bhmet(n,itmax, pot,derpot, T):
i = 1 
phi = np.random.rand(n)*2*np.pi
theta = np.random.rand(n)*np.pi
x = 3*np.sin(theta)*np.cos(phi)
y = 3*np.sin(theta)*np.sin(phi)
z = 3*np.cos(theta)
xyzat = np.hstack((x,y,z))
vmintot = 0 
while i <= itmax: 
    print(i)   
    plmin = optimize.fmin_cg(pot,xyzat,derpot,gtol = 1e-5,) #posiciones para el mínimo local.4
    if pot(plmin) < vmintot or np.exp((1/T)*(vmintot-pot(plmin))) > np.random.rand():
        vmintot = pot(plmin)
    xyzat = plmin + 2*0.3*(np.random.rand(len(plmin))-0.5)
    i = i + 1  
return plmin,vmintot 

我尝试将初始条件(第一个'xyzat')定义为矩阵,但scipy.optimize.fmin_cg的参数被请求为数组(这就是为什么在函数中我将把数组重塑为矩阵)

我搜索全局极小值的函数是:

def ljpot(posiciones,):
r = np.array([])
matpos = np.zeros((int((1/3)*len(posiciones)),3))
matpos[:,0] = posiciones[0:int((1/3)*len(posiciones))]
matpos[:,1] = posiciones[int((1/3)*len(posiciones)):int((2/3)*len(posiciones))]
matpos[:,2] = posiciones[int((2/3)*len(posiciones)):]    
for j in range(0,np.shape(matpos)[0]):
    for k in range(j+1,np.shape(matpos)[0]):
        ri = np.sqrt(sum((matpos[k,:]-matpos[j,:])**2))
        r = np.append(r,ri) 
V = 4*((1/r)**12-(1/r)**6)
vt = sum(V)
return vt

其梯度为:

def gradpot(posiciones,):
gradv = np.array([])
matposg = np.zeros((int((1/3)*len(posiciones)),3))
matposg[:,0] = posiciones[:int((1/3)*len(posiciones))]
matposg[:,1] = posiciones[int((1/3)*len(posiciones)):int((2/3)*len(posiciones))]
matposg[:,2] = posiciones[int((2/3)*len(posiciones)):]   
for w in range(0,np.shape(matposg)[1]): #índice que cambia de columna. 
    for k in range(0,np.shape(matposg)[0]): #índice que cambia de fila.
        rkj = np.array([])
        xkj = np.array([])
        for j in range(0,np.shape(matposg)[0]): #también este cambia de fila. 
            if j != k:
                r = np.sqrt(sum((matposg[j,:]-matposg[k,:])**2))
                rkj = np.append(rkj,r) 
                xkj = np.append(xkj,matposg[j,w])
        dEdxj = sum(4*(6*(1/rkj)**8- 12*(1/rkj)**14)*(matposg[k,w]-xkj))
        gradv = np.append(gradv,dEdxj)
return gradv

我在矩阵中变换数组输入的原因是,对于每个粒子,有三个坐标x,y,z,因此矩阵的列对于每个粒子都是x,y,z。我试图使用np.reforme()来实现这一点,但对于程序已经得到正确结果的系统,它似乎给了我错误的结果

代码似乎运行得很好,但随着粒子数的增加,运行时间呈指数增长。我知道全局优化可能需要很长时间,但也许我在代码上弄乱了一点。我不知道减少运行时间的方法是否很明显,我对优化代码有点陌生,如果是这样的话,很抱歉。当然,欢迎您提供任何建议。非常感谢大家


Tags: 代码inforlennprangeintshape
1条回答
网友
1楼 · 发布于 2024-10-02 08:18:34

在快速查看后,我注意到两件事,在这两件事中,您肯定可以节省一些时间。这两种方法都需要更多的思考,但之后您将得到优化和更干净的代码


1。尽量避免使用appendappend效率很低。首先是一个空数组,然后每次都需要分配更多内存。这会导致内存处理效率低下,因为每次追加数字时都会复制阵列。数组越长,append的效率越低

备选方案:使用np.zeros((m,n))初始化数组,其中mn是数组最终的大小。然后需要一个计数器,将新值放入相应的位置。如果在计算之前未定义数组的大小,可以将其初始化为一个大数字,然后将其剪切


2。尽量避免使用for循环。它们通常非常慢,尤其是在遍历大型矩阵时,因为需要对每个条目分别进行索引

备选方案:矩阵运算通常要快得多。例如,您可以先定义两个矩阵AB,它们对应于matposg[j,:]matposg[k,:](不使用循环也可以!),然后简单地使用r = np.linalg.norm(A-B),而不是在两个for循环中定义r = np.sqrt(sum((matposg[j,:]-matposg[k,:])**2))

相关问题 更多 >

    热门问题