Algorithm 使用Morton order进行最近邻搜索的好处?
在研究粒子相互作用的模拟时,我偶然发现了莫顿顺序(Z顺序)的网格索引,它被认为提供了一种有效的最近邻单元搜索。我读到这篇文章的主要原因是,内存中空间紧密的单元几乎是按顺序排列的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排序,相邻单元的缓存命中率平均会增加。有没有办法分析缓存命中/未命中率 关于第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