0

I just want to get the dot product of some sets of multidimensional data. For simplicity, I am posting the pieces small, and demonstrating my efforts thus far.

To just get 'a' dot 'q', and the 4 numbers that I want is easy enough.

import numpy as np
a = np.arange(1,4)  # shape = (3,)
q = np.array([[x, x, x] for x in range(4)])+1       # shape = (4, 3)
c = np.dot(a, q.T)  # array([ 6, 12, 18, 24])   shape = (4,)

If I want to add another set to 'a', I can expand the dimensions. Again, pretty easy. The dot product simply reflects the additional dimension.

a = np.arange(1,4).reshape(1,3)     # shape = (1,3)
c = np.dot(a, q.T)  # array([[ 6, 12, 18, 24]])  shape = (1,4)

and the other set...

a = np.vstack((a,a+1))      # shape = (2,3)
c = np.dot(a, q.T)  # array([[ 6, 12, 18, 24], [ 9, 18, 27, 36]])     shape = (2,4)

To add another dimension to q, the transpose needs to be a little more complicated.

q = np.expand_dims(q, axis=0)   # shape = (1, 4, 3)
c = np.dot(a, np.transpose(q, (0, 2, 1)))    # shape = (2, 1, 4)

now stack 'q' matrix

q = np.vstack((q, q+1))   # shape = (2, 4, 3)
c = np.dot(a, np.transpose(q, (0, 2, 1)))    # shape = (2, 2, 4)

Though, what I am going for is the diagonal of c. While I have not tried it yet, I am imagining that when 'a' and 'q' start to reach >(2000, 3) and >(2000, 4, 3) c will be (2000, 2000, 4) and I only need 1/2000th of that. Does anyone know how to make this more efficient than doing the calculation and then taking the diagonal?

Again, what I want is...

c = np.dot(a, np.transpose(q, (0, 2, 1)))
c = c[np.arange(2), np.arange(2)]

or

c[0] = np.dot(a[0:1], np.transpose(q[0:1], (0, 2, 1)))
c[1] = np.dot(a[1:2], np.transpose(q[1:2], (0, 2, 1)))

but without having to make the enormous matrix first and then trim it later.

I have read a couple other, kinda, similar questions. Though, I hope that this question is perceived to be more complicated than a dot product of the same vector and its diagonal, Also, if the answer is np.einsum(), could you explain the process a more than the numpy docs?

jsfa11
  • 394
  • 4
  • 18

1 Answers1

0

I reposted the question, with the einsum() entries at each c. In fact, Alexander Korovin linked to an excellent einsum summary.

I just want to get the dot product of some sets of multidimensional data. For simplicity, I am posting the pieces small, and demonstrating my efforts thus far.

To just get 'a' dot 'q', and the 4 numbers that I want is easy enough.

import numpy as np
a = np.arange(1,4)  # shape = (3,)
q = np.array([[x, x, x] for x in range(4)])+1       # shape = (4, 3)
c = np.dot(a, q.T)  # array([ 6, 12, 18, 24])   shape = (4,)
c = np.einsum('i,ji->j', a, q)

If I want to add another set to 'a', I can expand the dimensions. Again, pretty easy. The dot product simply reflects the additional dimension.

a = np.arange(1,4).reshape(1,3)     # shape = (1,3)
c = np.dot(a, q.T)  # array([[ 6, 12, 18, 24]])  shape = (1,4)
c = np.einsum('ij,ij->i', a, q)

and the other set...

a = np.vstack((a,a+1))      # shape = (2,3)
c = np.dot(a, q.T)  # array([[ 6, 12, 18, 24], [ 9, 18, 27, 36]])     shape = (2,4)
c = np.einsum('ij,gj->ig', a, q)

To add another dimension to q, the transpose needs to be a little more complicated.

q = np.expand_dims(q, axis=0)   # shape = (1, 4, 3)
c = np.dot(a, np.transpose(q, (0, 2, 1)))    # shape = (2, 1, 4)
c = np.einsum('ij,fgj->fig', a, q)

now stack 'q' matrix

q = np.vstack((q, q+1))   # shape = (2, 4, 3)
c = np.dot(a, np.transpose(q, (0, 2, 1)))    # shape = (2, 2, 4)
c = np.einsum('ij,fgj->fig', a, q)

Though, what I am going for is the diagonal of c. While I have not tried it yet, I am imagining that when 'a' and 'q' start to reach >(2000, 3) and >(2000, 4, 3) c will be (2000, 2000, 4) and I only need 1/2000th of that. Does anyone know how to make this more efficient than doing the calculation and then taking the diagonal?

Again, what I want is...

c = np.dot(a, np.transpose(q, (0, 2, 1)))
c = c[np.arange(2), np.arange(2)]

or

c[0] = np.dot(a[0:1], np.transpose(q[0:1], (0, 2, 1)))
c[1] = np.dot(a[1:2], np.transpose(q[1:2], (0, 2, 1)))

but without having to make the enormous matrix first and then trim it later.

So do this...

c = np.einsum('ik,ijk->ij', a, q)
jsfa11
  • 394
  • 4
  • 18