Numpy: Change values in numpy array by indexes and condition - python

I am new in numpy, and I am having troubles with simple managment of numpy arrays.
I am doing a task in which it said that loops has to be avoid as much as possible, and I need to edit the values of an array through another array of indexes.
indexes # [3, 16]
y # [0. 1. 1. 1. 0. 1. 0. 0. 0. 0. 1. 1. 1. 0. 1. 0. 0. 0. 1. 1.]
y[indexes] = 2 # [0. 1. 1. 2. 0. 1. 0. 0. 0. 0. 1. 1. 1. 0. 1. 0. 2. 0. 1. 1.]
But I don't need change the value simply by 2. I need make a conditional change. This what I have got, but I would need something like
y[indexes] = 0 if y[indexes] == 1 else 0
>>> [0. 1. 1. 0. 0. 1. 0. 0. 0. 0. 1. 1. 1. 0. 1. 0. 1. 0. 1. 1.]
And the line above should be the results.
This is the loop way answer, but I need a numpy way if exists:
for index in indexes:
y[index] = 1 if y[index] == 0 else 0
Thanks in advance.

I don't know if I understood your question. But I hope this helps you.
tip 01
import numpy as np
indexes = [1, 5, 7] # index list
y = np.array([9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]) #array example
y[indexes][2] #3rd(0,1,>>2<<) item of y array (1,5,>>7<<).
In this case it is y[7] equal 16.
tip 02
This can also be useful.
y = np.array([0,1,1,0,3,0,1,0,1,0])
y
array([0, 1, 1, 0, 3, 0, 1, 0, 1, 0])
np.where(y != 1, y, 0)
y
array([0, 0, 0, 0, 3, 0, 0, 0, 0, 0])

Related

Python numpy replacing values that are in certain pattern

I am trying to 'avoid walls' using an A* star (A-Star) algorithm.
My array look like this:
[1, 1, 1, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1, 1],
[1, 1, 0, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1, 1]
I can only walk on 0 (zeroes) and 1 (ones) are the walls.
I want my AI to walk on the center of the the path, assuming that there is enough room to walk. AI can walk diagonally.
for example instead of [1, 1, 1, 0, 0, 0, 1, 1, 1],(First array) since there is enough room not to block the path how can I replace it with [1, 1, 1, 1, 0, 1, 1, 1, 1],
Afterthought:
The optimal path here if we will walk on center is [4 3 2 2 3 4].
Also, what if we are given the shortest path possible for this case it
would be [3 3 3 3 4 4] if we are going from (3, 0) to (4, 5). If we
just don't want walls in our path like having a single element before
the wall, how can we arrive to [3 3 2 2 3 4] if we allow start and
finish to touch walls?
Edit:
Ali_Sh answer is what I am initially looking for and is the accepted answer.
If a be the main array, indices of the middle 0 in each row can be achieved by:
cond = np.where(a == 0)
unique = np.unique(cond[0], return_index=True, return_counts=True)
ind = unique[1] + unique[2] // 2
cols = cond[1][ind] # --> [4 3 2 2 3 4]
and it can be used to substitute 1 values in a ones array with the main array shape:
one = np.ones(shape=a.shape)
one[np.arange(len(one)), cols] = 0
which will:
[[1. 1. 1. 1. 0. 1. 1. 1. 1.]
[1. 1. 1. 0. 1. 1. 1. 1. 1.]
[1. 1. 0. 1. 1. 1. 1. 1. 1.]
[1. 1. 0. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 0. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 0. 1. 1. 1. 1.]]
Here's an example where it just finds all the values that are zero in each row and sets the path as the middle argument. If there was a row with two patches of zeros, this could run into trouble. In that case, you would need to make sure that the arguments above and below a zero patch are also zero patches.
I have used matplotlib here to visualize the path:
import matplotlib.pyplot as plt
p = []
A = [[1, 1, 1, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1, 1],
[1, 1, 0, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1, 1]]
for i in range(len(A)):
ptemp = []
for j in range(len(A[0])):
if A[i][j] == 0:
ptemp.append(j) # find all the zero values
p.append(ptemp[int(len(ptemp)/2)]) # set the path as the center zero value
print(p)
plt.imshow(A[::-1])
plt.plot(p[::-1],range(len(A)))
plt.show()
For the update section of the question, if we have another path for columns instead the optimal path that specified in my previous answer (e.g. [3 1 1 1 2 3] instead [4 3 2 2 3 4]), it can be applied just using:
cols = np.array([3, 1, 1, 1, 2, 3])
one = np.ones(shape=a.shape)
one[np.arange(len(one)), cols] = 0
# [[1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 0. 1. 1. 1. 1. 1. 1. 1.]
# [1. 0. 1. 1. 1. 1. 1. 1. 1.]
# [1. 0. 1. 1. 1. 1. 1. 1. 1.]
# [1. 1. 0. 1. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.]]
If we want the all paths other than boundaries, we could add the following codes to the previous answer codes:
if we don't fully walk on the center but just avoid 'near walls' path
just even 1 offset from the walls:
cols_min = cols - (unique[2] - 2) // 2
cols_max = cols + (unique[2] - 2) // 2
one[np.arange(len(one)), cols_min] = 0
one[np.arange(len(one)), cols_max] = 0
# [[1. 1. 1. 1. 0. 1. 1. 1. 1.]
# [1. 1. 0. 0. 0. 1. 1. 1. 1.]
# [1. 1. 0. 1. 1. 1. 1. 1. 1.]
# [1. 1. 0. 1. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 1. 1. 0. 1. 1. 1. 1.]]
For when we can touch the walls (here one of them) on the first and the last rows, we could add the following codes to the previous answer codes:
col_min_first = cols[0] - unique[2][0] // 2
col_min_last = cols[-1] - unique[2][-1] // 2
one[0, col_min_first:cols[0]] = 0
one[-1, col_min_last:cols[-1]] = 0
# [[1. 1. 1. 0. 0. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 0. 1. 1. 1. 1. 1. 1.]
# [1. 1. 0. 1. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 0. 1. 1. 1. 1.]]
And, finally, if we want to find the shortest path, we can achieve the goal by finding the column with maximum number of 0 in it, firstly, and then, find the nearest column index 0 to that column for where the column not contains 0:
ind_max = np.argmax(np.sum(a == 0, axis=0))
mask_rows = a[:, ind_max] != 0
mask_col_min = a[:, ind_max - 1] == 0
mask_col_max = a[:, ind_max + 1] == 0
ind_max = np.where(mask_rows & mask_col_min, ind_max - 1, ind_max)
ind_max = np.where(mask_rows & mask_col_max, ind_max + 1, ind_max)
one = np.ones(shape=a.shape)
one[np.arange(len(one)), ind_max] = 0
# [[1. 1. 1. 0. 1. 1. 1. 1. 1.] | a = np.array([[1, 1, 1, 0, 0, 0, 1, 1, 1], [[1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.] | [1, 0, 0, 0, 0, 0, 1, 1, 1], [1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.] | [0, 0, 0, 1, 1, 1, 1, 1, 1], --> [1. 1. 0. 1. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.] | [1, 0, 0, 0, 1, 1, 1, 1, 1], [1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.] | [1, 1, 0, 0, 0, 1, 1, 1, 1], [1. 1. 1. 0. 1. 1. 1. 1. 1.]
# [1. 1. 1. 0. 1. 1. 1. 1. 1.]] | [1, 1, 1, 0, 0, 0, 1, 1, 1]]) [1. 1. 1. 0. 1. 1. 1. 1. 1.]]

choosing 5 random numbers / coordinates on a grid in python

I need help with making this so I can convert a string into a number in a list, I have done this but if I wanted to do it this way I would have to wright a dictionary with 100 definitions which I do not want to do. The code is just to show what I found all ready. As you can see this would take 100 definitions if I were to do it this way.
x1 = [0,0,0,0,0,0,0,0,0,0]
x2 = [0,0,0,0,0,0,0,0,0,0]
x3 = [0,0,0,0,0,0,0,0,0,0]
x4 = [0,0,0,0,0,0,0,0,0,0]
x5 = [0,0,0,0,0,0,0,0,0,0]
x6 = [0,0,0,0,0,0,0,0,0,0]
x7 = [0,0,0,0,0,0,0,0,0,0]
x8 = [0,0,0,0,0,0,0,0,0,0]
x9 = [0,0,0,0,0,0,0,0,0,0]
x10 = [0,0,0,0,0,0,0,0,0,0]
my_dict_grid = {
'x2[3]' : x2[3]
}
x = 'x2[3]'
print(my_dict_grid[x])
If you have multiple arrays you are managing all at once, create a multi-dimensional array:
x = [
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]
]
In that case, you can just index by row then column:
x[2][3]
Based on your comment, you want to randomly change values in the array. In that case, the approach above is not at all what you want. You want to pick two random numbers, and index to them in x to change them:
import random
for _ in range(5):
updated = False
while not updated:
i = random.randrange(10)
j = random.randrange(10)
if x[i][j] == 0:
x[i][j] = 1
updated = True
Original answer to the initial question:
(this is here more as an interesting thing, not as a viable approach)
Okay. Assuming that you have to do it the way you have described, you can generate a dictionary with all of the string keys:
my_dict_grid = {
f"x{i + 1}[{j}]": arr[j]
for i, arr in enumerate([x1, x2, x3, x4, x5, x6, x7, x8, x9, x10])
for j in range(10)
}
However, I have to stress that this is not a good idea.
3 different ways to solve this with oneliners, depending of the output you want:
my_list = [[ 0 for _ in range(10)] for _ in range(10)]
my_dict = {"x"+str(i+1):[ 0 for _ in range(10)] for i in range(10)}
my_dict2 = {"x"+str((i+1)%10)+"["+str(int((i+1)/10))+"]": 0 for i in range(100)}
print(my_list) #[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0,...
print(my_dict) #{'x10': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'x9': [0,...
print(my_dict2)#{'x4[3]': 0, 'x1[9]': 0, 'x6[6]': 0, 'x2[8]': 0,...
A more mathematical, but very practical way to do this with numpy:
import numpy as np
grid_shape = [10, 10] # define 10 x 10 grid
num_ones = 5
cells = np.zeros(grid_shape[0]*grid_shape[1]) # define 10*10 = 100 cells as flat array
cells[0:num_ones] = 1 # Set the first 5 entries to 1
np.random.shuffle(cells) # Shuffle the entries, such that the 1's are at random position
grid = cells.reshape(grid_shape) # shape the grid into the desired shape
Running the code above and will e.g. result in grid=
[[0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]]
Note that, by changing grid_shape you can resize your grid, and by changing num_ones, you will adapt the number of ones in your grid. Also, it is guaranteed that there will always be num_ones ones in your grid (given that num_ones is smaller or equal the number of elements in the grid).

Is there a way to insert multiple elements to different locations in a ndarray all at once?

I'm using numpy's ndarray, and I'm wondering is there a way that allows me to insert multiple elements to different locations all at once?
For example, I have an image, and I want to pad the image with 0s. This is what I currently have:
def zero_padding(self):
padded = self.copy()
padded.img = np.insert(self.img, 0, 0, axis = 0)
padded.img = np.insert(padded.img, padded.img.shape[0], 0, axis = 0)
padded.img = np.insert(padded.img, 0, 0, axis = 1)
padded.img = np.insert(padded.img, padded.img.shape[1], 0, axis = 1)
return padded
where padded is an instance of the image.
Sure, you can use the fancy indexing techinque of NumPy as follows:
import numpy as np
if __name__=='__main__':
A = np.zeros((5, 5))
A[[1, 2], [0, 3]] = 1
print(A)
Output:
[[0. 0. 0. 0. 0.]
[1. 0. 0. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
Cheers

Matrix in Python give wrong results using Numpy Python

I am a complete beginner with NumPy and I am trying to generate the following matrix pattern. Below is my code. What I am not figuring out is that what am I doing wrong to get this result. Thanks in advance for any help.
import numpy as np
def matrix(n):
final = []
for i in range(n):
final.append(list(np.tile([0,1],int(n/2))) if i%2==0 else list(np.tile([1,0],int(n/2))))
print(np.array(final))
size = 8
matrix(size)
While using numpy you should avoid working with arrays and for loops for matrix creating and editing because for large matrices it would be very slow.
Try to examine this code:
import math
import numpy as np
def zero_borders(mat: np.ndarray) -> None:
"""Makes the borders of the array zero."""
mat[:, 0] = 0 # left border
mat[:, -1] = 0 # right border
mat[0, :] = 0 # upper border
mat[-1, :] = 0 # bottom border
def zero_center_square(mat: np.ndarray) -> None:
"""Makes small square of zeros in the center of the array."""
size = mat.shape[0]
i_low = size//2 - 1
i_high = math.ceil(size/2)
mat[i_low, i_low:i_high + 1] = 0 # upper edge of the square
mat[i_high, i_low:i_high + 1] = 0 # upper edge of the square
mat[i_low:i_high + 1, i_low] = 0 # left edge of the square
mat[i_low:i_high + 1, i_high] = 0 # right edge of the square
def matrix(n: int) -> np.ndarray:
"""Creates a square matrix with special pattern."""
mat = np.ones((n, n))
zero_borders(mat)
zero_center_square(mat)
return mat
def main():
print("Even size:")
print(matrix(8))
print("")
print("Odd size:")
print(matrix(9))
if __name__ == "__main__":
main()
The output:
Even size:
[[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 1. 1. 1. 1. 1. 0.]
[0. 1. 1. 1. 1. 1. 1. 0.]
[0. 1. 1. 0. 0. 1. 1. 0.]
[0. 1. 1. 0. 0. 1. 1. 0.]
[0. 1. 1. 1. 1. 1. 1. 0.]
[0. 1. 1. 1. 1. 1. 1. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]]
Odd size:
[[0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 1. 1. 1. 1. 1. 1. 0.]
[0. 1. 1. 1. 1. 1. 1. 1. 0.]
[0. 1. 1. 0. 0. 0. 1. 1. 0.]
[0. 1. 1. 0. 1. 0. 1. 1. 0.]
[0. 1. 1. 0. 0. 0. 1. 1. 0.]
[0. 1. 1. 1. 1. 1. 1. 1. 0.]
[0. 1. 1. 1. 1. 1. 1. 1. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0.]]
You can use numpy ix_() like this:
>>> x = np.zeros((9,9), dtype=int)
>>> p1 = np.ix_([1,2,6,7],[1,2,3,4,5,6,7])
>>> x[p]=1
>>> p2 = np.ix_([3,4,5],[1,2,6,7])
>>> x[p2]=1
>>> x
array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 0, 0, 0, 1, 1, 0],
[0, 1, 1, 0, 1, 0, 1, 1, 0],
[0, 1, 1, 0, 0, 0, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]])
You have not mentioned any particular pattern for lxl length of matrix, so I will write just code about how to generate the matrix in given image.
You can use NumPy (particularly numpy.pad()) to create that matrix easily as:
import numpy as np
# Create required matrix
matrix = np.pad(np.pad(np.pad(np.array([[1]]), (1, 1)), (2, 2), constant_values = 1), (1, 1))
# If you want that as list instead of NumPy array
list_matrix = list(list(i) for i in matrix)

Modifying (keras/tensorflow) Tensors using numpy methods

I want to perform a specific operation. Namely, from a matrix:
A = np.array([[1,2],
[3,4]])
To the following
B = np.array([[1, 0, 0, 2, 0, 0],
[0, 1, 0, 0, 2, 0],
[0, 0, 1, 0, 0, 2],
[3, 0, 0, 4, 0, 0],
[0, 3, 0, 0, 4, 0],
[0, 0, 3, 0, 0, 4]])
Or in words: multiply every entry by the identity matrix and keep the same order.
Now I have accomplished this by using numpy, using the following code. Here N and M are the dimensions of the starting matrix, and the dimension of the identity matrix.
l_slice = 3
n_slice = 2
A = np.reshape(np.arange(1, 1+N ** 2), (N, N))
B = np.array([i * np.eye(M) for i in A.flatten()])
C = B.reshape(N, N, M, M).reshape(N, N * M, M).transpose([0, 2, 1]).reshape((N * M, N * M))
where C has my desired properties.
But now I want do this modification in Keras/Tensorflow, where the matrix A is the outcome of one of my layers.
However, I am not sure yet if I will be able to properly create matrix B. Especially when batches are involved, I think I will somehow mess up the dimensions of my problem.
Can anyone with more Keras/Tensorflow experience comment on this 'reshape' and how he/she sees this happening within Keras/Tensorflow?
Here is a way to do that with TensorFlow:
import tensorflow as tf
data = tf.placeholder(tf.float32, [None, None])
n = tf.placeholder(tf.int32, [])
eye = tf.eye(n)
mult = data[:, tf.newaxis, :, tf.newaxis] * eye[tf.newaxis, :, tf.newaxis, :]
result = tf.reshape(mult, n * tf.shape(data))
with tf.Session() as sess:
a = sess.run(result, feed_dict={data: [[1, 2], [3, 4]], n: 3})
print(a)
Output:
[[1. 0. 0. 2. 0. 0.]
[0. 1. 0. 0. 2. 0.]
[0. 0. 1. 0. 0. 2.]
[3. 0. 0. 4. 0. 0.]
[0. 3. 0. 0. 4. 0.]
[0. 0. 3. 0. 0. 4.]]
By the way, you can do basically the same in NumPy, which should be faster than your current solution:
import numpy as np
data = np.array([[1, 2], [3, 4]])
n = 3
eye = np.eye(n)
mult = data[:, np.newaxis, :, np.newaxis] * eye[np.newaxis, :, np.newaxis, :]
result = np.reshape(mult, (n * data.shape[0], n * data.shape[1]))
print(result)
# The output is the same as above
EDIT:
I'll try to give some intuition about why/how this works, sorry if it's too long. It is not that hard but I think it's sort of tricky to explain. Maybe it is easier to see how the following multiplication works
import numpy as np
data = np.array([[1, 2], [3, 4]])
n = 3
eye = np.eye(n)
mult1 = data[:, :, np.newaxis, np.newaxis] * eye[np.newaxis, np.newaxis, :, :]
Now, mult1 is a sort of "matrix of matrices". If I give two indices, I will get the diagonal matrix for the corresponding element in the original one:
print(mult1[0, 0])
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
So you could say this matrix could be visualize like this:
| 1 0 0 | | 2 0 0 |
| 0 1 0 | | 0 2 0 |
| 0 0 1 | | 0 0 2 |
| 3 0 0 | | 4 0 0 |
| 0 3 0 | | 0 4 0 |
| 0 0 3 | | 0 0 4 |
However this is deceiving, because if you try to reshape this to the final shape the result is not the right one:
print(np.reshape(mult1, (n * data.shape[0], n * data.shape[1])))
# [[1. 0. 0. 0. 1. 0.]
# [0. 0. 1. 2. 0. 0.]
# [0. 2. 0. 0. 0. 2.]
# [3. 0. 0. 0. 3. 0.]
# [0. 0. 3. 4. 0. 0.]
# [0. 4. 0. 0. 0. 4.]]
The reason is that reshaping (conceptually) "flattens" the array first and then gives the new shape. But the flattened array in this case is not what you need:
print(mult1.ravel())
# [1. 0. 0. 0. 1. 0. 0. 0. 1. 2. 0. 0. 0. 2. 0. ...
You see, it first traverses the first submatrix, then the second, etc. What you want though is for it to traverse first the first row of the first submatrix, then the first row of the second submatrix, then second row of first submatrix, etc. So basically you want something like:
Take the first two submatrices (the ones with 1 and 2)
Take all the first rows ([1, 0, 0] and [2, 0, 0]).
Take the first of these ([1, 0, 0])
Take each of its elements (1, 0 and 0).
And then continue for the rest. So if you think about it, we traversing first the axis 0 (row of "matrix of matrices"), then 2 (rows of each submatrix), then 1 (column of "matrix of matrices") and finally 3 (columns of submatrices). So we can just reorder the axis to do that:
mult2 = mult1.transpose((0, 2, 1, 3))
print(np.reshape(mult2, (n * data.shape[0], n * data.shape[1])))
# [[1. 0. 0. 2. 0. 0.]
# [0. 1. 0. 0. 2. 0.]
# [0. 0. 1. 0. 0. 2.]
# [3. 0. 0. 4. 0. 0.]
# [0. 3. 0. 0. 4. 0.]
# [0. 0. 3. 0. 0. 4.]]
And it works! So in the solution I posted, to avoid the tranposing, I just make the multiplication so the order of the axes is exactly that:
mult = data[
:, # Matrix-of-matrices rows
np.newaxis, # Submatrix rows
:, # Matrix-of-matrices columns
np.newaxis # Submatrix columns
] * eye[
np.newaxis, # Matrix-of-matrices rows
:, # Submatrix rows
np.newaxis, # Matrix-of-matrices columns
: # Submatrix columns
]
I hope that makes it slightly clearer. To be honest, in this case in particular I could came up with the solution quickly because I had to solve a similar problem not too long ago, and I guess you end up building an intuition of these things.
Another way to achieve the same effect in numpy is to use the following:
A = np.array([[1,2],
[3,4]])
B = np.repeat(np.repeat(A, 3, axis=0), 3, axis=1) * np.tile(np.eye(3), (2,2))
Then, to replicate it in tensorflow, we can use tf.tile, but there is no tf.repeat, however someone has provided this function on tensorflow tracker.
def tf_repeat(tensor, repeats):
"""
Args:
input: A Tensor. 1-D or higher.
repeats: A list. Number of repeat for each dimension, length must be the same as the number of dimensions in input
Returns:
A Tensor. Has the same type as input. Has the shape of tensor.shape * repeats
"""
with tf.variable_scope("repeat"):
expanded_tensor = tf.expand_dims(tensor, -1)
multiples = [1] + list(repeats)
tiled_tensor = tf.tile(expanded_tensor, multiples=multiples)
repeated_tesnor = tf.reshape(tiled_tensor, tf.shape(tensor) * repeats)
return repeated_tesnor
and thus the tensorflow implementation will look like the following. Here I also consider that the first dimension represents batches, and thus we do not operate on it.
N = 2
M = 3
nbatch = 2
Ain = np.reshape(np.arange(1, 1 + N*N*nbatch), (nbatch, N, N))
A = tf.placeholder(tf.float32, shape=(nbatch, N, N))
B = tf.tile(tf.eye(M), [N, N]) * tf_repeat(A, [1, M, M])
with tf.Session() as sess:
print(sess.run(C, feed_dict={A: Ain}))
and the result:
[[[1. 0. 0. 2. 0. 0.]
[0. 1. 0. 0. 2. 0.]
[0. 0. 1. 0. 0. 2.]
[3. 0. 0. 4. 0. 0.]
[0. 3. 0. 0. 4. 0.]
[0. 0. 3. 0. 0. 4.]]
[[5. 0. 0. 6. 0. 0.]
[0. 5. 0. 0. 6. 0.]
[0. 0. 5. 0. 0. 6.]
[7. 0. 0. 8. 0. 0.]
[0. 7. 0. 0. 8. 0.]
[0. 0. 7. 0. 0. 8.]]]

Categories

Resources