0

This is related to another question I have except there I am looking for a vectorized/broadcasting solution.

Here I am hoping to try using np.fromfunction but am having issues.

The MWE is

# L1 and L2 will range from 0 to 3 typically, sometimes up to 5
# all of the following are dummy values but match correct `type`
L1, L2, x1, x2, fac = 2, 3, 2.0, 4.5, 2.3
saved_values = np.random.uniform(high=75.0, size=[max(L1,L2) + 1, max(L1,L2) + 1]) 
facts = np.random.uniform(high=65.0, size=[L1 + L2 + 1])
val = 0

for i in range(L1+1):
    sf = saved_values[L1][i] * x1 ** (L1 - i)
    for j in range(L2 + 1):
        m = i + j
        if m % 2 == 0:
            num = sf * facts[m] / (2 * fac) ** (m / 2)
            val += saved_values[L2][j] * x1 ** (L1 - j) * num

rather than use a double for loop, which is not vectorized and potentially slower (being vectorized is more important for me), I would like to use np.fromfunction to fill a matrix with the necessary values

I tried the following

matrix = np.fromfunction(lambda i, j:
                         saved_values[L1][i] * x1 ** (L1 - i) *
                         saved_values[L2][j] * x2 ** (L2 - j) *
                         facts[i+j] / (2 * fac) **( (i+j) / 2),
                         (L1+1,L2+1)
                         )

This generates the double for loop matrix, I then need to go over it and make anything that would fail (i+j) % 2 == 0 have a zero value, and then sum all elements in the matrix.

However

I get the following error

Traceback (most recent call last):                                                                                                                                                 
  File "main.py", line 54, in <module>                                                                                                                                             
    (L1+1,L2+1)                                                                                                                                                                    
  File "/usr/lib/python3/dist-packages/numpy/core/numeric.py", line 1808, in fromfunction                                                                                          
    return function(*args,**kwargs)                                                                                                                                                
  File "main.py", line 53, in <lambda>                                                                                                                                             
    facts[i+j] / (2 * fac) **( (i+j) / 2),                                                                                                                                         
IndexError: arrays used as indices must be of integer (or boolean) type
Dilbert
  • 101
  • 2
  • `fromfunction` does not 'vectorize'. When you have problems like this, write a small function that shows you what the `i,j` actually are. – hpaulj Jun 26 '20 at 11:39

1 Answers1

2

As I suppose, you think that the function passed as the first parameter to np.fromfunction is called several times, for each combination of i and j.

Unfortunately, this is not the case. To see the actual way how it operates, make such experiment:

def myFun(i, j):
    print(f'myFun:\n{i.shape}\n{i}\n{j.shape}\n{j}')
    rv = i + j
    return rv

I deliberately put a trace printout, to show what I mean.

Then run it:

np.fromfunction(myFun, (2, 3))

The result is:

myFun:
(2, 3)
[[0. 0. 0.]
 [1. 1. 1.]]
(2, 3)
[[0. 1. 2.]
 [0. 1. 2.]]

array([[0., 1., 2.],
       [1., 2., 3.]])

The first part is the printout, occuring only once and the second - the actual result. Note that:

  • shapes of both i and j are (2,3),
  • both i and j are actually arrays, not integers,
  • the whole computation is performed by addition of both arrays.

So the conclusions are that:

  • the passed function operates in a vectorized way, on arrays of parameters, adding respective elements and returning the result,
  • your concept is probably impossible to implement.
Valdi_Bo
  • 30,023
  • 4
  • 23
  • 41
  • can't I just make an arbitrary myfunc that depends on i,j, and also an array whose indice uses the i, j, and do that? – Dilbert Jun 26 '20 at 17:10
  • Yes, you can. But this function must be invoked in 2 nested loops, not using *np.fromfunction*. – Valdi_Bo Jun 26 '20 at 17:46
  • I can't use loops. Everything here is scalar, but the real problem is vectors. I am trying to get rid of the `for loops` so that I have a vectorized solution that can be passed arrays. i.e., `m % 2 == 0` breaks vectorization, as does the for loops themselves since they have `range(L1+1)` etc. i.e., I need to evaluate that loop passing the `x` and `y` and `z` components of vectors. It is currently set up for only 1 dimension to be passed. – Dilbert Jun 26 '20 at 18:00