Here is my Python implementation of counting neighbours of Game of Life with radius as parameter.
def neighbors_count(n2d_array, radii=1):
assert n2d_array.ndim == 2
row_len, col_len = n2d_array.shape
nbrs_count = np.zeros_like(n2d_array)
for row_idx, row_val in enumerate(n2d_array):
for col_idx, col_val in enumerate(row_val):
start_row = 0 if (row_idx-radii) < 0 else (row_idx-radii)
end_row = row_len if (row_idx+radii+1) > row_len else (row_idx+radii+1)
start_col = 0 if (col_idx-radii) < 0 else (col_idx-radii)
end_col = row_len if (col_idx+radii+1) > row_len else (col_idx+radii+1)
neighbor = 0
for block_row_idx in np.arange(start_row, end_row):
for block_col_idx in np.arange(start_col, end_col):
neighbor += n2d_array[block_row_idx, block_col_idx]
nbrs_count[row_idx, col_idx] = neighbor - n2d_array[row_idx, col_idx]
return nbrs_count
I found out that my implementation is very slow compared to scipy.signal.convolve2d
:
def neighbors_count2(n2d_array, radii=1):
from scipy.signal import convolve2d
diameter = 2 * radii + 1
n2d_array = n2d_array.astype(bool)
nbrs_count = convolve2d(n2d_array, np.ones((diameter, diameter)),
mode='same', boundary='fill') - n2d_array
return nbrs_count
Here is %timeit
result in my computer:
%timeit -n 10 neighbors_count(np.random.randint(2, size=(100,100)))
10 loops, best of 3: 232 ms per loop
%timeit -n 10 neighbors_count2(np.random.randint(2, size=(100,100)))
10 loops, best of 3: 963 µs per loop
How to improve/vectorize my code so it can run faster than scipy.signal.convolve2d
?