Algorithm 使用Morton order进行最近邻搜索的好处?

Algorithm 使用Morton order进行最近邻搜索的好处?,algorithm,nearest-neighbor,spatial-index,z-order-curve,Algorithm,Nearest Neighbor,Spatial Index,Z Order Curve,在研究粒子相互作用的模拟时,我偶然发现了莫顿顺序(Z顺序)的网格索引,它被认为提供了一种有效的最近邻单元搜索。我读到这篇文章的主要原因是,内存中空间紧密的单元几乎是按顺序排列的 在第一个实现的中间,我不能思考如何高效地实现最近邻居的算法,特别是与基本统一网格相比。 给定一个单元(x,y),获得8个相邻单元索引并计算相应的z索引是很简单的。尽管这提供了对元素的恒定访问时间,但必须计算z索引或在预定义的表中查找z索引(每个轴和或单独)。这怎么可能更有效率呢?访问数组A中的元素的顺序是A[0]->A-

在研究粒子相互作用的模拟时,我偶然发现了莫顿顺序(Z顺序)的网格索引,它被认为提供了一种有效的最近邻单元搜索。我读到这篇文章的主要原因是,内存中空间紧密的单元几乎是按顺序排列的

在第一个实现的中间,我不能思考如何高效地实现最近邻居的算法,特别是与基本统一网格相比。

  • 给定一个单元(x,y),获得8个相邻单元索引并计算相应的z索引是很简单的。尽管这提供了对元素的恒定访问时间,但必须计算z索引或在预定义的表中查找z索引(每个轴和或单独)。这怎么可能更有效率呢?访问数组A中的元素的顺序是A[0]->A->A[3]->A[4]->,这是真的吗。。。比A[1023]->A[12]->A[456]->A[56]->的顺序更有效

  • 我希望存在一种更简单的算法来查找z顺序中的最近邻。大致如下:找到第一个相邻单元格,迭代。但这不可能是真的,因为这只在2^4大小的块内有效。然而,有两个问题:当单元不在边界上时,可以很容易地确定块的第一个单元并遍历块中的单元,但必须检查单元是否是最近的邻居。当单元位于边界上时,情况更糟,需要考虑2^5个单元。我错过了什么?有没有一个相对简单有效的算法可以满足我的需要

  • 第一点的问题。很容易测试,但我不太熟悉所描述的访问模式生成的底层指令,我真的很想了解幕后发生了什么

    提前感谢您的帮助、推荐信等。。。
    编辑:
    谢谢你澄清第一点!因此,有趣的是,通过Z排序,相邻单元的缓存命中率平均会增加。有没有办法分析缓存命中/未命中率

    关于第2点: 我应该补充一点,我了解如何为R^d中的点云构建Morton有序阵列,其中索引I=f(x1,x2,…,xd)是通过逐位交错等方式获得的。我试图了解的是,是否有比下面的naive ansatz更好的方法来获得最近邻(在d=2中,这里是“伪代码”):


    是的,按顺序访问数组元素确实更快。CPU将内存从RAM分块加载到缓存中。如果按顺序访问,CPU可以轻松地预加载下一个块,并且您不会注意到加载时间。如果你随机访问,它就不能。这就是所谓的缓存一致性,它意味着访问靠近已访问内存的内存会更快

    在您的示例中,当加载[1]、[2]、[3]和[4]时,处理器可能会同时加载其中几个索引,这使得它们非常简单。此外,如果您继续尝试访问[5],它可以在您操作[1]之类的数据块时预加载该数据块,从而使加载时间实际上为零


    但是,如果加载[1023],处理器必须加载该块。然后它必须加载一个[12]——它还没有加载,因此必须加载一个新的块。等等,等等。但是,我不知道你问题的其余部分。

    在现代基于多级缓存的计算机系统中,空间位置是优化数据元素访问时间的一个重要因素

    简言之,这意味着如果访问内存中的数据元素,那么访问内存中靠近的另一个数据元素(其地址接近第一个)的成本可能比访问距离较远的数据元素的成本低几个数量级

    当按顺序访问一维数据时,如在简单的图像处理或声音处理中,或在数据结构上以相同的方式处理每个元素,然后按顺序排列内存中的数据元素,以实现空间局部性-即,由于您在访问元素N之后访问元素N+1,这两个元素应该在内存中相邻放置

    标准c数组(和许多其他数据结构)具有此属性

    Morton排序的要点是支持这样的方案,即数据在维度上访问两次,而不是在维度上访问一次。换句话说,在访问元素(x,y)之后,您可以继续访问(x+1,y)或(x,y+1)或类似内容

    莫顿排序意味着(x,y)、(x+1,y)和(x,y+1)在内存中彼此接近。在标准的c多维数组中,情况未必如此。例如,在数组myArray[10000][10000]中,(x,y)和(x,y+1)相距10000个元素-相距太远,无法利用空间位置


    在Morton排序中,标准c数组仍然可以用作数据的存储,但是计算(x,y)的位置不再像存储[x+y*rowsize]那样简单

    要使用Morton排序实现应用程序,您需要了解如何将坐标(x,y)转换为存储中的地址。换句话说,您需要一个函数
    f(x,y)
    ,该函数可用于访问存储,如
    store[f(x,y)]
    中所示


    看起来你需要做更多的研究-点击维基百科页面的链接,特别是
    BIGMIN
    函数上的链接。

    Hmmm“缓存一致性”或“引用位置”?谢谢你的澄清!这里有一个莫顿订单的3D实现,这里有详细的数学、算法和实验结果,在编辑之前我还没有看到你的评论。我会仔细看看参考资料,非常感谢!感谢您解释阵列中的邻近性。对于
    // Get the z-indices of cells adjacent to the cell containing (x, y) 
    // Accessing the contents of the cells is irrelevant here
    (x, y) \elem R^2    
    point = (x, y)
    zindex = f(x, y)     
    (zx, zy) = f^(-1)(zindex)          // grid coordinates 
    nc = [(zx - 1, zy - 1), (zx - 1, zy), (zx - 1, zy + 1),  // neighbor grid 
          (zx    , zy - 1),               (zx,     zy + 1),  // coordinates
          (zx + 1, zy - 1), (zx + 1, zy), (zx + 1, zy + 1)]
    
    ni= [f(x[0], x[1]) for x in nc]    // neighbor indices