1

What is the problem with the use of np.min here? Why doesn't numba like using a list in that function, is there some other way to get np.min to work?

from numba import njit
import numpy as np

@njit
def availarray(length):
    out=np.ones(14)
    if length>0:
        out[0:np.min([int(length),14])]=0
    return out

availarray(3)

The function works fine with min but np.min should be faster...

MSeifert
  • 145,886
  • 38
  • 333
  • 352
Kingle
  • 496
  • 1
  • 6
  • 20
  • In general one should avoid using NumPy functions on Python lists -and- Python functions on NumPy arrays (see for example https://stackoverflow.com/a/49908528/539338). But that doesn't apply to numba functions because numba doesn't use Python lists, instead it uses a homogeneous-type version of Pythons list. Numba also replaces all function calls to built-in or NumPy functions with their own implementation of these. So you cannot really make arguments about the performance of numba functions based on experience from non-numba implementations - one really needs to measure the performance. – MSeifert Mar 03 '19 at 19:19

2 Answers2

3

The problem is that the numba version of np.min requires an array as input.

from numba import njit
import numpy as np

@njit
def test_numba_version_of_numpy_min(inp):
    return np.min(inp)

>>> test_numba_version_of_numpy_min(np.array([1, 2]))  # works
1

>>> test_numba_version_of_numpy_min([1, 2]) # doesn't work
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<function amin at 0x000001B5DBDEE598>) with argument(s) of type(s): (reflected list(int64))
 * parameterized
In definition 0:
    All templates rejected with literals.
In definition 1:
    All templates rejected without literals.
This error is usually caused by passing an argument of a type that is unsupported by the named function.

The better solution would be to just use the numba version of Pythons min:

from numba import njit
import numpy as np

@njit
def availarray(length):
    out = np.ones(14)
    if length > 0:
        out[0:min(length, 14)] = 0
    return out

Since both np.min and min are actually Numba versions of these functions (at least in njitted functions) min should also be much faster in this case. However it's unlikely to be noticeable because the allocation of the array and setting some of the elements to zero will be the dominant runtime contributors here.

Note that you don't even need the min call here - because slicing implicitly stops at the end of the array even if a bigger stop index is used:

from numba import njit
import numpy as np

@njit
def availarray(length):
    out = np.ones(14)
    if length > 0:
        out[0:length] = 0
    return out
MSeifert
  • 145,886
  • 38
  • 333
  • 352
0

To make your code work with numba, you will have to apply np.min on a NumPy array which means you will have to convert your list [int(length),14] to a NumPy array as following

from numba import njit
import numpy as np

@njit
def availarray(length):
    out=np.ones(14)
    if length>0:
        out[0:np.min(np.array([int(length),14]))]=0   
    return out

availarray(3)
# array([0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
Sheldore
  • 37,862
  • 7
  • 57
  • 71
  • 1
    Seems like that would be more computationally expensive than just using min(int(length), 14)? – Kingle Mar 03 '19 at 18:53