【发布时间】:2021-08-04 19:22:39
【问题描述】:
我正在尝试实现 Jump Flooding 算法以从点数组中绘制 Voronoi 图。下面的代码可以正常工作,但对于大 N 来说非常慢。它慢的原因是有一个循环将新信息添加到正在迭代的数组中。该数组列出了相邻点。如果我不包括这个附加,Voronoi 图是无意义的,算法没有达到大多数点。我不明白为什么在原始邻居搜索中识别的邻居的简单扫描并没有击中网格上的所有点。你能建议我的代码有什么问题吗?如果有一个高性能的替代方法可以将所有找到的邻居附加到一个巨大的数组中?或者这可能只是一个 python 问题,用 C/C++ 等重写将解决性能问题?
import matplotlib.pyplot as plt
import numpy as np
from time import time
# array = np.zeros((5, 5))
# originalSeeds = {1: [2, 2], 2: [4, 1], 3: [0, 4]}
array = np.zeros((10, 10))
originalSeeds = {1: [2, 2], 2: [4, 1], 3: [0, 4]}
# array = np.zeros((200, 200))
# originalSeeds = {1: [20, 20], 2: [40, 10], 3: [0, 40]}
for key, value in originalSeeds.items():
array[value[0], value[1]] = key
seeds = {1: [], 2: [], 3: []}
# this is constantly updated list of neighbors
colors = [1, 2, 3]
colorvalues = {1: 1, 2: 2, 3: 3}
# plt.imshow(array)
# plt.show()
start = time()
step = 2**(int(np.log2(array.shape[0])))
def distance(crd1, crd2):
return np.linalg.norm(crd1 - crd2)
while step >= 1:
for color in colors:
originalSeedCoords = originalSeeds[color]
# neighbor displacments
disp = step * np.array([[1, 1], [0, 1], [-1, 1], [1, -1], [1, 0], [-1, -1], [0, -1], [-1, 0]])
for element in disp:
center = originalSeeds[color]
idx = center + np.array(element)
if idx[0] > array.shape[0] - 1 or idx[1] > array.shape[1] - 1 or idx[0] < 0 or idx[1] < 0:
continue
else:
if array[idx[0], idx[1]] == color:
continue
elif array[idx[0], idx[1]] == 0:
array[idx[0], idx[1]] = colorvalues[color]
seeds[color].append(list(idx))
else:
currColor = array[idx[0], idx[1]]
if distance(idx, originalSeeds[color]) < distance(idx, originalSeeds[currColor]):
array[idx[0], idx[1]] = colorvalues[color]
seeds[color].append(list(idx))
else:
array[idx[0], idx[1]] = colorvalues[currColor]
seeds[currColor].append(list(idx))
for color in colors:
for seed in seeds[color]: # this list may grov during iteration, filling in uncharted points
for element in disp:
center = seed
idx = center + np.array(element)
if idx[0] > array.shape[0] - 1 or idx[1] > array.shape[1] - 1 or idx[0] < 0 or idx[1] < 0:
continue
else:
if array[idx[0], idx[1]] == color:
continue
elif array[idx[0], idx[1]] == 0:
array[idx[0], idx[1]] = colorvalues[color]
if list(idx) not in seeds[color]:
seeds[color].append(list(idx))
else:
currColor = array[idx[0], idx[1]]
if distance(idx, originalSeeds[color]) < distance(idx, originalSeeds[currColor]):
array[idx[0], idx[1]] = colorvalues[color]
if list(idx) not in seeds[color]:
seeds[color].append(list(idx))
else:
array[idx[0], idx[1]] = colorvalues[currColor]
if list(idx) not in seeds[currColor]:
seeds[currColor].append(list(idx))
step = step // 2
# step -= 1
【问题讨论】:
-
用 C++ 转换这段代码会有很大帮助。这应该至少快 1 个数量级。使用更好的数据结构也应该有所帮助。事实上,dicts/hash-maps 很慢。如果键始终是大于或等于 0 的小整数,则可以使用快速纯数组。除此之外,算法可能也可以改进。事实上,
not in是在O(n)时间执行的。seeds[...]应转换为集合而不是列表,以便在恒定时间内执行此操作(需要进行小修复以避免在迭代集合时出现散列问题和更新)。其他改进可能是可能的。 -
我不能在这里使用集合,因为数组需要在迭代过程中改变长度(python 集合不能这样做)。有没有一种方法可以在循环遍历它们时重写它而不需要附加到“seeds [color]”数组?
标签: python performance voronoi