我正在研究如何在 python3 中尽可能高效地计算形式的双倍总和内的点积:
import cmath
for j in range(0,N):
for k in range(0,N):
sum_p += cmath.exp(-1j * sum(a*b for a,b in zip(x, [l - m for l, m in zip(r_p[j], r_p[k])])))
其中 r_np 是一个包含数千个三元组的数组,而 xa 是一个常数三元组。三元组长度的时间N=1000
约为2.4s
. 同样使用numpy:
import numpy as np
for j in range(0,N):
for k in range(0,N):
sum_np = np.add(sum_np, np.exp(-1j * np.inner(x_np,(r_np[j] - r_np[k]))))
运行时间约为4.0s
. 我认为这是由于没有大的矢量化优势,只有短的 3 点 3 是 np.dot,它被循环中的 N^2 吃掉了。但是,通过使用带有 map 和 mul 的普通 python3,我可以获得对第一个示例的适度加速:
from operator import mul
for j in range(0,N):
for k in range(0,N):
sum_p += cmath.exp(-1j * sum(map(mul,x, [l - m for l, m in zip(r_p[j], r_p[k])])))
运行时约2.0s
尝试使用 if 条件不计算大小写j=k
,其中
r_np[j] - r_np[k] = 0
因此点积也变为0,或者将总和分成两部分以达到相同的效果
for j in range(0,N):
for k in range(j+1,N):
...
for k in range(0,N):
for j in range(k+1,N):
...
两者都让它变得更慢。所以整个事情的比例为 O(N^2),我想知道是否通过一些方法,如排序或其他方法,可以摆脱循环并使其比例为 O(N logN)。问题是我需要一组N~6000
三元组的个位数秒运行时,因为我有数千个这样的总和要计算。否则我必须尝试 scipy's weave 、numba、pyrex 或 python 或者完全走 C 路径……</p>
提前感谢您的帮助!
编辑:
这就是数据样本的样子:
# numpy arrays
x_np = np.array([0,0,1], dtype=np.float64)
N=1000
xy = np.multiply(np.subtract(np.random.rand(N,2),0.5),8)
z = np.linspace(0,40,N).reshape(N,1)
r_np = np.hstack((xy,z))
# in python format
x = (0,0,1)
r_p = r_np.tolist()