Skip to content

Commit

Permalink
Enables fastmath flags throughout numba funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
songololo committed May 26, 2021
1 parent 5171e56 commit c730a81
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 141 deletions.
43 changes: 21 additions & 22 deletions cityseer/algos/centrality.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
from cityseer.algos import checks


# don't use 'nnan' fastmath flag
@njit(cache=True, fastmath={'ninf', 'nsz', 'arcp', 'contract', 'afn', 'reassoc'}, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def shortest_path_tree(
edge_data: np.ndarray,
node_edge_map: Dict,
src_idx: int,
max_dist: float = np.inf,
angular: bool = False) -> Tuple[np.ndarray, np.ndarray]:
'''
"""
All shortest paths to max network distance from source node
Returns impedances and predecessors for shortest paths from a source node to all other nodes within max distance
Angular flag triggers check for sidestepping / cheating with angular impedances (sharp turns)
Expand All @@ -41,7 +40,7 @@ def shortest_path_tree(
4 - cycles
5 - origin segments - for any to_idx, the origin segment of the shortest path
6 - last segments - for any to_idx, the last segment of the shortest path
'''
"""
# prepare the arrays
n = len(node_edge_map)
tree_map = np.full((n, 7), np.nan, dtype=np.float32)
Expand Down Expand Up @@ -149,11 +148,11 @@ def shortest_path_tree(
return tree_map, tree_edges


@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def _find_edge_idx(node_edge_map: Dict, edge_data: np.ndarray, start_nd_idx: int, end_nd_idx: int) -> int:
'''
"""
Finds an edge from start and end nodes
'''
"""
# iterate the start node's edges
for edge_idx in node_edge_map[start_nd_idx]:
# check whether the edge's out node matches the target node
Expand All @@ -165,37 +164,37 @@ def _find_edge_idx(node_edge_map: Dict, edge_data: np.ndarray, start_nd_idx: int


# node density
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_density(to_dist, to_imp, beta, cycles):
return 1.0 # return float explicitly


# node farness
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_farness(to_dist, to_imp, beta, cycles):
return to_dist


# node cycles
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_cycles(to_dist, to_imp, beta, cycles):
return cycles


# node harmonic
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_harmonic(to_dist, to_imp, beta, cycles):
return 1.0 / to_imp


# node beta weighted
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_beta(to_dist, to_imp, beta, cycles):
return np.exp(-beta * to_dist)


# node harmonic angular
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_harmonic_angular(to_dist, to_imp, beta, cycles):
a = 1 + (to_imp / 180)
return 1.0 / a
Expand All @@ -205,18 +204,18 @@ def node_harmonic_angular(to_dist, to_imp, beta, cycles):


# node betweenness
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_betweenness(to_dist, beta):
return 1.0 # return float explicitly


# node betweenness beta weighted
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def node_betweenness_beta(to_dist, beta):
'''
"""
distance is based on distance between from and to vertices
thus potential spatial impedance via between vertex
'''
"""
return np.exp(-beta * to_dist)


Expand All @@ -236,7 +235,7 @@ def node_betweenness_beta(to_dist, beta):
'''


@njit(cache=False, fastmath=True, parallel=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True, parallel=True)
def local_node_centrality(node_data: np.ndarray,
edge_data: np.ndarray,
node_edge_map: Dict,
Expand Down Expand Up @@ -395,13 +394,13 @@ def local_node_centrality(node_data: np.ndarray,


# segment density
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def segment_density(n, m, n_imp, m_imp, beta):
return m - n


# segment harmonic
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def segment_harmonic(n, m, n_imp, m_imp, beta):
if n_imp < 1:
return np.log(m_imp)
Expand All @@ -410,15 +409,15 @@ def segment_harmonic(n, m, n_imp, m_imp, beta):


# segment beta
@njit(cache=True, fastmath=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True)
def segment_beta(n, m, n_imp, m_imp, beta):
if beta == 0.0:
return m_imp - n_imp
else:
return (np.exp(-beta * m_imp) - np.exp(-beta * n_imp)) / -beta


@njit(cache=False, fastmath=True, parallel=True, nogil=True)
@njit(cache=True, fastmath=checks.fastmath, nogil=True, parallel=True)
def local_segment_centrality(node_data: np.ndarray,
edge_data: np.ndarray,
node_edge_map: Dict,
Expand Down
26 changes: 14 additions & 12 deletions cityseer/algos/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
def_min_thresh_wt = 0.01831563888873418
# for checking linestring geometries
tolerance = 0.001
# fastmath flags
fastmath = {'ninf', 'nsz', 'arcp', 'contract', 'afn', 'reassoc'}

quiet_mode = False
if 'GCP_PROJECT' in os.environ:
Expand All @@ -22,24 +24,24 @@
debug_mode = True


@njit(cache=False)
@njit(cache=False, fastmath=fastmath)
def progress_bar(current: int, total: int, steps: int = 20):
'''
"""
Printing carries a performance penalty
Cache has to be set to false per Numba issue:
https://github.com/numba/numba/issues/3555
https://github.com/krishnanlab/PecanPy/issues/5
https://github.com/krishnanlab/PecanPy/commit/9c6ca6f5c6341e84aa080b2936cd59d9d8a37b24
TODO: set cache to True once resolved
'''
"""
if steps == 0 or current == 0 or total < 2 * steps:
return
step_size = int(total / steps) # round down
if current % step_size == 0:
print('Processed non-sequential checkpoint', int(current / step_size), 'of', steps)


@njit(cache=True)
@njit(cache=True, fastmath=fastmath)
def check_numerical_data(data_arr: np.ndarray):
if not data_arr.ndim == 2:
raise ValueError('The numeric data array must have a dimensionality 2, '
Expand All @@ -49,7 +51,7 @@ def check_numerical_data(data_arr: np.ndarray):
raise ValueError('The numeric data values must consist of either floats or NaNs.')


@njit(cache=True)
@njit(cache=True, fastmath=fastmath)
def check_categorical_data(data_arr: np.ndarray):
for cl in data_arr:
if not np.isfinite(np.float(cl)) or not cl >= 0:
Expand All @@ -58,15 +60,15 @@ def check_categorical_data(data_arr: np.ndarray):
raise ValueError('Data map contains non-integer class-codes.')


@njit(cache=True)
@njit(cache=True, fastmath=fastmath)
def check_data_map(data_map: np.ndarray, check_assigned=True):
'''
"""
DATA MAP:
0 - x
1 - y
2 - assigned network index - nearest
3 - assigned network index - next-nearest
'''
"""
# catch zero length data maps
if len(data_map) == 0:
raise ValueError('Zero length data map')
Expand All @@ -83,11 +85,11 @@ def check_data_map(data_map: np.ndarray, check_assigned=True):
raise ValueError('Data map has not been assigned to a network.')


@njit(cache=True)
@njit(cache=True, fastmath=fastmath)
def check_network_maps(node_data: np.ndarray,
edge_data: np.ndarray,
node_edge_map: Dict):
'''
"""
NODE MAP:
0 - x
1 - y
Expand All @@ -100,7 +102,7 @@ def check_network_maps(node_data: np.ndarray,
4 - impedance factor
5 - entry bearing
6 - exit bearing
'''
"""
# catch zero length node or edge maps
if len(node_data) == 0:
raise ValueError('Zero length node map')
Expand Down Expand Up @@ -146,7 +148,7 @@ def check_network_maps(node_data: np.ndarray,
'Invalid impedance factor encountered. Should be finite number greater than or equal to zero.')


@njit(cache=True)
@njit(cache=True, fastmath=fastmath)
def check_distances_and_betas(distances: np.ndarray, betas: np.ndarray):
if len(distances) == 0:
raise ValueError('No distances provided.')
Expand Down
Loading

0 comments on commit c730a81

Please sign in to comment.