Reputation:
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
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
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
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
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