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
1
  • fromfunction does not 'vectorize'. When you have problems like this, write a small function that shows you what the i,j actually are. Commented Jun 26, 2020 at 11:39

1 Answer 1

4

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.
Sign up to request clarification or add additional context in comments.

3 Comments

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?
Yes, you can. But this function must be invoked in 2 nested loops, not using np.fromfunction.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.