【发布时间】:2018-05-18 12:41:06
【问题描述】:
我需要计算 2D 中许多三角形的 signed area,由形状为 (2, 3, n) 的 numpy 数组给出(x/y 坐标,三角形中的节点,三角形的数量)。我正在寻找一种快速完成的方法,到目前为止我能想到的最好的方法是
import numpy
import perfplot
def six(p):
return (
+p[0][2] * p[1][0]
+ p[0][0] * p[1][1]
+ p[0][1] * p[1][2]
- p[0][2] * p[1][1]
- p[0][0] * p[1][2]
- p[0][1] * p[1][0]
) / 2
def mix(p):
return (
+p[0][2] * (p[1][0] - p[1][1])
+ p[0][0] * (p[1][1] - p[1][2])
+ p[0][1] * (p[1][2] - p[1][0])
) / 2
def mix2(p):
p1 = p[1] - p[1][[1, 2, 0]]
return (+p[0][2] * p1[0] + p[0][0] * p1[1] + p[0][1] * p1[2]) / 2
def cross(p):
e1 = p[:, 1] - p[:, 0]
e2 = p[:, 2] - p[:, 0]
return (e1[0] * e2[1] - e1[1] * e2[0]) / 2
def einsum(p):
return (
+numpy.einsum("ij,ij->j", p[0][[2, 0, 1]], p[1][[0, 1, 2]])
- numpy.einsum("ij,ij->j", p[0][[2, 0, 1]], p[1][[1, 2, 0]])
) / 2
def einsum2(p):
return numpy.einsum("ij,ij->j", p[0][[2, 0, 1]], p[1] - p[1][[1, 2, 0]]) / 2
def einsum3(p):
return (
numpy.einsum(
"ij,ij->j", numpy.roll(p[0], 1, axis=0), p[1] - numpy.roll(p[1], 2, axis=0)
)
/ 2
)
perfplot.save(
"out.png",
setup=lambda n: numpy.random.rand(2, 3, n),
kernels=[six, mix, mix2, cross, einsum, einsum2, einsum3],
n_range=[2 ** k for k in range(19)],
)
关于如何提高效率的任何提示?
【问题讨论】:
-
有趣。好吧,可能是不同的 numpy 版本、不同的 BLAS 版本等等。如果您发现可以说速度是原来的两倍,我相信它会在任何机器上有所改进。
-
我认为你不能让它比几个加法和乘法更简单,在这一点上,如果性能真的是一个问题,你需要考虑其他途径(Cython、Numba、CUDA , ETC。)。我不确定在 10 ^ 4-10 ^ 5 步骤中许多功能急剧增加的原因,当有些功能非常相似时……它可能是某种神器(
mix和six是基准中的第一个),或者可能是中间副本的影响......? -
看看 Numba 或 Cython。 stackoverflow.com/a/50387858/4045774 您的混合解决方案有例如。两个问题。糟糕的缓存和内存行为以及不必要的除法(可以用更快的乘法代替)
标签: python arrays numpy perfplot