Change block order of a binary diagonal matrix

Viewed 82

I have the following binary matrix (numpy array):

M = np.array([[1, 1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0]])

In practice, it has two triangles on the diagonal. I would like to reverse the blocks of the matrix, so that the two triangles appear on the other diagonal, but keeping the same shape:

M = np.array([[0, 0, 1, 1], [0, 0, 1, 0], [1, 1, 0, 0], [1, 0, 0, 0]])

I have tried using a Dataframe with sort_index() and the possible combinations of axis and ascending but none of them worked.

How can I do that?

I need a general code, which works also for bigger matrices that have these triangular structures on the diagonal.

Visually, I would like to go from: enter image description here to: enter image description here

3 Answers

Just slice the second axis in reverse: M[:, ::-1]

output:

array([[0, 0, 1, 1],
       [0, 0, 0, 1],
       [1, 1, 0, 0],
       [0, 1, 0, 0]])

NB. to give an explicit example, this shifts from:

array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

to:

array([[ 3,  2,  1,  0],
       [ 7,  6,  5,  4],
       [11, 10,  9,  8],
       [15, 14, 13, 12]])

You need to inject an additional dimension to reverse, temporarily. For this you have to know the size (or the number) of triangles along an axis:

import numpy as np

# generate dummy input with 3 triangles of size 2
tri = np.array([[1, 1], [1, 0]])
zero = np.zeros_like(tri)
arr = np.block([[tri, zero, zero], [zero, tri, zero], [zero, zero, tri]])
# alternatively: arr = np.kron(np.eye(3), tri)

tri_size = tri.shape[0]
res = arr.reshape(-1, tri_size, arr.shape[-1])[::-1, ...].reshape(arr.shape)

Input above:

array([[1, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0],
       [0, 0, 1, 1, 0, 0],
       [0, 0, 1, 0, 0, 0],
       [0, 0, 0, 0, 1, 1],
       [0, 0, 0, 0, 1, 0]])

Output:

array([[0, 0, 0, 0, 1, 1],
       [0, 0, 0, 0, 1, 0],
       [0, 0, 1, 1, 0, 0],
       [0, 0, 1, 0, 0, 0],
       [1, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0]])

The auxiliary array is shaped (num_triangles, triangle_size, second_dim) if the original array is shaped (num_triangles * triangle_size, second_dim).

Try using numpy.roll

import numpy as np
M = np.array([[1, 1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 0]])
M = np.roll(M,2,axis=1) # Axis 1 for row wise
print(M)
>>> array([
       [0, 0, 1, 1],
       [0, 0, 1, 0],
       [1, 1, 0, 0],
       [1, 0, 0, 0]])
Related