0

I am trying to parallelize a for-loop with numba. I'm new to this library, but after some research I crafted this code, which looked correct in comparison to the examples I studied:

@njit(nopython=True, parallel=True)
def tempFtemp(ftemp_pte, func_F, numPointsEval, pointsToEval):
for i in prange(0, numPointsEval):
    ftemp_pte[:,i] = np.hstack(func_F(np.vstack(pointsToEval[:,i])))
return ftemp_pte

ftemp_pte= tempFtemp(ftemp_pte, func_F, numPointsEval, pointsToEval)

When i compile it in my program thought, i get the error "non-precise type pyobject" at the line for i in prange(0, numPointsEval):. Both ftemp_pteand pointsToEvalare 2d arrays, numPointsEvalis an integer and func_Fis a random function which will produce the 1d arrays to be stored in ftemp_pte[:,i].

Any help on how to figure out what is producing this error would be greatly appreciated.

[EDIT]

The sequential code i have initially (which works) is the following:

def func_F(x):
    f= np.zeros((1,2))
    f[0,0]= x[0,0]
    n= max(np.size(x,0), np.size(x,1))    
    g    = 1 + 9* np.sum(x[1:n])/(n-1)
    h    = 1 - np.sqrt(f[0,0]/g)
    f[0,1] = g * h
    F= np.transpose(f)
    return F

for i in range(0, numPointsEval):
   ftemp_pte[:,i] = np.hstack(func_F(np.vstack(pointsToEval[:,i])))

I also should mention that the use of hstackand vstack is needed, so that the format of the arrays created can match ftemp_ptearray. Removing those instructions would result in a mismatch of dimensions.

The variable ftemp_pte always has 2 rows and x columns. One example of the correct values is

[[0.21875   0.21875   0.21875   0.21875   0.21875   0.21875   0.21875
  0.21875   0.21875   0.21875   0.21875   0.21875   0.21875   0.21875
  0.21875   0.21875   0.21875   0.21875   0.21875   0.21875   0.21875
  0.21875   0.21875   0.21875   0.21875   0.21875   0.21875   0.21875
  0.21875  ]
 [0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286
  0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286
  0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286
  0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286 0.5397286
  0.5397286]]

The original purpose of my code is to translate to Python the following Matlab's parfor instruction

parfor i=1:numPointsEval
     ftemp_pte(:,i) = feval(func_F,pointsToEval(:,i));

Any help would be greatly appreciated

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

2 Answers2

1

Answer to problem #2.

As long as you are not really stacking arrays, but reshaping them, you should avoid hstack() and vstack() and consider using reshape() or ravel(). This way for example:

ftemp_pte[:, i] = func_F(pointsToEval[:, i].reshape(1, -1)).ravel()

However, reshape() on non-contiguous arrays is not supported by numba.

So I have managed to make your code run with numba by transposing everything to avoid reshaping arrays. The following code does work and may give you some ideas:

@nb.njit
def func_F(x):
    f = np.zeros(2)    # Simple 1d array
    f[0] = x[0]
    n = max(x.shape)
    g = 1 + 9 * np.sum(x[1:n]) / (n - 1)
    h = 1 - np.sqrt(f[0] / g)
    f[1] = g * h
    return f

@nb.njit(parallel=True)
def tempFtemp(ftemp_pte, func_F, numPointsEval, pointsToEval):
    for i in nb.prange(numPointsEval):
        ftemp_pte[i] = func_F(pointsToEval[i])
    return ftemp_pte

ftemp_pte = np.zeros((2, 5)).T
pointsToEval = np.zeros((2, 5)).T
numPointsEval = 5
ftemp_pte = tempFtemp(ftemp_pte, func_F, numPointsEval, pointsToEval)
print(ftemp_pte.T)
aerobiomat
  • 2,883
  • 1
  • 16
  • 19
  • Thank you very much for your help. The code did not work but i will try to find another alternative to doing so and i will be changing the ```vstack```and ```hstack```operations for your suggested ones – Luis Monteiro May 28 '21 at 09:58
0

The docs say that first-class function objects can be Numba cfunc compiled functions, JIT compiled functions, and objects that implement the Wrapper Address Protocol.

You can pass a JITted function, as in this simplified example:

@nb.njit
def cos(a):
    return np.cos(a)

@nb.njit(parallel=True)
def tempFtemp(ftemp_pte, func_F, numPointsEval, pointsToEval):
    for i in nb.prange(numPointsEval):
        ftemp_pte[:, i] = func_F(pointsToEval[:, i])
    return ftemp_pte

ftemp_pte = tempFtemp(ftemp_pte, np.cos, numPointsEval, pointsToEval)  # Error
ftemp_pte = tempFtemp(ftemp_pte, cos, numPointsEval, pointsToEval)     # Works

This solves the "non-precise type pyobject" problem, but I have deleted the hstack and vstack operations from the example because they produce their own problems and inefficiencies.

aerobiomat
  • 2,883
  • 1
  • 16
  • 19
  • Thank you for the help, sadly it still does not work. Imma edit my post with the following problem after trying your suggestion – Luis Monteiro May 27 '21 at 15:58
  • According to the new error message, the problem happens when `func_F()` is called in `tempFunc_F()`. This may be because of the function itself or the parameters you are passing to it. You should post the simplest version of `func_F()` and data passed to it that the problem can be reproduced. – aerobiomat May 27 '21 at 16:19
  • Ok thank for very much. I will edit the post so i provide all the necessary info. Really appreciate your help – Luis Monteiro May 27 '21 at 16:27
  • I updated the question and gave all the details needed i think. I would trully appreciate your help, been debating with this problem for days – Luis Monteiro May 27 '21 at 18:41
  • could you give me some feedback please? – Luis Monteiro May 27 '21 at 22:04
  • Sorry, European time here. Without sample input arrays one can only guess. I can only make your code work with 2xn arrays. Is that a correct assumption? – aerobiomat May 28 '21 at 09:11
  • @areobiomat no problem, thanks for still trying to help. The main idea of my problem was to convert a Matlab's parfor operation into Python to be honest, using Numba and my sequential version were only the ways i got further with. I will put right now the original Matlab line and if you could help me either with Numba, ProcessPoolExecutor or multiprocesing.Pool you would be helping me so much – Luis Monteiro May 28 '21 at 09:31
  • I have added an additional answer. I don't know whether it will solve your problem, but may give you some ideas. – aerobiomat May 28 '21 at 09:40
  • @areobiomat just provided some context about the correct values of ```ftemp_pte``` should have after those cicles, since this loop is inside another loop – Luis Monteiro May 28 '21 at 09:44
  • Thank you very much, i will try using it now – Luis Monteiro May 28 '21 at 09:47