Using parallel parameter in numba.jit decoratior function does wrong result

For two opposite corners of the rectangle (x1, y1) and (x2, y2) and two radii r1 and r2 find the ratio of the points located between the circles defined by the radii r1 and r2 to the total number of points in the rectangle.

NumPy simple approach:

 def func_1(x1,y1,x2,y2,r1,r2,n): x11,y11 = np.meshgrid(np.linspace(x1,x2,n),np.linspace(y1,y2,n)) z1 = np.sqrt(x11**2+y11**2) a = np.where((z1>(r1)) & (z1<(r2))) fill_factor = len(a[0])/(n*n) return fill_factor 

Next, I tried to optimize this function using the jit decorator. When i use:

 nopython = True 

The function is faster and gives the correct output. But when I also add:

 parallel = True 

The function is faster, but gives the wrong result. I know this has something to do with my z matrix, as it is not being updated properly.

 @jit(nopython=True,parallel=True) def func_2(x1,y1,x2,y2,r1,r2,n): x_ = np.linspace(x1,x2,n) y_ = np.linspace(y1,y2,n) z1 = np.zeros((n,n)) for i in range(n): for j in range(n): z1[i][j] = np.sqrt((x_[i]*x_[i]+y_[j]*y_[j])) a = np.where((z1>(r1)) & (z1<(r2))) fill_factor = len(a[0])/(n*n) return fill_factor 

Tested Values:

 x1 = 1.0 x2 = -1.0 y1 = 1.0 y2 = -1.0 r1 = 0.5 r2 = 0.75 n = 25000 

Additional info: Python version: 3.6.1, Numba version: 0.34.0 + 5.g1762237, NumPy version: 1.13.1

+1
python numpy jit numba
source share
1 answer

The problem with parallel=True is that it is a black box. Numba does not even guarantee that it will actually parallelize anything. He uses heuristics to find out if it is parallelized and what can be done in parallel. They may fail, and in your example they do not work, as in my experiments with parallel and numba . This makes parallel unreliable, and I would advise against using it!

In newer versions (0.34) prange added, and you might be more fortunate. It cannot be applied in this case, because prange works like range and is different from np.linspace ...

Just note: you can avoid creating z and run np.where completely in your function, you can just do the checks explicitly:

 import numpy as np import numba as nb @nb.njit # equivalent to "jit(nopython=True)". def func_2(x1,y1,x2,y2,r1,r2,n): x_ = np.linspace(x1,x2,n) y_ = np.linspace(y1,y2,n) cnts = 0 for i in range(n): for j in range(n): z = np.sqrt(x_[i] * x_[i] + y_[j] * y_[j]) if r1 < z < r2: cnts += 1 fill_factor = cnts/(n*n) return fill_factor 

This should also provide some acceleration compared to your function, perhaps even more than using parallel=True (if it works correctly).

0
source share

All Articles