I have a some nested loops (three total) where I'm trying to use numpy.einsum to speed up the calculations, but I'm struggling to get the notation correct. I managed to get rid of one loop, but I can't figure out the other two. Here's what I've got so far:
import numpy as np
import time
def myfunc(r, q, f):
nr = r.shape[0]
nq = q.shape[0]
y = np.zeros(nq)
for ri in range(nr):
for qi in range(nq):
y[qi] += np.einsum('i,i',f[ri,qi]*f[:,qi],np.sinc(q[qi]*r[ri,:]/np.pi))
return y
r = np.random.random(size=(1000,1000))
q = np.linspace(0,1,1001)
f = np.random.random(size=(r.shape[0],q.shape[0]))
start = time.time()
y = myfunc(r, q, f)
end = time.time()
print(end-start)
While this was much faster than the original, this is still too slow, and takes about 30 seconds. Note the original without the einsum call was the following (which looks like it will take ~2.5 hours, didn't wait to find out for sure):
def myfunc(r, q, f):
nr = r.shape[0]
nq = q.shape[0]
y = np.zeros(nq)
for ri in range(nr):
for rj in range(nr):
for qi in range(nq):
y[qi] += f[ri,qi]*f[rj,qi]*np.sinc(q[qi]*r[ri,rj]/np.pi))
return y
Does anyone know how to get rid of these loops with an einsum, or any other tool for that matter?
Your function seems to be equivalent to the following:
Which took about 20 seconds on my system, with most of the time to allocate
s
.Let's test it for a small sample:
Since
np.sinc
is not a linear operator, I'm not quite sure how we can further reduce the run time.