确认点位于指定音高的网格上

时间:2017-10-05 12:30:39

标签: numpy floating-point

虽然我试图在大量使用numpy的环境中解决这个问题(因此特别欢迎基于numpy的优雅解决方案),但基本问题与numpy(甚至是Python)无关。

任务是为算法创建一个自动测试,该算法应该产生分布在网格上的点,网格的音高被指定为算法的输入。点的绝对位置无关紧要,但它们的相对位置有效。例如,关注

collection_of_points = algorithm(data, pitch=[1.3, 1.5, 2])

collection_of_points应仅包含x坐标相差1.3倍的点,其y坐标相差1.5倍,其z坐标相差2倍。

测试应验证是否满足此条件。

我尝试过的一件事,看起来并不是太难看,但是不起作用

points = algo(data, pitch=requested_pitch)
for p1, p2 in itertools.combinations(points, 2):
    distance_between_points = np.array(p2) - np.array(p1)
    assert np.allclose(distance_between_points % requested_pitch, 0)

[除了那些不熟悉python或numpy的人:

  • itertools.combinations(points, 2)是一种迭代所有点对的简单方法
  • np.array的算术运算是按元素执行的,因此np.array([5,6,7]) % np.array([2,3,4])通过np.array([1, 0, 3])评估为np.array([5%2, 6%3, 7%4])
  • np.allclose检查两个输入数组中的所有对应元素是否近似相等,并且numpy自动假装作为第二个参数传入的0是真的是一个正确大小的全零数组

要了解上面显示的想法失败的原因,请考虑所需的3音高和相关维度中由8.9999999分隔的两个点。 8.999999 % 3位于2.999999左右,远不及所需的0

在所有这些中,我无法感觉到我错过了一些明显的东西,或者我正在重新发明一些轮子。

你能建议一种优雅的方式来编写这样的支票吗?

1 个答案:

答案 0 :(得分:1)

将您的断言更改为:

np.all(np.logical_or(np.isclose(x % y, 0), np.isclose((x % y) - y, 0)))

如果要使其更具可读性,则应该使语句功能化。类似的东西:

def is_multiple(x, y, rtol=1e-05, atol=1e-08):
    """
    Test if x is a multiple of y.
    """
    remainder = x % y
    is_zero = np.isclose(remainder, 0., rtol, atol)
    is_y = np.isclose(remainder, y, rtol, atol)
    return np.logical_or(is_zero, is_y)

然后:

    assert np.all(is_multiple(distance_between_points, requested_pitch))