This is based on a previous question of mine Replacing for loops with function call inside with broadcasting/vectorized solution but is more complicated, and the additional complications have me at a loss.
Here are some similar posts, however, I was not able to get my problem to work after reading the solutions to their problems:
Broadcasting function calls in np arrays
Broadcasting a function call to a a 3D array in python
Broadcasting a python function onto np arrays
Here is the MWE
def OneD(x, y, z, r_1, r_2):
ret = 0.0
for i in range(x+1):
for j in range(y+1):
m = i + j
if m % 2 == 0:
ret += np.exp(i+r_1)**(j+1) / (z+1+r_2)
return ret
def ThreeD(a,b,c, d, e):
value = OneD(a[0],b[0], c, d[0], e[0])
value *= OneD(a[1],b[1], c, d[1], e[1])
value *= OneD(a[2],b[2], c, d[2], e[2])
return value
M1 = M2 = np.array(([[0,0,0],[0,0,1], [1,1,1], [1,0,2]]), dtype=int)
scales0 = scales1 = np.array([1.1, 2.2, 3.3, 4.4])
cc0 = cc1 = cc2 =1.77 # for simplicity, all constants made the same
r1 = np.array([0.0,0.0,0.0])
r2 = r1 + 1.0
results = np.zeros((4,4))
for s0, n0, in enumerate(M1):
for s1, n1, in enumerate(M2):
v = ThreeD(n0, n1, cc2, r1, r2)
v *= cc0 * cc1 * scales0[s0] * scales1[s1]
results[s0, s1] += v
Similar to the vectorized/Broadcasted version created for the simpler problem linked at the start, I am trying to get rid of the for loops
and speed up the calculation by performing vectorized calls to function OneD
v = np.prod(OneD(M1[:,None,:], M2[None,:,:], np.arange(4)[None,:,None], r1, r2), axis=2)
results = v * cc0*cc1*np.array(scales0)[:,None]*np.array(scales1)[None,:]
The problem I have is that now, when using OneD
, scalars are not being passed, but instead arrays are appearing. This tells me I need to pad the arrays further (maybe go up 2 dimensions?)? I am struggling with padding the arrays correctly. I think I will need to make the arrays have more dimensions, and then squeeze them after, but I am unclear on how to do this. My numerous attempts have been wrong, and always keep on ending up sending arrays to OneD
. For this example I need to end up with a (4,4) array.
[[ 7.07469713e-02 1.41493943e-01 2.12240914e-01 5.65975771e-01]
[ 1.41493943e-01 2.37400124e+00 3.56100187e+00 5.31397826e+00]
[ 2.12240914e-01 3.56100187e+00 3.75915002e+02 6.68688926e+01]
[ 2.37400124e+00 8.93002921e+00 1.12371774e+02 3.99028687e+03]]