user17539312
user17539312

Reputation:

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

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 ?

Upvotes: 0

Views: 299

Answers (4)

Nils Werner
Nils Werner

Reputation: 36775

The most simple solution is probably to use skimage.util.view_as_blocks():

import numpy as np
import skimage.util

a = np.zeros((6, 6))
b = skimage.util.view_as_blocks(a, (2, 2))
# b is a view of a, so changing values in b will also change values in a
b[::2, ::2, ...] = 1
b[1::2, 1::2, ...] = 1

a
# array([[1., 1., 0., 0., 1., 1.],
#        [1., 1., 0., 0., 1., 1.],
#        [0., 0., 1., 1., 0., 0.],
#        [0., 0., 1., 1., 0., 0.],
#        [1., 1., 0., 0., 1., 1.],
#        [1., 1., 0., 0., 1., 1.]])

Upvotes: 0

hilberts_drinking_problem
hilberts_drinking_problem

Reputation: 11602

Here is one take using np.repeat and np.tile:

import numpy as np

def tiled_matrix(n, m):
  row = np.tile(np.repeat([1, 0], m), (n // m) // 2 + 1)[:n]
  row_block = np.tile(row, (m,1))
  two_rows_block = np.vstack((row_block, 1 - row_block))
  arr = np.tile(two_rows_block, ((n // m) // 2 + 1, 1))[:n]
  return arr

print(tiled_matrix(10, 4))
# [[1 1 1 1 0 0 0 0 1 1]
#  [1 1 1 1 0 0 0 0 1 1]
#  [1 1 1 1 0 0 0 0 1 1]
#  [1 1 1 1 0 0 0 0 1 1]
#  [0 0 0 0 1 1 1 1 0 0]
#  [0 0 0 0 1 1 1 1 0 0]
#  [0 0 0 0 1 1 1 1 0 0]
#  [0 0 0 0 1 1 1 1 0 0]
#  [1 1 1 1 0 0 0 0 1 1]
#  [1 1 1 1 0 0 0 0 1 1]]

Here is another take with np.meshgrid and xor:

def meshgrid_mod(n, m):
  ix = np.arange(n, dtype=np.uint8)
  xs, ys = np.meshgrid(ix, ix)
  arr = ((xs % (2*m)) < m) ^ ((ys % (2*m)) < m)
  return arr.astype(np.int)

Upvotes: 0

Lord Bo
Lord Bo

Reputation: 3308

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.

Upvotes: 0

adrianop01
adrianop01

Reputation: 600

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.]]

Upvotes: 1

Related Questions