[英]How to implement in Python a function to compute the Euclidean distance between two arbitrary points on a torus
给定一个 10x10 网格(二维数组),随机填充数字, 0, 1
或2
。 考虑到周期性边界,如何找到两个给定点之间的欧几里得距离(距离向量的 l2 范数)?
让我们考虑一个称为centre
的任意网格点。 现在,我想找到包含与centre
相同值的最近网格点。 我需要考虑周期性边界,这样矩阵/网格可以被看作是一个圆环而不是一个平面。 在这种情况下,假设centre = matrix[0,2]
,我们发现matrix[9,2]
中存在相同的数字,它将位于矩阵的南边界。 使用我的代码计算的欧几里得距离将用于此示例np.sqrt(0**2 + 9**2) = 9.0
。 但是,由于周期性边界,距离实际上应该是1
,因为matrix[9,2]
是matrix[0,2]
的北邻。 因此,如果正确实现了周期性边界值,则不应存在幅度大于 8 的距离。
因此,我会对如何在 Python 中实现 function 感兴趣,以通过对边界应用环绕来计算环面上两个任意点之间的欧几里得距离。
import numpy as np
matrix = np.random.randint(0,3,(10,10))
centre = matrix[0,2]
#rewrite the centre to be the number 5 (to exclude itself as shortest distance)
matrix[0,2] = 5
#find the points where entries are same as centre
same = np.where((matrix == centre) == True)
idx_row, idx_col = same
#find distances from centre to all values which are of same value
dist = np.zeros(len(same[0]))
for i in range(0,len(same[0])):
delta_row = same[0][i] - 0 #row coord of centre
delta_col = same[1][i] - 2 #col coord of centre
dist[i] = np.sqrt(delta_row**2 + delta_col**2)
#retrieve the index of the smallest distance
idx = dist.argmin()
print('Centre value: %i. The nearest cell with same value is at (%i,%i)'
% (centre, same[0][idx],same[1][idx]))
对于每个轴,您可以检查环绕时或不环绕时距离是否较短。 考虑行轴,行i
和j
。
abs(i - j)
。10 - abs(i - j)
。 在您使用i == 0
和j == 9
的示例中,您可以检查这是否正确产生了 1 的距离。然后只需取较小的那个:
delta_row = same[0][i] - 0 #row coord of centre
delta_row = min(delta_row, 10 - delta_row)
同样对于delta_column
。
最终的dist[i]
计算不需要更改。
我有一个关于它如何工作的工作“草图”。 简而言之,我计算了 9 次距离,1 次表示正常距离,8 次移位可能纠正更近的“环面”距离。
随着n
越来越大,计算成本可能会随着数字 go 的增加而变得非常高。 但是,可能不需要环面效应,因为附近总是有一个点没有“环绕”。
您可以轻松地对此进行测试,因为对于大小为 1 的网格,如果找到距离为 1/2 或更近的点,您就知道没有更近的圆环点(对吗?)
import numpy as np
n=10000
np.random.seed(1)
A = np.random.randint(low=0, high=10, size=(n,n))
我创建 10000x10000 点,并将 1 的位置存储在ONES
中。
ONES = np.argwhere(A == 0)
现在我定义了我的环面距离,即尝试 9 个镜子中的哪一个最接近。
def distance_on_torus( point=[500,500] ):
index_diff = [[1],[1],[0],[0],[0,1],[0,1],[0,1],[0,1]]
coord_diff = [[-1],[1],[-1],[1],[-1,-1],[-1,1],[1,-1],[1,1]]
tree = BallTree( ONES, leaf_size=5*n, metric='euclidean')
dist, indi = tree.query([point],k=1, return_distance=True )
distances = [dist[0]]
for indici_to_shift, coord_direction in zip(index_diff, coord_diff):
MIRROR = ONES.copy()
for i,shift in zip(indici_to_shift,coord_direction):
MIRROR[:,i] = MIRROR[:,i] + (shift * n)
tree = BallTree( MIRROR, leaf_size=5*n, metric='euclidean')
dist, indi = tree.query([point],k=1, return_distance=True )
distances.append(dist[0])
return np.min(distances)
%%time
distance_on_torus([2,3])
它很慢,上面需要 15 分钟....对于n = 1000
不到一秒。
优化将首先考虑非环面距离,如果最小距离可能不是最小的,则仅使用最小的额外“块”集进行计算。 这将大大提高速度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.