Inset a matrix of zeros across another matrix's diagonal

Viewed 55

Watered down example

Consider I have the following matrix A,

1  2  4  3
1  7  3  6
2  4  1  1
6  9  3  6

I would want to convert it to the matrix B which looks like,

0  0  4  4
0  0  3  6
2  4  0  0
6  9  0  0

So basically I would want to have, let's say a 2x2 matrix of zeros in the diagonal of the 4x4 matrix given above.

Need for a general solution

What i have provided above is just an example and I am going to use (1296, 1296) sized matrix as input and I want to inset a 3x3 matrix of zeros inside its diagonal.

What I have done so far?

A simple range based loop and then setting values to zero like so,

for i in range(0, mat.shape[0] - 1, 3):
    mat[i][i] = 0
    mat[i][i + 1] = 0
    mat[i][i + 2] = 0
    mat[i + 1][i] = 0
    mat[i + 1][i + 1] = 0
    mat[i + 1][i + 2] = 0
    mat[i + 2][i] = 0
    mat[i + 2][i + 1] = 0
    mat[i + 2][i + 2] = 0

I completely understand that this is a very crude and nasty way to do it. Please suggest a fast and "numpy" way of doing this.

3 Answers

You could try something like this:

start=0
stop=1296
step=3
for i in np.arange(start=start, stop=stop, step=step):
    mat[i:i+step, i:i+step] = 0

Here is a loop free solution:

mat = np.ones((12,12))
np.einsum('ijik->ijk',mat.reshape((4,3,4,3)))[...] = 0
mat
# array([[0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
#        [0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
#        [0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
#        [1., 1., 1., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
#        [1., 1., 1., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
#        [1., 1., 1., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
#        [1., 1., 1., 1., 1., 1., 0., 0., 0., 1., 1., 1.],
#        [1., 1., 1., 1., 1., 1., 0., 0., 0., 1., 1., 1.],
#        [1., 1., 1., 1., 1., 1., 0., 0., 0., 1., 1., 1.],
#        [1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
#        [1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
#        [1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0.]])

This should fix it:

your_matrix = [
    [1, 2, 4, 3],
    [1, 7, 3, 6],
    [2, 4, 1, 1],
    [6, 9, 3, 6]
]

def calculate(matrix, x, y, size):
    for index, x_row in enumerate(matrix):
        for add in range(size):
            if index == y+add:
                for add_2 in range(size):
                    x_row[x+add_2] = 0

    return matrix


your_matrix = calculate(matrix=your_matrix, x=1, y=1, size=2)
print(your_matrix)

The x, y is on the left top corner of your 0 box and the size is how big you want your box.

Related