通常情况下,您希望在不满足矩形数组要求的情况下在链接列表上实现数组的性能。
作为一个例子,考虑一个六角形网格,这里显示的单元格(3,3)的1个距离的邻居为中灰色,而2个距离的邻居为浅灰色。 假设我们想要一个包含每个单元格的数组,该数组包含该单元格每个1和2距离邻居的索引。一个小问题是,单元格具有不同数量的X距离邻居-与靠近网格中心的单元格相比,网格边界上的单元格更少。
(出于性能原因,我们需要一个邻居索引的数组---而不是从像元坐标到邻居索引的函数---)
我们可以通过跟踪每个单元格有多少个邻居来解决此问题。说你有一个数组
大小为neighbors2
的{{1}},其中R x C x N x 2
是网格行数,R
是列,C
是最大2距离邻居数网格中的任何单元。
然后,通过保留大小为N
的附加数组n_neighbors2
,我们可以跟踪填充了R x C
中的哪些索引以及哪些填充为零。例如,要检索像元(2,5)的2距离邻居,我们只需将数组索引如下:
neighbors2
someNeigh = neighbors2[2, 5, 0..n_neighbors2[2, 5], ..]
将是索引的someNeigh
数组(或视图),其中n_neighbors2[2, 5] x 2
产生第一个邻居的行,someNeigh[0, 0]
产生第一个邻居的列邻居等等。
请注意,位置
someNeigh[0, 1]
无关紧要;这个空间只是填充以使矩阵保持矩形。
提供了一个用于查找任何单元的d距离邻居的函数:
neighbors2[2, 5, n_neighbors2[2, 5]+1.., ..]
我们如何创建上述数组import Data.Bits (shift)
rows, cols = (7, 7)
type Cell = (Int, Int)
generateNeighs :: Int -> Cell -> [Cell]
generateNeighs d cell1 = [ (row2, col2)
| row2 <- [0..rows-1]
, col2 <- [0..cols-1]
, hexDistance cell1 (row2, col2) == d]
hexDistance :: Cell -> Cell -> Int
hexDistance (r1, c1) (r2, c2) = shift (abs rd + abs (rd + cd) + abs cd) (-1)
where
rd = r1 - r2
cd = c1 - c2
和neighbors2
?假设我们事先知道2距离邻居n_neighbors2
的最大数量。然后可以修改N
以始终返回相同大小的列表,因为我们可以用(0,0)填充其余条目。在我看来,这留下了两个问题:
generateNeighs
的函数,该函数不是对每个索引都进行操作,而是对一个分片进行操作,在我们的情况下,它应该一次填充一个单元格。neighbors2
应该同时填充为n_neighbors2
欢迎使用neighbors2
或repa
数组的解决方案。
答案 0 :(得分:2)
这是您的图片向右倾斜30度:
您可以看到您的数组实际上是完美的矩形。
在选定的中心单元格周围很容易找到六个周围的周边指数,例如(想象中的import tensorflow as tf
import tf_metrics
y_true = [0, 1, 0, 0, 0, 2, 3, 0, 0, 1]
y_pred = [0, 1, 0, 0, 1, 2, 0, 3, 3, 1]
pos_indices = [1] # Metrics for class 1 -- or
pos_indices = [1, 2, 3] # Average metrics, 0 is the 'negative' class
num_classes = 4
average = 'micro'
# Tuple of (value, update_op)
precision = tf_metrics.precision(
y_true, y_pred, num_classes, pos_indices, average=average)
recall = tf_metrics.recall(
y_true, y_pred, num_classes, pos_indices, average=average)
f2 = tf_metrics.fbeta(
y_true, y_pred, num_classes, pos_indices, average=average, beta=2)
f1 = tf_metrics.f1(
y_true, y_pred, num_classes, pos_indices, average=average)
是图片中边缘到中心n == 2
的距离):
(i,j) == (3,3)
整个街区都很简单
periphery n (i,j) =
-- 2 (3,3)
let
((i1,j1):ps1) = reverse . take (n+1) . iterate (\(i,j)->(i,j+1)) $ (i-n,j)
-- ( 1, 3)
((i2,j2):ps2) = reverse . take (n+1) . iterate (\(i,j)->(i+1,j)) $ (i1,j1)
-- ( 1, 5)
.....
ps6 = ....... $ (i5,j5)
in filter isValid (ps6 ++ ... ++ ps2 ++ ps1)
对于每个像元/距离组合,只需快速生成邻域索引,并在每个索引对的 O(1)时间访问您的数组即可。
答案 1 :(得分:2)
完整地写出@WillNess的答案,并结合@leftroundabout的建议,将指数存储在一维向量中,我们得到了:
import qualified Data.Array.Accelerate as A
import Data.Array.Accelerate (Acc, Array, DIM1, DIM2, DIM3, Z(..), (:.)(..), (!), fromList, use)
rows = 7
cols = 7
type Cell = (Int, Int)
(neighs, nNeighs) = generateNeighs
-- Return a vector of indices of cells at distance 'd' or less from the given cell
getNeighs :: Int -> Cell -> Acc (Array DIM1 Cell)
getNeighs d (r,c) = A.take n $ A.drop start neighs
where
start = nNeighs ! A.constant (Z :. r :. c :. 0)
n = nNeighs ! A.constant (Z :. r :. c :. d)
generateNeighs :: (Acc (Array DIM1 Cell), Acc (Array DIM3 Int))
generateNeighs = (neighsArr, nNeighsArr)
where
idxs = concat [[(r, c) | c <- [0..cols-1]] | r <- [0..rows-1]]
(neighsLi, nNeighsLi, n) = foldl inner ([], [], 0) idxs
neighsArr = use $ fromList (Z :. n) neighsLi
nNeighsArr = use $ fromList (Z :. rows :. cols :. 5) nNeighsLi
inner (neighs', nNeighs', n') idx = (neighs' ++ cellNeighs, nNeighs'', n'')
where
(cellNeighs, cellNNeighs) = neighborhood idx
n'' = n' + length cellNeighs
nNeighs'' = nNeighs' ++ n' : cellNNeighs
neighborhood :: Cell -> ([Cell], [Int])
neighborhood (r,c) = (neighs, nNeighs)
where
neighsO = [ periphery d (r,c) | d <- [1..4] ]
neighs = (r,c) : concat neighsO
nNeighs = tail $ scanl (+) 1 $ map length neighsO
periphery d (r,c) =
-- The set of d-distance neighbors form a hexagon shape. Traverse each of
-- the sides of this hexagon and gather up the cell indices.
let
ps1 = take d . iterate (\(r,c)->(r,c+1)) $ (r-d,c)
ps2 = take d . iterate (\(r,c)->(r+1,c)) $ (r-d,c+d)
ps3 = take d . iterate (\(r,c)->(r+1,c-1)) $ (r,c+d)
ps4 = take d . iterate (\(r,c)->(r,c-1)) $ (r+d,c)
ps5 = take d . iterate (\(r,c)->(r-1,c)) $ (r+d,c-d)
ps6 = take d . iterate (\(r,c)->(r-1,c+1)) $ (r,c-d)
in filter isValid (ps6 ++ ps5 ++ ps4 ++ ps3 ++ ps2 ++ ps1)
isValid :: Cell -> Bool
isValid (r, c)
| r < 0 || r >= rows = False
| c < 0 || c >= cols = False
| otherwise = True
答案 2 :(得分:0)
这可以通过使用permute函数来一次填充1个单元格的邻居。
import Data.Bits (shift)
import Data.Array.Accelerate as A
import qualified Prelude as P
import Prelude hiding ((++), (==))
rows = 7
cols = 7
channels = 70
type Cell = (Int, Int)
(neighs, nNeighs) = fillNeighs
getNeighs :: Cell -> Acc (Array DIM1 Cell)
getNeighs (r, c) = A.take (nNeighs ! sh1) $ slice neighs sh2
where
sh1 = constant (Z :. r :. c)
sh2 = constant (Z :. r :. c :. All)
fillNeighs :: (Acc (Array DIM3 Cell), Acc (Array DIM2 Int))
fillNeighs = (neighs2, nNeighs2)
where
sh = constant (Z :. rows :. cols :. 18) :: Exp DIM3
neighZeros = fill sh (lift (0 :: Int, 0 :: Int)) :: Acc (Array DIM3 Cell)
-- nNeighZeros = fill (constant (Z :. rows :. cols)) 0 :: Acc (Array DIM2 Int)
(neighs2, nNeighs2li) = foldr inner (neighZeros, []) indices
nNeighs2 = use $ fromList (Z :. rows :. cols) nNeighs2li
-- Generate indices by varying column fastest. This assures that fromList, which fills
-- the array in row-major order, gets nNeighs in the correct order.
indices = foldr (\r acc -> foldr (\c acc2 -> (r, c):acc2 ) acc [0..cols-1]) [] [0..rows-1]
inner :: Cell
-> (Acc (Array DIM3 Cell), [Int])
-> (Acc (Array DIM3 Cell), [Int])
inner cell (neighs, nNeighs) = (newNeighs, n : nNeighs)
where
(newNeighs, n) = fillCell cell neighs
-- Given an cell and a 3D array to contain cell neighbors,
-- fill in the neighbors for the given cell
-- and return the number of neighbors filled in
fillCell :: Cell -> Acc (Array DIM3 Cell) -> (Acc (Array DIM3 Cell), Int)
fillCell (r, c) arr = (permute const arr indcomb neighs2arr, nNeighs)
where
(ra, ca) = (lift r, lift c) :: (Exp Int, Exp Int)
neighs2li = generateNeighs 2 (r, c)
nNeighs = P.length neighs2li
neighs2arr = use $ fromList (Z :. nNeighs) neighs2li
-- Traverse the 3rd dimension of the given cell
indcomb :: Exp DIM1 -> Exp DIM3
indcomb nsh = index3 ra ca (unindex1 nsh)
generateNeighs :: Int -> Cell -> [Cell]
generateNeighs d cell1 = [ (row2, col2)
| row2 <- [0..rows]
, col2 <- [0..cols]
, hexDistance cell1 (row2, col2) P.== d]
-- Manhattan distance between two cells in an hexagonal grid with an axial coordinate system
hexDistance :: Cell -> Cell -> Int
hexDistance (r1, c1) (r2, c2) = shift (abs rd + abs (rd + cd) + abs cd) (-1)
where
rd = r1 - r2
cd = c1 - c2