# Find elements surrounding an element in 2D tensor

Hello

Suppose I have the following 2D tensor

`````` [[20, 29,  9,  7, 31, 35]],

[[ 9, 23, 30,  5,  2, 31]],

[[ 6, 27, 19,  5, 30,  7]],

[[29,  4, 36,  2, 20, 27]],

[[32,  2, 38, 10, 35,  1]],

[[27, 40, 13, 10, 20,  3]],

[[ 6, 20, 30,  7, 40, 39]]
``````

I would like to create a new tensor, which will have the shape (…original_shape…,4)
And will contain the 4 surrounding neighbors of each element, with a special index to the border.
The directions will be “hard coded” (top,right,down,left)
For example,

``````new_tensor[0,0,:] = [[[
BORDER,29,BORDER,BORDER
]]]
``````

I thought on 2 options:

• Create `surround` function that will return the 4 surrounding elements (including BORDER in the right places) and run it on all tensor elements, and then build a new tensor from the results. But, as you may think, this is not the most efficient thing to do…

• Use other tools, scatter / gather / others

Do you have any recommendation?

Thanks
Tankwell

Hi Tankwell!

Pad your input tensor with your special “border value” and then run `conv2d()`
with the appropriately constructed kernel:

``````>>> import torch
>>> print (torch.__version__)
1.12.0
>>>
>>> t = torch.tensor ([[20, 29,  9,  7, 31, 35],
...                    [ 9, 23, 30,  5,  2, 31],
...                    [ 6, 27, 19,  5, 30,  7],
...                    [29,  4, 36,  2, 20, 27],
...                    [32,  2, 38, 10, 35,  1],
...                    [27, 40, 13, 10, 20,  3],
...                    [ 6, 20, 30,  7, 40, 39]],
...                   dtype = torch.float)
>>>
>>> border_value = -99.0
>>>
>>> # build convolution kernel
>>> kernel = torch.zeros (4, 1, 3, 3)
>>> kernel[0, 0, 0, 1] = 1.0   # top
>>> kernel[1, 0, 1, 2] = 1.0   # right
>>> kernel[2, 0, 2, 1] = 1.0   # down
>>> kernel[3, 0, 1, 0] = 1.0   # left
>>>
>>> tpad = torch.nn.functional.pad (t, (1, 1, 1, 1), mode = 'constant', value = border_value)
>>> tsur = torch.nn.functional.conv2d (tpad.unsqueeze (0), kernel).permute (1, 2, 0)
>>>
>>> tsur.shape
torch.Size([7, 6, 4])
>>> tsur[0, 0, :]
tensor([-99.,  29.,   9., -99.])
>>> tsur
tensor([[[-99.,  29.,   9., -99.],
[-99.,   9.,  23.,  20.],
[-99.,   7.,  30.,  29.],
[-99.,  31.,   5.,   9.],
[-99.,  35.,   2.,   7.],
[-99., -99.,  31.,  31.]],

[[ 20.,  23.,   6., -99.],
[ 29.,  30.,  27.,   9.],
[  9.,   5.,  19.,  23.],
[  7.,   2.,   5.,  30.],
[ 31.,  31.,  30.,   5.],
[ 35., -99.,   7.,   2.]],

[[  9.,  27.,  29., -99.],
[ 23.,  19.,   4.,   6.],
[ 30.,   5.,  36.,  27.],
[  5.,  30.,   2.,  19.],
[  2.,   7.,  20.,   5.],
[ 31., -99.,  27.,  30.]],

[[  6.,   4.,  32., -99.],
[ 27.,  36.,   2.,  29.],
[ 19.,   2.,  38.,   4.],
[  5.,  20.,  10.,  36.],
[ 30.,  27.,  35.,   2.],
[  7., -99.,   1.,  20.]],

[[ 29.,   2.,  27., -99.],
[  4.,  38.,  40.,  32.],
[ 36.,  10.,  13.,   2.],
[  2.,  35.,  10.,  38.],
[ 20.,   1.,  20.,  10.],
[ 27., -99.,   3.,  35.]],

[[ 32.,  40.,   6., -99.],
[  2.,  13.,  20.,  27.],
[ 38.,  10.,  30.,  40.],
[ 10.,  20.,   7.,  13.],
[ 35.,   3.,  40.,  10.],
[  1., -99.,  39.,  20.]],

[[ 27.,  20., -99., -99.],
[ 40.,  30., -99.,   6.],
[ 13.,   7., -99.,  20.],
[ 10.,  40., -99.,  30.],
[ 20.,  39., -99.,   7.],
[  3., -99., -99.,  40.]]])
``````

(If you can live with `0.0` as your special border value, you can avoid
the cost in time and memory of constructing `tpad` by using `Conv2d` with
`padding_mode = 'zeros'`.)

Best.

K. Frank

Hey,
Tha’ts relly helped!

Actually I have to select some of the centers and not all of them.
I have 2 ways to do that:

1. Add them to the surround tensor above by 5 nonzero elements [add (1,1)] in the kernel, and looking for that value later
2. Use the original 2D tensor to find [for each sample] the i,j location of the `argument` passed (the value we are looking for). After, searching in that location on `surr`

The thing is that I have to locate a value in a 2D tensor on each sample in the batch…seems to be not so efficient