我正在迭代求解N个耦合微分方程(u1(t),v1(t),u2(t),v2(t),...)。我有一个由N个振荡器组成的环,每个振荡器都连接到P个邻居。我试图通过不将所有迭代步骤都保存到列表中来提高效率,而是将每10个时间步的结果导出到一个二进制文件中,然后导入该文件,以便随时间推移绘制结果。以下是我未使用二进制文件的旧代码。结果不错,但是效率很低:
import numpy as np
import matplotlib.pyplot as plt
dt = 0.001
ts = np.arange(0, 30, dt)
N, P = 4, 2
u = np.array([np.zeros(len(ts)) for i in range(N)])
v = np.array([np.zeros(len(ts)) for i in range(N)])
def a_u(j,t,P,u,v):
del_li = []
for k in range(j-P,j+P):
del_li.append(u[k][t-1] - u[j][t-1])
return (u[j][t-1] - ((u[j][t-1])**3)/3 - v[j][t-1] + (1/(4*P))*sum(del_li))
for t in range(len(ts)):
for j in range(-P,P):
u[j][t] = u[j][t-1] + a_u(j,t,P,u,v)*dt
v[j][t] = v[j][t-1] + (u[j][t-1] + 1.05)*dt + np.random.normal(scale=np.sqrt(dt))
我尝试使用二进制文件使以上代码更快的尝试如下:
u, v = np.array(np.zeros(N)), np.array(np.zeros(N))
def a_u(j,t,P,u,v):
del_li = []
for k in range(j-P,j+P):
del_li.append(u[k] - u[j])
return (u[j] - ((u[j])**3)/3 - v[j] + (1/(4*P))*sum(del_li))
with open('oscillators.bin', 'wb') as f: # write binary file
for t in range(len(ts)):
osc_list = []
for j in range(-P,P):
u[j] += a_u(j,t,P,u,v)*dt
v[j] += (u[j] + 1.05)*dt + np.random.normal(scale=np.sqrt(dt))
if not t % 10:
osc_list.append(u[j])
osc_list.append(v[j])
if j==P:
np.save(f, osc_list)
fp = open("oscillators.bin", 'rb') # read binary file
a = []
for i in range(int(len(ts)/10)):
a.append(np.load(fp))
A = np.array(a) # u[1], v[1], ... = A[:,0], A[:,1], ...
我是否采取了正确的步骤来提高代码效率?我的实际代码比这复杂得多,并且我使用的参数要大得多,因此效率很重要。
在第二行的第一行中,您将u
和v
数组分配到相同的存储位置。即,当您分配给u[j]
和v[j]
时,您分配给相同的位置,将覆盖先前的内容。这将提供完全不同的计算。
使用循环的方式只有在使用cython或类似代码编译代码时才有效率,在这种情况下,类型歧义的python语言的通常开销会减少,并且您可以避免分配和垃圾回收。 u,v
数组的每一步。矢量化运算的其他numpy机制
u,v = u - (u**3)/3 - v)*dt, (u + 1.05)*dt + np.random.normal(scale=np.sqrt(dt), size=len(v))
更快。但是,这种形式仍然没有与相邻节点的耦合。