I have an array of n vectors of length m. For example, with n = 3, m = 2:
x = array([[1, 2], [3, 4], [5,6]])
I want to take the outer product of each vector with itself, then concatenate them into an array of square matrices of shape (n, m, m). So for the x
above I would get
array([[[ 1, 2],
[ 2, 4]],
[[ 9, 12],
[12, 16]],
[[25, 30],
[30, 36]]])
I can do this with a for
loop like so
np.concatenate([np.outer(v, v) for v in x]).reshape(3, 2, 2)
Is there a numpy expression that does this without the Python for
loop?
Bonus question: since the outer products are symmetric, I don't need to m x m multiplication operations to calculate them. Can I get this symmetry optimization from numpy?
Maybe use einsum
?
>>> x = np.array([[1, 2], [3, 4], [5,6]])
>>> np.einsum('ij...,i...->ij...',x,x)
array([[[ 1, 2],
[ 2, 4]],
[[ 9, 12],
[12, 16]],
[[25, 30],
[30, 36]]])
I used the following snippet when I was trying to do the same in Theano:
def multiouter(A,B):
'''Provided NxK (Theano) matrices A and B it returns a NxKxK tensor C with C[i,:,:]=A[i,:]*B[i,:].T'''
return A.dimshuffle(0,1,'x')*B.dimshuffle(0,'x',1)
Doing a straighforward conversion to Numpy yields
def multiouter(A,B):
'''Provided NxK (Numpy) arrays A and B it returns a NxKxK tensor C with C[i,:,:]=A[i,:]*B[i,:].T'''
return A[:,:,None]*B[:,None,:]
I think I got the inspiration for it from another StackOverflow posting, so I am not sure I can take all the credit.
Note: indexing with None
is equivalent to indexing with np.newaxis
and instantiates a new axis with dimension 1.