Add arrays of different dimensions - python

I am trying to add two arrays of different dimensions. Array A has shape (20,2,2,2,2,3) and array B has shape (20). Currently, I am using np.newaxis 5 times, so B gets the same shape as A and then I add them. In my actual code A is much bigger and this forces me to write np.newaxis many times. Is there a way to avoid repeating the np.newaxis and just tell python to give B the same shape as A?
A = np.zeros([20,2,2,2,2,3])
B = np.arange(1,21)
B = B[:,np.newaxis,np.newaxis,np.newaxis,np.newaxis,np.newaxis]
C = A + B

If you are broadcasting, this will work:
A= np.zeros([20,2,2,2,2,3])
B = np.arange(1,21)
B = B.reshape([20,1,1,1,1,1])
C = A + B
In a more dynamic way:
shape_a = [20,2,2,2,2,3]
A= np.zeros(shape_a)
B = np.arange(1,21)
shape_b = [shape_a[0]] +(len(shape_a)-1)*[1]
B = B.reshape(shape_b)
C = A + B
With no broadcasting:
A = np.zeros([20,2,2,2,2,3])
B = np.arange(1,21)
C = A.copy()
C[:,0,0,0,0,0] += B
And if you don't care about A, just the result:
C = np.zeros([20,2,2,2,2,3])
B = np.arange(1,21)
C[:,0,0,0,0,0] += B

What you are doing is broadcasting to the number of dimensions of A, but if you look carefully, this operation you did does not make B have the same shape as A. Indeed they are still different:
>>> B[:, None, None, None, None, None].shape
(20, 1, 1, 1, 1, 1)
So this is basically applying np.expand_dims consequently five times. An alternative way is to reshape the array with extra singletons:
>>> B.reshape((-1, *(1,)*(A.ndim-1))).shape
(20, 1, 1, 1, 1, 1)
Which will reshape (*,) to (*, 1, 1, 1, 1, 1).
This has the same effect as placing the np.newaxis manually.

For your case, you can also do:
C = (A.reshape(A.shape[0], -1) + B[:,None]).reshape(A.shape)
Or swap the common axis to the end:
C = (A.swapaxes(0,-1) + B).swapaxes(0,-1)

Related

Tensor reduction based off index vector

As an example, I have 2 tensors: A = [1;2;3;4;5;6;7] and B = [2;3;2]. The idea is that I want to reduce A based off B - such that B's values represent how to sum A's values- such that B = [2;3;2] means the reduced A shall be the sum of the first 2 values, next 3, and last 2: A' = [(1+2);(3+4+5);(6+7)]. It is apparent that the sum of B shall always be equal to the length of A. I'm trying to do this as efficiently as possible - preferably specific functions or matrix operations contained within pytorch/python. Thanks!
Here is the solution.
First, we create an array of indices B_idx with the same size of A.
Then, accumulate (add) all elements in A based on the indices B_idx using index_add_.
A = torch.arange(1, 8)
B = torch.tensor([2, 3, 2])
B_idx = [idx.repeat(times) for idx, times in zip(torch.arange(len(B)), B)]
B_idx = torch.cat(B_idx) # tensor([0, 0, 1, 1, 1, 2, 2])
A_sum = torch.zeros_like(B)
A_sum.index_add_(dim=0, index=B_idx, source=A)
print(A_sum) # tensor([ 3, 12, 13])

Matrix of matrices in python

Hey so I'm working on this code for a material analysis. I have a matrix generated for each layer of the material and I want to save each of these matrices as their own element. The way I was doing this was by saving it to a dictionary. I then form one matrix by summing all the values of the dictionary. Now I do this for three different conditions which leaves me with 3 matrices: A, B, and D. I want to make a matrix of all of these so that it looks like:
| A B |
| B D |
However I can't get it to print properly as it always says matrix: then one of the matrices such as A. It prints the second matrix, B, on the third line where A ended instead of being next to A. I also need to perform future operations on this massive matrix so I'm wondering what the best way to go about that would be. This is a part of my code:
Qbars = {}
for i in plies:
Qbar11 = Q11 * math.cos(float(thetas[j]))**4 + Q22 *math.sin(float(thetas[j]))**4 + \
2 * (Q12 + 2 * Q66) * math.sin(float(thetas[j]))**2 * math.cos(float(thetas[j]))**2
Qbar22 = Q11 * math.sin(float(thetas[j]))**4 + Q22 *math.cos(float(thetas[j]))**4 + \
2 * (Q12 + 2 * Q66) * math.sin(float(thetas[j]))**2 * math.cos(float(thetas[j]))**2
Qbar12 = (Q11 + Q22 - 4 * Q66) * math.sin(float(thetas[j]))**2 * \
math.cos(float(thetas[j]))**2 + Q12 * (math.cos(float(thetas[j]))**4 + \
math.sin(float(thetas[j]))**4)
Qbar66 = (Q11 + Q22 - 2 * Q12 - 2 * Q66) * math.sin(float(thetas[j]))**2 * \
math.cos(float(thetas[j])) **2 + Q66 * (math.sin(float(thetas[j]))**4 + \
math.cos(float(thetas[j]))**4)
Qbar16 = (Q11 - Q12 - 2 * Q66) * math.cos(float(thetas[j]))**3 * \
math.sin(float(thetas[j])) - (Q22 - Q12 - 2 * Q66) * math.cos(float(thetas[j])) * \
math.sin(float(thetas[j]))**3
Qbar26 = (Q11 - Q12 - 2 * Q66) * math.cos(float(thetas[j])) * \
math.sin(float(thetas[j]))**3 - (Q22 - Q12 - 2 * Q66) * \
math.cos(float(thetas[j]))**3 * math.sin(float(thetas[j]))
Qbar = np.matrix ([[Qbar11, Qbar12, Qbar16], [Qbar12, Qbar22, Qbar26], \
[Qbar16, Qbar26, Qbar66]])
Qbars[i] = Qbar
if len(thetas) == 1:
j = 0
else:
j = j + 1
k=0
Alist = {}
for i in plies:
Alist[i] = Qbars[i].dot(h[k])
if len(h) == 1:
k = 0
else:
k = k + 1
A = sum(Alist.values())
ABD = ([A, B],[B, D])
print ABD
One of the next operations I intend to perform would be to multiply the matrix by a 6x1 array that would look like such:
| Nx | | A A A B B B |
| Ny | | A A A B B B |
| Nxy| | A A A B B B |
------ * ----------------
| Mx | | B B B D D D |
| My | | B B B D D D |
| Mxy| | B B B D D D |
What would be the best way to go about doing this?
EDIT: I made this shorter code to reproduce what I'm dealing with, I couldn't think of how to make it even smaller.
import os
import numpy as np
import math
os.system('cls')
ang = raw_input("ENTER 0 (SPACE) 45 ")
thetas = [int(i) for i in ang.split()]
x = 40
h = [3, 5]
y = [1,2]
j = 0
Qbars = {}
for i in y:
theta = [thetas[j] * math.pi / 180]
Q = math.sin(float(thetas[j]))
Qbar = np.matrix ([[Q, Q, Q], [Q, Q, Q], [Q, Q, Q]])
Qbars[i] = Qbar
if len(thetas) == 1:
j = 0
else:
j = j + 1
print Qbars
k=0
Alist = {}
for i in y:
Alist[i] = Qbars[i].dot(h[k])
if len(h) == 1:
k = 0
else:
k = k + 1
A = sum(Alist.values())
AAAA = ([A, A], [A, A])
print AAAA
test = raw_input("Press ENTER to close")
As others have noted, the matrix class is pretty much deprecated by now. They are more limited than ndarrays, with very little additional functionality. The main reason why people prefer to use numpy matrices is that linear algebra (in particular, matrix multiplication) works more naturally for matrices.
However, as far as I can tell you're using np.dot rather than the overloaded arithmetic operators of the matrix class to begin with, so you would not see any loss of functionality from using np.array instead. Furthermore, if you would switch to python 3.5 or newer, you could use the # matrix multiplication operator that would let you write things such as
Alist[i] = Qbars[i] # h[k]
In the following I'll use the ndarray class instead of the matrix class for the above reasons.
So, your question has two main parts: creating your block matrix and multiplying the result with a vector. I suggest using an up-to-date numpy version, since there's numpy.block introduced in version 1.13. This conveniently does exactly what you want it to do:
>>> import numpy as np
>>> A,B,C = (np.full((3,3),k) for k in range(3))
>>> A
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
>>> B
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
>>> C
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2]])
>>> np.block([[A,B],[B,C]])
array([[0, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 1, 1],
[1, 1, 1, 2, 2, 2],
[1, 1, 1, 2, 2, 2],
[1, 1, 1, 2, 2, 2]])
Similarly, you can concatenate your two 3-length vectors using np.concatenate or one of the stacking methods (these are available in older versions too).
Now, the problem is that you can't multiply a matrix of shape (6,1) with a matrix of shape (6,6), so the question is what you're really trying to do here. In case you want to multiply each element of your matrix with the corresponding row of your vector, you can just multiply your arrays (of class np.ndarray!) and make use of array broadcasting:
>>> Q = np.block([[A,B],[B,C]]) # (6,6)-shape array
>>> v = np.arange(6).reshape(-1,1) # (6,1)-shape array
>>> v * Q
array([[ 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 1, 1, 1],
[ 0, 0, 0, 2, 2, 2],
[ 3, 3, 3, 6, 6, 6],
[ 4, 4, 4, 8, 8, 8],
[ 5, 5, 5, 10, 10, 10]])
The other option is that you want to do matrix-vector multiplication, but then either you have to transpose your vector (in order to multiply it with the matrix from the right) or swap the order of the matrix and the vector (multiplying the vector with the matrix from the left). Example for the former:
>>> v.T # Q # python 3.5 and up
array([[12, 12, 12, 27, 27, 27]])
>>> v.T.dot(Q)
array([[12, 12, 12, 27, 27, 27]])
Another benefit of arrays (rather than matrices) is that arrays can be multidimensional. Instead of putting numpy arrays inside a dict and summing them that way, you could define a 3d array (a collection of 2d arrays along a third axis), then you could sum along the third dimension. One huge benefit of numpy is its efficient memory need and performance, and these aspects are strongest if you use numpy objects and methods all through your code. Mixing native python objects (such as dicts, zips, loops) typically hinders performance.

Tensorflow: tensor multiplication row-by-row with more different matrices

I have a matrix A which is defined as a tensor in tensorflow, of n rows and p columns. Moreover, I have say k matrices B1,..., Bk with p rows and q columns. My goal is to obtain a resulting matrix C of n rows and q columns where each row of C is the matrix product of the corresponding row in A with one of the B matrices. Which B to choose is determined by a give index vector I of dimension n that can take values ranging from 1 to k. In my case, the B are weight variables while I is another tensor variable given as input.
An example of code in numpy would look as follows:
A = array([[1, 0, 1],
[0, 0, 1],
[1, 1, 0],
[0, 1, 0]])
B1 = array([[1, 1],
[2, 1],
[3, 6]])
B2 = array([[1, 5],
[3, 2],
[0, 2]])
B = [B1, B2]
I = [1, 0, 0, 1]
n = A.shape[0]
p = A.shape[1]
q = B1.shape[1]
C = np.zeros(shape = (n,q))
for i in xrange(n):
C[i,:] = np.dot(A[i,:],B[I[i]])
How can this be translated in tensor flow?
In my specific case the variables are defined as:
A = tf.placeholder("float", [None, p])
B1 = tf.Variable(tf.random_normal(p,q))
B2 = tf.Variable(tf.random_normal(p,q))
I = tf.placeholder("float",[None])
This is a bit tricky and there are probably better solutions. Taking your first example, my approach computes C as follows:
C = diag([0,1,1,0]) * A * B1 + diag([1,0,0,1]) * A * B2
where diag([0,1,1,0]) is the diagonal matrix having vector [0,1,1,0] in its diagonal. This can be achieved through tf.diag() in TensorFlow.
For convenience, let me assume that k<=n (otherwise some B matrices would remain unused). The following script obtains those diagonal values from vector I and computes C as mentioned above:
k = 2
n = 4
p = 3
q = 2
a = array([[1, 0, 1],
[0, 0, 1],
[1, 1, 0],
[0, 1, 0]])
index_input = [1, 0, 0, 1]
import tensorflow as tf
# Creates a dim·dim tensor having the same vector 'vector' in every row
def square_matrix(vector, dim):
return tf.reshape(tf.tile(vector,[dim]), [dim,dim])
A = tf.placeholder(tf.float32, [None, p])
B = tf.Variable(tf.random_normal(shape=[k,p,q]))
# For the first example (with k=2): B = tf.constant([[[1, 1],[2, 1],[3, 6]],[[1, 5],[3, 2],[0, 2]]], tf.float32)
C = tf.Variable(tf.zeros((n, q)))
I = tf.placeholder(tf.int32,[None])
# Create a n·n tensor 'indices_matrix' having indices_matrix[i]=I for 0<=i<n (each row vector is I)
indices_matrix = square_matrix(I, n)
# Create a n·n tensor 'row_matrix' having row_matrix[i]=[i,...,i] for 0<=i<n (each row vector is a vector of i's)
row_matrix = tf.transpose(square_matrix(tf.range(0, n, 1), n))
# Find diagonal values by comparing tensors indices_matrix and row_matrix
equal = tf.cast(tf.equal(indices_matrix, row_matrix), tf.float32)
# Compute C
for i in range(k):
diag = tf.diag(tf.gather(equal, i))
mul = tf.matmul(diag, tf.matmul(A, tf.gather(B, i)))
C = C + mul
sess = tf.Session()
sess.run(tf.initialize_all_variables())
print(sess.run(C, feed_dict={A : a, I : index_input}))
As an improvement, C may be computed using a vectorized implementation instead of using a for loop.
Just do 2 matrix multiplications
A1 = A[0:3:3,...] # this will get the first last index of your original but just make a new matrix
A2 = A[1:2]
in tensorflow
A1 = tf.constant([matrix elements go here])
A2 = tf.constant([matrix elements go here])
B = ...
B1 = tf.matmul(A1,B)
B2 = tf.matmul(A2,B)
C = tf.pack([B1,B2])
granted if you need to reorganize the C tensor you can also use gather
C = tf.gather(C,[0,3,2,1])

Slices along arbitrary axis

I have a numpy array A such that
A.shape[axis] = n+1.
Now I want to construct two slices B and C of A by selecting the indices 0, .., n-1 and 1, ..., n respectively along the axis axis. Thus
B.shape[axis] = C.shape[axis] = n
and B and C have the same size as A along the other axes. There must be no copying of data.
# exemple data
A = np.random.rand(2, 3, 4, 5)
axis = 2
n = A.ndim
# building n-dimensional slice
s = [slice(None), ] * n
s[axis] = slice(0, n - 1)
B = A[s]
s[axis] = slice(1, n)
C = A[s]
One-liners :
B = A[[slice(None) if i != axis else slice(0, n-1) for i in xrange(n)]]
C = A[[slice(None) if i != axis else slice(1, n) for i in xrange(n)]]

Summing values of numpy array based on indices in other array

Assume I have the following arrays:
N = 8
M = 4
a = np.zeros(M)
b = np.random.randint(M, size=N) # contains indices for a
c = np.random.rand(N) # contains random values
I want to sum the values of c according to the indices provided in b, and store them in a. Writing a loop for this is trivial:
for i, v in enumerate(b):
a[v] += c[i]
Since N can get quite big in my real-world problem I'd like to avoid using python loops, but I can't figure out how to write it as a numpy-statement. Can anyone help me out?
Ok, here some example values:
In [27]: b
Out[27]: array([0, 1, 2, 0, 2, 3, 1, 1])
In [28]: c
Out[28]:
array([ 0.15517108, 0.84717734, 0.86019899, 0.62413489, 0.24357903,
0.86015187, 0.85813481, 0.7071174 ])
In [30]: a
Out[30]: array([ 0.77930596, 2.41242955, 1.10377802, 0.86015187])
import numpy as np
N = 8
M = 4
b = np.array([0, 1, 2, 0, 2, 3, 1, 1])
c = np.array([ 0.15517108, 0.84717734, 0.86019899, 0.62413489, 0.24357903, 0.86015187, 0.85813481, 0.7071174 ])
a = ((np.mgrid[:M,:N] == b)[0] * c).sum(axis=1)
returns
array([ 0.77930597, 2.41242955, 1.10377802, 0.86015187])

Categories

Resources