Home > front end >  How to change the value of some m x m submatrices from an NxN matrix with numpy?
How to change the value of some m x m submatrices from an NxN matrix with numpy?

Time:12-06

The general problem I'm facing could be translated as follows:

Code a NxN matrix in which mxm sub-matrices of values x or y are regularly alternated.

For example, let's say I need to make a 6x6 matrix with 2x2 sub-matrices of 0 or 1 are alternated, the result should be the matrix below:

0 0 1 1 0 0 
0 0 1 1 0 0
1 1 0 0 1 1
1 1 0 0 1 1
0 0 1 1 0 0
0 0 1 1 0 0

For now, I only managed to get this:

0 0 1 0 0 0 
0 0 1 0 0 0 
1 1 0 0 0 0 
0 0 0 0 0 0
0 0 0 0 0 0 
0 0 0 0 0 0 

with the code :

b = numpy.zeros((6, 6))
b[:2, 2:6:4] = 1
b[2:6:4, :2] = 1
print(b)

I managed to find a solution but it has four for-loop so it is hard to read and takes a bit of time. The code for this possible answer is:

c = np.array([])    
for k in range(3):
    for l in range (2):
        for i in range(3):
            for j in range (2):
            
                if (k i)%2 == 0:
                    c = np.append(c, 0)
                else:
                    c = np.append(c, 1)
print("c = ", np.reshape(c, (6, 6)))

Isn't there a better way to give the expected output without using loops or with 1 or 2 loops max ?

CodePudding user response:

import numpy as np
m = 8 
n = 4

c = np.zeros(shape=(m,m))    
assert not m%n #m must be divisible by n
for row_i in range(m):
  for col_i in range(m):
    if (row_i//n   col_i//n)%2:
      c[row_i][col_i] = 1

print(c)
[[0. 0. 0. 0. 1. 1. 1. 1.]
 [0. 0. 0. 0. 1. 1. 1. 1.]
 [0. 0. 0. 0. 1. 1. 1. 1.]
 [0. 0. 0. 0. 1. 1. 1. 1.]
 [1. 1. 1. 1. 0. 0. 0. 0.]
 [1. 1. 1. 1. 0. 0. 0. 0.]
 [1. 1. 1. 1. 0. 0. 0. 0.]
 [1. 1. 1. 1. 0. 0. 0. 0.]]

CodePudding user response:

I think you're on the right track with using python array slicing. Here is an example for 2x2 submatrices (works with any even-square sized matrix b).

# first block for submatrices starting at column and row index 0

# 0::4 - every 4th column/row starting from column 0
# so this results in 1 0 0 0 1 0 and so on
b[0::4, 0::4] = 1

# 1::4 - every 4th column starting from column 1
# so this results in 0 1 0 0 0 1 and so on
b[0::4, 1::4] = 1

b[1::4, 0::4] = 1
b[1::4, 1::4] = 1

# second block for submatrices starting from column and row index 2 
b[2::4, 2::4] = 1
b[2::4, 3::4] = 1
b[3::4, 2::4] = 1
b[3::4, 3::4] = 1

Now for larger submatrices you have just to increase the distance between the entries. For submatrices of size n, the distance must be 2 * n, because that is the sheme for the repetition of 1 in the matrix. Each block then has size n. Try to write a procedure. If you do not succeed I will help further.

CodePudding user response:

I cut down your for-loop to 2:

def create_mxm_from_NxN(N,m):
    """N has to be divisible by m"""
    b = np.zeros((N,N))
    skip = N // m
    for i in range(0,N 1,m):
        for s in range(1,skip 1,2):
            b[i:i m, i s*m:i (s 1)*m] = 1
            b[i s*m:i (s 1)*m, i:i m] = 1
    return b.astype(int)

Output:

create_mxm_from_NxN(6,2)

[[0 0 1 1 0 0]
 [0 0 1 1 0 0]
 [1 1 0 0 1 1]
 [1 1 0 0 1 1]
 [0 0 1 1 0 0]
 [0 0 1 1 0 0]]


create_mxm_from_NxN(9,3)

[[0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0]
 [1 1 1 0 0 0 1 1 1]
 [1 1 1 0 0 0 1 1 1]
 [1 1 1 0 0 0 1 1 1]
 [0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0]]
  • Related