I want to get the upper "corner" or hypertriangle of a fully symmetric numpy nd array. In other words, i want to slice the array along all its diagonals (with optional offset) and take only the remaining triangle.
# with a 3d array and 0 offset,
a = np.arange(5)
arr=a[:,None,None] a[None,:,None] a[None,None,:]
upper_corner(arr,offset=0)
Expected output:
array([[[ 0, 1, 2, 3, 4],
[ 0, 2, 3, 4, 5],
[ 0, 0, 4, 5, 6],
[ 0, 0, 0, 6, 7],
[ 0, 0, 0, 0, 8]],
[[ 0, 2, 3, 4, 5],
[ 0, 0, 4, 5, 6],
[ 0, 0, 0, 6, 7],
[ 0, 0, 0, 0, 8],
[ 0, 0, 0, 0, 0]],
[[ 0, 0, 4, 5, 6],
[ 0, 0, 0, 6, 7],
[ 0, 0, 0, 0, 8],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0]],
[[ 0, 0, 0, 6, 7],
[ 0, 0, 0, 0, 8],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0]],
[[ 0, 0, 0, 0, 8],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0]]])
Is there an indexing or slicing solution for this in n-dimensions?
CodePudding user response:
np.triu (triangle upper) can almost do this in one go:
>>> np.triu(arr)
array([[[ 0, 1, 2, 3, 4],
[ 0, 2, 3, 4, 5],
[ 0, 0, 4, 5, 6],
[ 0, 0, 0, 6, 7],
[ 0, 0, 0, 0, 8]],
[[ 1, 2, 3, 4, 5],
[ 0, 3, 4, 5, 6],
[ 0, 0, 5, 6, 7],
[ 0, 0, 0, 7, 8],
[ 0, 0, 0, 0, 9]],
[[ 2, 3, 4, 5, 6],
[ 0, 4, 5, 6, 7],
[ 0, 0, 6, 7, 8],
[ 0, 0, 0, 8, 9],
[ 0, 0, 0, 0, 10]],
[[ 3, 4, 5, 6, 7],
[ 0, 5, 6, 7, 8],
[ 0, 0, 7, 8, 9],
[ 0, 0, 0, 9, 10],
[ 0, 0, 0, 0, 11]],
[[ 4, 5, 6, 7, 8],
[ 0, 6, 7, 8, 9],
[ 0, 0, 8, 9, 10],
[ 0, 0, 0, 10, 11],
[ 0, 0, 0, 0, 12]]])
But since you seem to want the triangle to move incrementally each time, you can generate an appropriate mask like this:
mask = np.array([np.triu(np.ones(arr.shape[1:], dtype=int), i) for i in range(arr.shape[0])])
and then multiply the original array by the mask:
>>> corners = arr * mask
>>> corners
array([[[0, 1, 2, 3, 4],
[0, 2, 3, 4, 5],
[0, 0, 4, 5, 6],
[0, 0, 0, 6, 7],
[0, 0, 0, 0, 8]],
[[0, 2, 3, 4, 5],
[0, 0, 4, 5, 6],
[0, 0, 0, 6, 7],
[0, 0, 0, 0, 8],
[0, 0, 0, 0, 0]],
[[0, 0, 4, 5, 6],
[0, 0, 0, 6, 7],
[0, 0, 0, 0, 8],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 6, 7],
[0, 0, 0, 0, 8],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 8],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]])
CodePudding user response:
You can try the following:
import numpy as np
arr = np.arange(4**3).reshape(4, 4, 4)
print(arr)
It gives:
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
[[16 17 18 19]
[20 21 22 23]
[24 25 26 27]
[28 29 30 31]]
[[32 33 34 35]
[36 37 38 39]
[40 41 42 43]
[44 45 46 47]]
[[48 49 50 51]
[52 53 54 55]
[56 57 58 59]
[60 61 62 63]]]
Get the corner:
x, y, z = np.ogrid[0:arr.shape[0], 0:arr.shape[1], 0:arr.shape[2]]
arr[x - z y > 0] = 0
print(arr)
Result:
[[[ 0 1 2 3]
[ 0 5 6 7]
[ 0 0 10 11]
[ 0 0 0 15]]
[[ 0 17 18 19]
[ 0 0 22 23]
[ 0 0 0 27]
[ 0 0 0 0]]
[[ 0 0 34 35]
[ 0 0 0 39]
[ 0 0 0 0]
[ 0 0 0 0]]
[[ 0 0 0 51]
[ 0 0 0 0]
[ 0 0 0 0]
[ 0 0 0 0]]]
