【问题标题】:efficient sign function in python for case of periodic boundary conditionspython中用于周期性边界条件的有效符号函数
【发布时间】:2023-03-09 11:30:01
【问题描述】:

我有 cython 代码用于加速原本纯 python 计算中的瓶颈。我在长度为 Lbox 的周期框中有一对点(对于这个问题,1d 情况很好)。我需要计算 y-x 的符号,当周期性边界条件有效时,我需要翻转这个符号。

在没有 PBC 的情况下,以下问题提供了解决方案:Is there a standard sign function (signum, sgn) in C/C++?。该解决方案就是我用来计算 sgn 函数的方法。

def sgn(x, y):
    """ If x > y, returns 1. 
    If x < y, returns -1. 
    If x == y, returns 0. 
    """
    return (y < x) - (x < y)

下面写的sgn_pbc函数返回正确的结果,但是写的效率低:sgn_pbc中的控制流是导致PBC版本变慢的罪魁祸首。我怎样才能以类似于 sgn 函数的方式编写 sgn_pbc,从而避免笨拙的控制流程?

def sgn_pbc(x, y, Lbox):
    d = abs(x-y)
    if d <= Lbox/2.:
        return sgn(x, y)
    else:
        return -1*sgn(x, y)

【问题讨论】:

  • sgn,你为什么不用np.sign(y-x)
  • 对于一对浮点数,上面的sgn函数比np.sign快400%左右
  • 你用numpy标记了这个。通常加快速度的最佳方法是对代码进行矢量化,这就是 numpy 的全部意义所在。您是否对矢量化解决方案感兴趣,其中xy 是浮点数组,还是要坚持使用“浮点对”?
  • 这些是python 还是cython 函数?我看到了def,但没有看到cdef

标签: python performance numpy cython


【解决方案1】:

首先,

-1*sgn(x, y) == sgn(y, x)

那么,

def sgn_pbc(x, y, Lbox):
    d = abs(x-y)
    if d <= Lbox/2.:
        return sgn(x, y)
    else:
        return sgn(y, x)

同样在 Python 中,函数调用是最昂贵的操作。你可以内联你的sgn

def sgn_pbc(x, y, Lbox):
    d = abs(x-y)
    if d <= Lbox/2.:
        return (y < x) - (x < y)
    else:
        return (x < y) - (y < x)

但是if 可以(大部分)重写为:

def sgn_pbc(x, y, Lbox):
    d = abs(x-y)
    w = sgn(Lbox/2., d)
    return  w * sgn(x, y)

再一次,内联sgn

def sgn_pbc(x, y, Lbox):
    d = abs(x-y)
    w = sgn(Lbox/2., d)
    return  w * (y < x) - (x < y)

我说主要是因为d == Lbox/2. this 返回错误值的情况。

不过还没有计时。

【讨论】:

  • 这正是我卡住的地方:这种方法仍然需要控制流来正确处理 d==Lbox/2 的情况,因此根本没有加速。
  • 那些是浮点值吗?因为您可以添加 +eps 以使该等式成立的概率非常低(1/2**53)。
  • 除非我有什么误解,否则无论添加什么epsilon,当距离正好等于Lbox/2+epsilon 时,返回的结果都是不正确的。
  • 是的。这概率有多大?
猜你喜欢
  • 2023-03-10
  • 2015-10-29
  • 2020-02-12
  • 2016-10-30
  • 2016-06-24
  • 1970-01-01
  • 2015-03-21
  • 2016-11-19
  • 2019-04-02
相关资源
最近更新 更多