General Problem
Suppose that I have a ndarray v of shape (nrow,ncols,3). I want to compute the ndarray outer_array of shape (nrow,ncols,3,3) containing all outer products of the vectors of shape (3) at each index (nrow,ncol). Of course, this is the the kind of problem for which numpy.einsum exists.
Now, what I've tried is:
outer_array = numpy.einsum("xyi,xyj->xyij",v,v.conjugate())
Now, I'm not sure that this will work: despite the fact that outer_array has the expected shape, the elements of the matrices of outer products do not correspond to what I'm expecting.
I think this is due to the choice of labels in the einsum expression: the product is supposed to be summed over x and y because the indices are repeated, but since I'm reusing them in the output expression, the result of the sum is somehow broadcast.
On the other hand, if I write:
outer_array = numpy.einsum("xyi,uvj->...ij",v,v.conjugate())
numpy will compute all possible combinations of outer products for each pair (x,y) and (u,v), resulting in an array of shape (ncols,nrow,ncols,nrow,3,3), where the diagonals (u,v) = (x,y) will contain the desired output.
The Precise Question
How do I choose the first two indices in the einsum notation in order to obtain an array where at each index x,y I get the outer product of vector v with itself without having to resort to the second expression?
Edit apparently, this form seems to work too:
outer_array = numpy.einsum("...i,...j->...ij",v,v.conjugate())
I can only admire how useful numpy broadcasting is!
xandyare repeated in the terms to be summed over and appear in the output again. Can someone explain that? - Bafe