Module geodome.neighbourhood_search
Expand source code
import numpy as np
from numba import njit
MAX_POINTS = 12
@njit
def adj_insert(adj: np.ndarray, root: np.int64, neighbour: np.int64) -> None:
"""Function to insert a point into adjacency list of root vertex
Args:
adj (np.ndarray): array of arrays, representing adjacency list
root (np.int64): index of root vertex
neighbour (np.int64): index of neighbour vertex to add
"""
root_list = adj[root]
for i in range(MAX_POINTS):
if root_list[i] == neighbour:
break
if root_list[i] == -1:
root_list[i] = neighbour
break
@njit
def create_adj_list(vertices: np.ndarray, triangles: np.ndarray) -> np.ndarray:
"""Function to create adjacency list representation of vertices
Args:
vertices (np.ndarray): numpy array of vertices
triangles (np.ndarray): numpy array of vertices
Returns:
np.ndarray: array of arrays representing adjacency list
"""
adj = np.full((len(vertices), MAX_POINTS), -1, dtype=np.int64)
for t in triangles:
adj_insert(adj, t[0], t[1])
adj_insert(adj, t[0], t[2])
adj_insert(adj, t[1], t[0])
adj_insert(adj, t[1], t[2])
adj_insert(adj, t[2], t[0])
adj_insert(adj, t[2], t[1])
return adj
@njit
def find_neighbours_vertex(
vertices: np.ndarray, adj_list: np.ndarray, index: np.int64, depth=1
) -> np.ndarray:
"""Function to find nearest neighbours to a specific point, up to a
specified depth
Args:
vertices (np.ndarray): numpy array of vertices in the Dome
adj (np.ndarray): adjacency list of the vertices
index (np.int64): index of the root vertex
depth (np.int64, optional): search depth. Defaults to 1.
Returns:
np.ndarray: Array of neighbours found, may include -1 representing empty entries
"""
size = 1
for i in range(depth):
size += (i + 1) * MAX_POINTS
if size > len(vertices):
size = len(vertices)
curr_depth = 1
neighbours = np.full(size, -1, dtype=np.int64)
neighbours[0] = index
num_neighbours = 1
queue = np.full(1, index, dtype=np.int64)
visited = np.full(len(vertices), False, dtype=np.bool_)
q_end = 1
while curr_depth <= depth:
temp = np.full(len(queue) * MAX_POINTS, -1, dtype=np.int64)
temp_ptr = 0
q_front = 0
while q_front < q_end:
v_index = queue[q_front]
for neighbour in adj_list[v_index]:
if neighbour != -1 and visited[neighbour] == False:
neighbours[num_neighbours] = neighbour
temp[temp_ptr] = neighbour
num_neighbours += 1
temp_ptr += 1
visited[neighbour] = True
visited[v_index] = True
q_front += 1
# resize queue to contain all new neighbours, remove -1
new_queue = np.zeros(temp_ptr, dtype=np.int64)
for i in range(temp_ptr):
new_queue[i] = temp[i]
queue = new_queue
q_end = temp_ptr
curr_depth += 1
if temp_ptr == 0:
break
return neighbours
@njit
def find_neighbours_triangle(
vertices: np.ndarray, adj_list: np.ndarray, start_vertices: np.ndarray, depth=1
) -> np.ndarray:
"""Function to find nearest neighbours to a specific point, up to a
specified depth
Args:
vertices (np.ndarray): numpy array of vertices in the Dome
adj (np.ndarray): adjacency list of the vertices
index (np.int64): index of the root triangle
depth (np.int64, optional): search depth. Defaults to 1.
Returns:
np.ndarray: Array of neighbours found, may include -1 representing empty entries
"""
START_LEN = 3
if len(start_vertices) != START_LEN:
raise Exception("Invalid starting vertices")
# make space for initial 3 vertices
size = START_LEN
for i in range(depth):
size += ((i + 1) * MAX_POINTS) + START_LEN
if size > len(vertices):
size = len(vertices)
curr_depth = 1
neighbours = np.full(size, -1, dtype=np.int64)
queue = start_vertices
visited = np.full(len(vertices), False, dtype=np.bool_)
# add initial 3 triangle vertices to neighbour array
for i in range(START_LEN):
visited[queue[i]] = True
neighbours[i] = queue[i]
num_neighbours = START_LEN
q_end = START_LEN
while curr_depth <= depth:
temp = np.full((len(queue) * MAX_POINTS) + START_LEN, -1, dtype=np.int64)
temp_ptr = 0
q_front = 0
while q_front < q_end:
v_index = queue[q_front]
for neighbour in adj_list[v_index]:
if neighbour != -1 and visited[neighbour] == False:
neighbours[num_neighbours] = neighbour
temp[temp_ptr] = neighbour
num_neighbours += 1
temp_ptr += 1
visited[neighbour] = True
visited[v_index] = True
q_front += 1
new_queue = np.zeros(temp_ptr, dtype=np.int64)
for i in range(temp_ptr):
new_queue[i] = temp[i]
queue = new_queue
q_end = temp_ptr
curr_depth += 1
if temp_ptr == 0:
break
return neighbours
Functions
def adj_insert(adj: numpy.ndarray, root: numpy.int64, neighbour: numpy.int64) ‑> None-
Function to insert a point into adjacency list of root vertex
Args
adj:np.ndarray- array of arrays, representing adjacency list
root:np.int64- index of root vertex
neighbour:np.int64- index of neighbour vertex to add
Expand source code
@njit def adj_insert(adj: np.ndarray, root: np.int64, neighbour: np.int64) -> None: """Function to insert a point into adjacency list of root vertex Args: adj (np.ndarray): array of arrays, representing adjacency list root (np.int64): index of root vertex neighbour (np.int64): index of neighbour vertex to add """ root_list = adj[root] for i in range(MAX_POINTS): if root_list[i] == neighbour: break if root_list[i] == -1: root_list[i] = neighbour break def create_adj_list(vertices: numpy.ndarray, triangles: numpy.ndarray) ‑> numpy.ndarray-
Function to create adjacency list representation of vertices
Args
vertices:np.ndarray- numpy array of vertices
triangles:np.ndarray- numpy array of vertices
Returns
np.ndarray- array of arrays representing adjacency list
Expand source code
@njit def create_adj_list(vertices: np.ndarray, triangles: np.ndarray) -> np.ndarray: """Function to create adjacency list representation of vertices Args: vertices (np.ndarray): numpy array of vertices triangles (np.ndarray): numpy array of vertices Returns: np.ndarray: array of arrays representing adjacency list """ adj = np.full((len(vertices), MAX_POINTS), -1, dtype=np.int64) for t in triangles: adj_insert(adj, t[0], t[1]) adj_insert(adj, t[0], t[2]) adj_insert(adj, t[1], t[0]) adj_insert(adj, t[1], t[2]) adj_insert(adj, t[2], t[0]) adj_insert(adj, t[2], t[1]) return adj def find_neighbours_triangle(vertices: numpy.ndarray, adj_list: numpy.ndarray, start_vertices: numpy.ndarray, depth=1) ‑> numpy.ndarray-
Function to find nearest neighbours to a specific point, up to a specified depth
Args
vertices:np.ndarray- numpy array of vertices in the Dome
adj:np.ndarray- adjacency list of the vertices
index:np.int64- index of the root triangle
depth:np.int64, optional- search depth. Defaults to 1.
Returns
np.ndarray- Array of neighbours found, may include -1 representing empty entries
Expand source code
@njit def find_neighbours_triangle( vertices: np.ndarray, adj_list: np.ndarray, start_vertices: np.ndarray, depth=1 ) -> np.ndarray: """Function to find nearest neighbours to a specific point, up to a specified depth Args: vertices (np.ndarray): numpy array of vertices in the Dome adj (np.ndarray): adjacency list of the vertices index (np.int64): index of the root triangle depth (np.int64, optional): search depth. Defaults to 1. Returns: np.ndarray: Array of neighbours found, may include -1 representing empty entries """ START_LEN = 3 if len(start_vertices) != START_LEN: raise Exception("Invalid starting vertices") # make space for initial 3 vertices size = START_LEN for i in range(depth): size += ((i + 1) * MAX_POINTS) + START_LEN if size > len(vertices): size = len(vertices) curr_depth = 1 neighbours = np.full(size, -1, dtype=np.int64) queue = start_vertices visited = np.full(len(vertices), False, dtype=np.bool_) # add initial 3 triangle vertices to neighbour array for i in range(START_LEN): visited[queue[i]] = True neighbours[i] = queue[i] num_neighbours = START_LEN q_end = START_LEN while curr_depth <= depth: temp = np.full((len(queue) * MAX_POINTS) + START_LEN, -1, dtype=np.int64) temp_ptr = 0 q_front = 0 while q_front < q_end: v_index = queue[q_front] for neighbour in adj_list[v_index]: if neighbour != -1 and visited[neighbour] == False: neighbours[num_neighbours] = neighbour temp[temp_ptr] = neighbour num_neighbours += 1 temp_ptr += 1 visited[neighbour] = True visited[v_index] = True q_front += 1 new_queue = np.zeros(temp_ptr, dtype=np.int64) for i in range(temp_ptr): new_queue[i] = temp[i] queue = new_queue q_end = temp_ptr curr_depth += 1 if temp_ptr == 0: break return neighbours def find_neighbours_vertex(vertices: numpy.ndarray, adj_list: numpy.ndarray, index: numpy.int64, depth=1) ‑> numpy.ndarray-
Function to find nearest neighbours to a specific point, up to a specified depth
Args
vertices:np.ndarray- numpy array of vertices in the Dome
adj:np.ndarray- adjacency list of the vertices
index:np.int64- index of the root vertex
depth:np.int64, optional- search depth. Defaults to 1.
Returns
np.ndarray- Array of neighbours found, may include -1 representing empty entries
Expand source code
@njit def find_neighbours_vertex( vertices: np.ndarray, adj_list: np.ndarray, index: np.int64, depth=1 ) -> np.ndarray: """Function to find nearest neighbours to a specific point, up to a specified depth Args: vertices (np.ndarray): numpy array of vertices in the Dome adj (np.ndarray): adjacency list of the vertices index (np.int64): index of the root vertex depth (np.int64, optional): search depth. Defaults to 1. Returns: np.ndarray: Array of neighbours found, may include -1 representing empty entries """ size = 1 for i in range(depth): size += (i + 1) * MAX_POINTS if size > len(vertices): size = len(vertices) curr_depth = 1 neighbours = np.full(size, -1, dtype=np.int64) neighbours[0] = index num_neighbours = 1 queue = np.full(1, index, dtype=np.int64) visited = np.full(len(vertices), False, dtype=np.bool_) q_end = 1 while curr_depth <= depth: temp = np.full(len(queue) * MAX_POINTS, -1, dtype=np.int64) temp_ptr = 0 q_front = 0 while q_front < q_end: v_index = queue[q_front] for neighbour in adj_list[v_index]: if neighbour != -1 and visited[neighbour] == False: neighbours[num_neighbours] = neighbour temp[temp_ptr] = neighbour num_neighbours += 1 temp_ptr += 1 visited[neighbour] = True visited[v_index] = True q_front += 1 # resize queue to contain all new neighbours, remove -1 new_queue = np.zeros(temp_ptr, dtype=np.int64) for i in range(temp_ptr): new_queue[i] = temp[i] queue = new_queue q_end = temp_ptr curr_depth += 1 if temp_ptr == 0: break return neighbours