def process_node(node, point, tree_points, distances, indices): i = cuda.grid(1) n_points = tree_points.shape[0] n_neighbors = distances.shape[1] start = node_range_start(node, n_points) end = node_range_end(node, n_points) for j in range(start, end): tree_point = tree_points[j] dist = vincenty(point[0], point[1], tree_point[0], tree_point[1]) if distances[i][0] > dist: # replace farthest neighbor with current point distances[i][0] = dist indices[i][0] = j # bubble sort neighbors for k in range(1, n_neighbors): if distances[i][k - 1] < distances[i][k]: # swap distances temp = distances[i][k] distances[i][k] = distances[i][k - 1] distances[i][k - 1] = temp # swap indices temp = indices[i][k] indices[i][k] = indices[i][k - 1] indices[i][k - 1] = temp
def distance_to_node(point, node, centroids, radiuses): distance = vincenty(point[0], point[1], centroids[node][0], centroids[node][1]) distance = distance - radiuses[node] # 1e-4 meters is less than Vincenty's formula accuracy return distance if distance > 1e-4 else 0
def find_all(arr, res): x, y = cuda.grid(2) if x > y and (x < res.shape[0]) and (y < res.shape[0]): dist = vincenty(arr[x, 0], arr[x, 1], arr[y, 0], arr[y, 1]) cuda.atomic.min(res, x, dist) cuda.atomic.min(res, y, dist)
def query(points, centroids, radiuses, distances, indices): i = cuda.grid(1) if i >= points.shape[0]: return point = points[i] n_nodes = centroids.shape[0] n_points = points.shape[0] n_neighbors = distances.shape[1] home_node = point_id_to_node(i, n_points, n_nodes) node = home_node while True: distance = distance_to_node(point, node, centroids, radiuses) left_child = node * 2 + 1 if distance > distances[i][0]: node = next_right(node) elif left_child < n_nodes: node = left_child else: start = node_range_start(node, n_points) end = node_range_end(node, n_points) for j in range(start, end): p1 = points[i] p2 = points[j] dist = vincenty(p1[0], p1[1], p2[0], p2[1]) if distances[i][0] > dist: distances[i][0] = dist indices[i][0] = j for k in range(1, n_neighbors): if distances[i][k - 1] < distances[i][k]: temp = distances[i][k] distances[i][k] = distances[i][k - 1] distances[i][k - 1] = temp temp = indices[i][k] indices[i][k] = indices[i][k - 1] indices[i][k - 1] = temp node = next_right(node) if node == home_node or node >= n_nodes: break
def stupid_cpu(points): l = len(points) result = np.zeros(l, dtype=np.float32) result[:] = np.inf for x in range(l): for y in range(l): distance = vincenty(points[x, 0], points[x, 1], points[y, 0], points[y, 1]) if (distance < result[x]): result[x] = distance return result
def recursive_build(i_node, data, node_centroids, node_radius, idx_array, node_idx, n_nodes, leaf_size): idx_start, idx_end = node_id_to_range(i_node, data.shape[0]) # determine Node centroid node_centroids[i_node] = [0, 0] for i in range(idx_start, idx_end): node_centroids[i_node] += data[idx_array[i]] node_centroids[i_node] /= (idx_end - idx_start) # determine Node radius radius = 0.0 for i in range(idx_start, idx_end): dist = vincenty(node_centroids[i_node][0], node_centroids[i_node][1], data[idx_array[i]][0], data[idx_array[i]][1]) if dist > radius: radius = dist # set node properties node_radius[i_node] = radius node_idx[i_node] = idx_start, idx_end i_child = 2 * i_node + 1 # recursively create subnodes if i_child + 1 >= n_nodes: if idx_end - idx_start > 2 * leaf_size: print('Memory layout is flawed: not enough nodes allocated') elif idx_end - idx_start < 2: print('Memory layout is flawed: not enough nodes allocated') else: partition_indices(data, idx_array, idx_start, idx_end) recursive_build(i_child, data, node_centroids, node_radius, idx_array, node_idx, n_nodes, leaf_size) recursive_build(i_child + 1, data, node_centroids, node_radius, idx_array, node_idx, n_nodes, leaf_size)
def brute_force(points, neighbors=None, n_neighbors=2): if neighbors is None: neighbors = points n = len(points) distances = np.zeros((n, n_neighbors), dtype=np.float32) distances[:] = np.inf indices = np.zeros((n, n_neighbors), dtype=np.int32) for i in range(n): for j in range(len(neighbors)): distance = vincenty(points[i, 0], points[i, 1], neighbors[j, 0], neighbors[j, 1]) if distance < distances[i][0]: distances[i][0] = distance indices[i][0] = j # bubble sort neighbors for k in range(1, n_neighbors): if distances[i][k - 1] < distances[i][k]: # swap distances temp = distances[i][k] distances[i][k] = distances[i][k - 1] distances[i][k - 1] = temp # swap indices temp = indices[i][k] indices[i][k] = indices[i][k - 1] indices[i][k - 1] = temp distances = np.flip(distances, 1) indices = np.flip(indices, 1) return distances, indices
def plain_vincenty(point1, point2): return vincenty(point1[0], point1[1], point2[0], point2[1])
def distance_to_node(point, node, centroids, radiuses): distance = vincenty(point[0], point[1], centroids[node][0], centroids[node][1]) return max(0, distance - radiuses[node])