TensorFlow outer product of two 2-rank tensors - python

Suppose I have a rank two tensor, [[a,b],[c,d]](in general a m-by-n matrix).
I want to expand every element by a 2-2 identity matrix(outer product) and result in
[[a, 0, b, 0],[0,a,0,b],[c,0,d,0],[0,c,0,d]].
What is the most efficient way to implement it in tensorflow?
This operation appears a lot in the framework.

I would like to do this in 2-step process.
If I have a m-by-n matrix, and a 2-2 identity matrix.
First I will enlarge (repeat) the matrix to "2m-2n matrix"
and then multiply by the enlarged identity matrix (2m-2n matrix). As following shows.
import tensorflow as tf
#Process 1 repeat the tensor in 2D.
#e.g. [1,2,3,4] --> [[1,1,2,2],[1,1,2,2],[3,3,4,4],[3,3,4,4]]
# assuming m x n idenity matrix e.g. [1,2,3],[4,5,6]] , m=2,n=3
id_matrix_size=2 # size of identity matrix (e.g. 2x2 3x3 ...)
m=2
n=3
mytensor=tf.constant([[1,2,3],[4,5,6] ],dtype = tf.float32)
# similar to np.repeat in x-dimension.
flatten_mytensor=tf.reshape(mytensor,[-1,1])
a=tf.tile(flatten_mytensor, [1, id_matrix_size])
b=tf.reshape( a, [m,-1])
# tile in y-dimension
c=tf.tile(b,[1,id_matrix_size])
d=tf.reshape(c,[id_matrix_size*m,id_matrix_size*n])
#Process 2 tile identity matrix in 2D.
identity_matrix=tf.eye(id_matrix_size) # identity matrix
identity_matrix_2D= tf.tile(identity_matrix,[m,n])
#Process 3 elementwise multiply
output = tf.multiply(d,identity_matrix_2D )
with tf.Session() as sess:
print(sess.run(output) )
#output :
#[[1. 0. 2. 0. 3. 0.]
# [0. 1. 0. 2. 0. 3.]
# [4. 0. 5. 0. 6. 0.]
# [0. 4. 0. 5. 0. 6.]]
And also, a def is more convenient if lots of implements are needed.
def Expand_tensor(mytensor,id_matrix_size):
m=mytensor.shape[0]
n=mytensor.shape[1]
# similar to np.repeat in x-dimension.
flatten_mytensor=tf.reshape(mytensor,[-1,1])
a=tf.tile(flatten_mytensor, [1, id_matrix_size])
b=tf.reshape( a, [m,-1])
# tile in y-dimension
c=tf.tile(b,[1,id_matrix_size])
d=tf.reshape(c,[id_matrix_size*m,id_matrix_size*n])
# tile identity matrix in 2D.
identity_matrix=tf.eye(id_matrix_size) # identity matrix
identity_matrix_2D= tf.tile(identity_matrix,[m,n])
#elementwise multiply
output = tf.multiply(d,identity_matrix_2D )
return output
mytensor=tf.constant([[1,2,3],[4,5,6] ],dtype = tf.float32)
with tf.Session() as sess:
print(sess.run(Expand_tensor(mytensor,2)) )

Related

Re-calculate elements of symmetric matrix using a "i not equal to j" loop in Python

The correlation matrix is a symmetric matrix, meaning that its upper diagonal and lower diagonal elements are mirror images of each other, together called off-diagonal elements (as opposed to the diagonal elements, which are all equal to 1 in any correlation matrix since any variable's correlation with itself is just 1).
The off-diagonal elements of a correlation matrix are the same wherever the i'th row number and j'th column number in the lower diagonal are swapped in the upper diagonal, i.e. correlation of variables 1 and 2 (row 1, column 2) are the same for variables 2 and 1 (row 2, column 1). Therefore, we only need to re-calculate the lower-diagonal elements, and copy them to corresponding positions in the matrix's upper-diagonal after
import numpy as np
from numpy.random import randn
X = randn(20,3)
Rho = np.corrcoef(X.T) #correlation matrix
print(np.tril(Rho)) #lower off-diagonal of matrix Rho to re-calculate, then copy to other side
shows
array([[ 1. , 0. , 0. ],
[-0.03003281, 1. , 0. ],
[-0.02602238, 0.06137713, 1. ]])
What is the most efficient way to code a "i not-equal-to j" loop for the following sequence of steps:
re-calculate the lower off-diagonal elements of the symmetric matrix according to some apply function (to make it simple, we will just add +2 to each of these elements)
flip those same calculations onto its mirror image (the corresponding upper off-diagonals)
Also, replace the diagonal elements of the symmetric matrix with a vector filled with 10's (instead of 1's as found in the correlation matrix)
The aim is to generate a new matrix that is a re-calculation of the original.
Let us generate Rho first (note that I'm initializing the pseudo-random number generator in order to obtain the same Rho in different runs of the code):
In [526]: import numpy as np
In [527]: np.random.seed(0)
...: n = 3
...: X = np.random.randn(20, n)
...: Rho = np.corrcoef(X.T)
In [528]: Rho
Out[528]:
array([[1. , 0.03224462, 0.05021998],
[0.03224462, 1. , 0.15140358],
[0.05021998, 0.15140358, 1. ]])
Then you can use NumPy's tril_indices_from and advanced indexing to generate the new matrix:
In [548]: result = np.zeros_like(Rho)
In [549]: lrows, lcols = np.tril_indices_from(Rho, k=-1)
In [550]: result[lrows, lcols] = Rho[lrows, lcols] + 2
In [551]: result
Out[551]:
array([[0. , 0. , 0. ],
[2.03224462, 0. , 0. ],
[2.05021998, 2.15140358, 0. ]])
In [552]: result[lcols, lrows] = result[lrows, lcols]
In [553]: result
Out[553]:
array([[0. , 2.03224462, 2.05021998],
[2.03224462, 0. , 2.15140358],
[2.05021998, 2.15140358, 0. ]])
In [554]: result[np.arange(n), np.arange(n)] = 10
In [555]: result
Out[555]:
array([[10. , 2.03224462, 2.05021998],
[ 2.03224462, 10. , 2.15140358],
[ 2.05021998, 2.15140358, 10. ]])

Numpy or Tensorflow vectorize a sequential operation

I am wondering if it's possible to vectorize the following operation in Numpy or Tensorflow. The ultimate goal is to do it in Tensorflow, but seems Numpy would be easier for illustration here.
The problem is to get an discretized occupancy grid from a set of 2D points (x, y), and calculate the average of points in that particular grid.
Given 2D array xy, every row [x, y] will be mapped to an index [xid, yid]. This step is done via np.apply_along_axis
In another 3D array grid_sum, given the [xid, yid] we calculated in 1), we update grid_sum[xid, yid] += [x, y].
In yet another 2D array grid_count, given the [xid, yid] we calculated in 1), we update grid_sum[xid, yid] += 1.
We get the final results 3D array grid_mean by dividing grid_sum by grid_count at every [xid, yid].
The problem of vectorize this operation is different rows might be trying to write to the same location in the new array, creating a race condition. How can I handle this?
I have the following minimal example here to help understand this situation.
Edit after comment
This example works fine because I use a for loop. Is it possible to achieve the same without the for loop?
import numpy as np
xy = np.array([[1, 1], [1, 1]], dtype=np.int16)
grid_sum = np.zeros([3, 3, 2])
grid_count = np.zeros([3, 3])
for i in range(xy.shape[0]):
idx = xy[i] # simple case, just use array value as index
grid_sum[idx[0], idx[1], :] += xy[i]
grid_count[idx[0], idx[1]] += 1
print(grid_sum)
print(grid_count)
# grid_sum result
# [[[0. 0.]
# [0. 0.]
# [0. 0.]]
# [[0. 0.]
# [2. 2.]
# [0. 0.]]
# [[0. 0.]
# [0. 0.]
# [0. 0.]]]
# grid_count result
# [[0. 0. 0.]
# [0. 2. 0.]
# [0. 0. 0.]]

How to fill specific elements of a matrix knowing their indices with values from a column vector

How can I fill the elements of the lower triangular part of a matrix, including the diagonal, with values from a column vector?
For example i have :
m=np.zeros((3,3))
n=np.array([[1],[1],[1],[1],[1],[1]]) #column vector
I want to replace values which have indices of (0,0),(1,0),(1,1),(2,0),(2,1),(2,2) from m with the vector n, so I get:
m=np.array([[1,0,0],[1,1,0],[1,1,1]])
Then I want make the same operation to m.T to get as a result:
m=np.array([[1,1,1],[1,1,1],[1,1,1]])
Can someone help me please? n should be a vector with shape(6,1)
I'm not sure if there's going to be a clever numpy-specific way of doing this, but it looks relatively straightforward like this:
import numpy as np
m=np.zeros((3,3))
n=np.array([[1],[1],[1],[1],[1],[1]]) #column vector
indices=[(0,0),(1,0),(1,1),(2,0),(2,1),(2,2)]
for ix, index in enumerate(indices):
m[index] = n[ix][0]
print(m)
for ix, index in enumerate(indices):
m.T[index] = n[ix][0]
print(m)
Output of the above is:
[[1. 0. 0.]
[1. 1. 0.]
[1. 1. 1.]]
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]

How to compute an affine transformation of multiple points?

I have a 3d numpy array of point (484,3,1) and a 2d transformation matrix (3,3). I want to compute the transformation for all 484 points.
I have tried to reshape the arrays and compute the dot product, but I am struggling to get it to output a (484,3,1) shaped array where all the points are transformed.
points = np.random.randint(0, 979, (484,3,1))
transformation = array([[0.94117647, 0. , 0. ],
[0. , 0.94117647, 0. ],
[0. , 0. , 1. ]])
points.shape = (484,3,1)
transformation = (3,3)
transformation.dot(points).shape = (3,484,1)
I would like this to be as optimized as possible. Any advice would be greatly appreciated.
Just do a reshape to (484,3) dimensions and use the np.matmul (np.dot is also possible but since you are looking for a matrix multiplication matmul is prefered according to the documentation) product
np.matmul(points.reshape(484,-1), transformation).reshape(484,3,-1)
resulting shape is the same of course given by the last reshaping: (484,3,1)

Convert lower triangle half to Symmertic matrix using numpy

I have a matrix which has to be transformed to a symmetric matrix using
python numpy.
Apparently, using the following code in am able to transform to symmetric matrix .. this work fine for small matrix but for a large 150 * 151
I get the following error...operands could not be broadcast together
with shapes (151,150) (150,151)
import numpy as np
from numpy import genfromtxt
my_data = genfromtxt('C:\\Users\\vish_\\firstest\\demo\\002.csv',
delimiter=',')
print(my_data)
[[ 0. nan nan]
[ 1. 0. nan]
[ 2. 3. 0.]]
<!-- code for symmetric matrix in file!>
m = np.tril(my_data) + np.tril(my_data, -1).T
print(m)
[[0. 1. 2.]
[1. 0. 3.]
[2. 3. 0.]]
<!-- code for saving matrix in file!>
np.set_printoptions(suppress=True)
np.set_printoptions(precision=3)
m.tofile('foo2.csv',sep=',',format='%10.5f')
np.savetxt("foo2.csv", m ,delimiter=",",fmt='%f')
I get the following error...operands could not be broadcast together
with shapes (151,150) (150,151)
You don't have a square matrix. 150 x 151 is not a square matrix! The reason it worked for smaller example because it was a square matrix (3 x 3). The example on which you are trying to work is not a square matrix. Please there is a transpose operator in the code (see below towards right).
m = np.tril(my_data) + np.tril(my_data, -1).T
For 150 x 151 the transpose will be 151 x 150 shape. The dimensions will not line up for the addition to happen. Best wishes

Categories