确定具有周期性条件的二维网格中的相邻单元格
Determine neighboring cells in a two-dimensional grid with periodic conditions
假设我们有以下二维网络,我们用整数标记其单元格索引:
20 21 22 23 24
15 16 17 18 19
10 11 12 13 14
5 6 7 8 9
0 1 2 3 4
我想要的是一个函数,它接收单元格索引 (cell) 和沿轴的单元格数量(在本例中为 n=5),以及 returns 具有 9 个邻居的数组(包括单元格本身),考虑到全局框的周期性。
我向您展示了我尝试过的方法,'almost' 有效:
def celdas_vecinas(cell,n):
return np.mod(cell + np.array([0, -n-1, -n, -n+1, -1, 1, n-1, n, n+1], dtype=np.int64), n**2)
我在其中输入 np.mod 以反映周期性条件。关键是这个函数只对某些值表现良好。
>>> celdas_vecinas(1,5)
array([ 1, 20, 21, 22, 0, 2, 5, 6, 7]) # right!
>>> celdas_vecinas(21,5)
array([21, 15, 16, 17, 20, 22, 0, 1, 2]) # right!
但是如果我在角落输入其中一个单元格的索引,会发生以下情况:
>>> celdas_vecinas(0,5)
array([ 0, 19, 20, 21, 24, 1, 4, 5, 6]) # should be 9 instead of 19
例如 cell=5 也失败。
有谁知道如何实现这个功能?当单元格索引不触及任何边界时,它很容易实现,但我不知道如何包括周期性影响,虽然我猜它一定与 np.mod 函数有关
Numpy 实现 可以利用 numpy.argwhere to retrieve value indeces, create the grid of indices with numpy.ix_, and finally apply numpy.narray.ravel 方法来展平数组::
import numpy as np
n = 5
grid = np.arange(n**2).reshape(n,n)[::-1]
def celdas_vecinas_np(grid, v, n):
x, y = np.argwhere(grid == v)[0]
idx = np.arange(x-1, x+2) %n
idy = np.arange(y-1, y+2) %n
return grid[np.ix_(idx, idy)].ravel()
celdas_vecinas_np(grid, 24, n)
array([ 3, 4, 0, 23, 24, 20, 18, 19, 15])
另一方面,对于 Numba 实现,我们不能使用 numpy.argwhere
,但我们可以使用 numpy.where 来获取索引。一旦我们这样做了,这只是在正确的范围内循环的问题,即:
from numba import njit
@njit
def celdas_vecinas_numba(grid, v, n):
x, y = np.where(grid == v)
x, y = x[0], y[0]
result = []
for ix in range(x-1, x+2):
for iy in range(y-1, y+2):
result.append(grid[ix%n, iy%n])
return result
celdas_vecinas_numba(grid, 24, n)
[3, 4, 0, 23, 24, 20, 18, 19, 15]
性能比较 如此小的网格 numba 在我的本地机器上运行速度已经快了约 20 倍:
%timeit celdas_vecinas_np(grid, 24, 5)
38 µs ± 1.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit celdas_vecinas_numba(grid, 24, n)
1.81 µs ± 93.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
行周期不像列周期那样工作。我认为你应该先在每一侧获得 2 个单元格,然后上下移动。我已经试过了,它似乎有效:
def celdas_vecinas(cell, n) :
last_row = n * (cell // n)
left_cell = last_row + ( cell - last_row - 1 ) % n
right_cell = last_row + ( cell - last_row + 1 ) % n
line = np.array( [ left_cell, cell, right_cell ] )
return np.mod( [ line + n, line, line - n ], n**2)
(我删除了之前的答案,因为我搞砸了 indeces)
试试这个:
grid = [[20, 21, 22, 23, 24],[15, 16, 17, 18, 19],[10, 11, 12, 13, 14],[5, 6, 7, 8, 9],[0, 1, 2, 3, 4]]
def celdas_vecinas(cell,n):
Row = [-1, -1, -1, 0, 0, 0, 1, 1, 1]
Col = [-1, 0, 1, -1, 0, 1, -1, 0, 1]
x = y = 0
for i in range(n):
z = 0;
for j in range(n):
if grid[i][j] == cell:
x = i
y = j
z = 1
break
if z:
break
ans = []
for i in range(9):
xx = (n + x + Row[i]) % n
yy = (n + y + Col[i]) % n
ans.append(grid[xx][yy])
return ans;
print(celdas_vecinas(1,5))
print(celdas_vecinas(21,5))
print(celdas_vecinas(5,5))
根据 Comevussor 的回答,我得到了以下代码:
@nb.njit(nb.i8[:](nb.i8, nb.i8), fastmath=True)
def celdas_vecinas(cell,n):
Nt = n**2 # total number of cells
x = cell % n; y = cell // n # x,y cell coordinates
izq = (x - 1) % n + y * n
der = (x + 1) % n + y * n
arri = (x % n + (y+1) * n) % Nt
aba = (x % n + (y-1) * n) % Nt
aba_izq = (izq - n) % Nt
aba_der = (der - n) % Nt
arri_izq = (izq + n) % Nt
arri_der = (der + n) % Nt
return np.array([cell, aba_izq, aba, aba_der, izq, der, arri_izq, arri, arri_der])
适用于以下性能:
>>> %timeit celdas_vecinas(0,5)
567 ns ± 13.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
假设我们有以下二维网络,我们用整数标记其单元格索引:
20 21 22 23 24
15 16 17 18 19
10 11 12 13 14
5 6 7 8 9
0 1 2 3 4
我想要的是一个函数,它接收单元格索引 (cell) 和沿轴的单元格数量(在本例中为 n=5),以及 returns 具有 9 个邻居的数组(包括单元格本身),考虑到全局框的周期性。
我向您展示了我尝试过的方法,'almost' 有效:
def celdas_vecinas(cell,n):
return np.mod(cell + np.array([0, -n-1, -n, -n+1, -1, 1, n-1, n, n+1], dtype=np.int64), n**2)
我在其中输入 np.mod 以反映周期性条件。关键是这个函数只对某些值表现良好。
>>> celdas_vecinas(1,5)
array([ 1, 20, 21, 22, 0, 2, 5, 6, 7]) # right!
>>> celdas_vecinas(21,5)
array([21, 15, 16, 17, 20, 22, 0, 1, 2]) # right!
但是如果我在角落输入其中一个单元格的索引,会发生以下情况:
>>> celdas_vecinas(0,5)
array([ 0, 19, 20, 21, 24, 1, 4, 5, 6]) # should be 9 instead of 19
例如 cell=5 也失败。
有谁知道如何实现这个功能?当单元格索引不触及任何边界时,它很容易实现,但我不知道如何包括周期性影响,虽然我猜它一定与 np.mod 函数有关
Numpy 实现 可以利用 numpy.argwhere to retrieve value indeces, create the grid of indices with numpy.ix_, and finally apply numpy.narray.ravel 方法来展平数组::
import numpy as np
n = 5
grid = np.arange(n**2).reshape(n,n)[::-1]
def celdas_vecinas_np(grid, v, n):
x, y = np.argwhere(grid == v)[0]
idx = np.arange(x-1, x+2) %n
idy = np.arange(y-1, y+2) %n
return grid[np.ix_(idx, idy)].ravel()
celdas_vecinas_np(grid, 24, n)
array([ 3, 4, 0, 23, 24, 20, 18, 19, 15])
另一方面,对于 Numba 实现,我们不能使用 numpy.argwhere
,但我们可以使用 numpy.where 来获取索引。一旦我们这样做了,这只是在正确的范围内循环的问题,即:
from numba import njit
@njit
def celdas_vecinas_numba(grid, v, n):
x, y = np.where(grid == v)
x, y = x[0], y[0]
result = []
for ix in range(x-1, x+2):
for iy in range(y-1, y+2):
result.append(grid[ix%n, iy%n])
return result
celdas_vecinas_numba(grid, 24, n)
[3, 4, 0, 23, 24, 20, 18, 19, 15]
性能比较 如此小的网格 numba 在我的本地机器上运行速度已经快了约 20 倍:
%timeit celdas_vecinas_np(grid, 24, 5)
38 µs ± 1.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit celdas_vecinas_numba(grid, 24, n)
1.81 µs ± 93.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
行周期不像列周期那样工作。我认为你应该先在每一侧获得 2 个单元格,然后上下移动。我已经试过了,它似乎有效:
def celdas_vecinas(cell, n) :
last_row = n * (cell // n)
left_cell = last_row + ( cell - last_row - 1 ) % n
right_cell = last_row + ( cell - last_row + 1 ) % n
line = np.array( [ left_cell, cell, right_cell ] )
return np.mod( [ line + n, line, line - n ], n**2)
(我删除了之前的答案,因为我搞砸了 indeces)
试试这个:
grid = [[20, 21, 22, 23, 24],[15, 16, 17, 18, 19],[10, 11, 12, 13, 14],[5, 6, 7, 8, 9],[0, 1, 2, 3, 4]]
def celdas_vecinas(cell,n):
Row = [-1, -1, -1, 0, 0, 0, 1, 1, 1]
Col = [-1, 0, 1, -1, 0, 1, -1, 0, 1]
x = y = 0
for i in range(n):
z = 0;
for j in range(n):
if grid[i][j] == cell:
x = i
y = j
z = 1
break
if z:
break
ans = []
for i in range(9):
xx = (n + x + Row[i]) % n
yy = (n + y + Col[i]) % n
ans.append(grid[xx][yy])
return ans;
print(celdas_vecinas(1,5))
print(celdas_vecinas(21,5))
print(celdas_vecinas(5,5))
根据 Comevussor 的回答,我得到了以下代码:
@nb.njit(nb.i8[:](nb.i8, nb.i8), fastmath=True)
def celdas_vecinas(cell,n):
Nt = n**2 # total number of cells
x = cell % n; y = cell // n # x,y cell coordinates
izq = (x - 1) % n + y * n
der = (x + 1) % n + y * n
arri = (x % n + (y+1) * n) % Nt
aba = (x % n + (y-1) * n) % Nt
aba_izq = (izq - n) % Nt
aba_der = (der - n) % Nt
arri_izq = (izq + n) % Nt
arri_der = (der + n) % Nt
return np.array([cell, aba_izq, aba, aba_der, izq, der, arri_izq, arri, arri_der])
适用于以下性能:
>>> %timeit celdas_vecinas(0,5)
567 ns ± 13.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)