1
votes

I have a function in which I do some operations and want to speed it up with numba. In my code changing the values in an array with advanced indexing is not working. I think they do say that in the numba documents. But what is a workaround for like numpy.put()?

Here a short example what I want to do:

#example array
array([[ 0,  1,  2],
       [ 0,  2, -1],
       [ 0,  3, -1]])

changeing the values at given indexes with any method working in numba...to get: changed values at:[0,0], [1,2], [2,1]

#changed example array by given indexes with one given value (10)
array([[ 10,  1,  2],
       [ 0,  2, 10],
       [ 0,  10, -1]])

Here what I did in python, but not working with numba:

indexList is a Tuple, which works with numpy.take()

This is the working example python code and the values in the array change to 100.

x = np.zeros((151,151))
print(x.ndim)
indexList=np.array([[0,1,3],[0,1,2]])
indexList=tuple(indexList)

def change(xx,filter_list):
    xx[filter_list] = 100
    return xx

Z = change(x,indexList)

Now using @jit on the function:

@jit
def change(xx,filter_list):
    xx[filter_list] = 100
    return xx

Z = change(x,indexList)

Compilation is falling back to object mode WITH looplifting enabled because Function "change" failed type inference due to: No implementation of function Function() found for signature: setitem(array(float64, 2d, C), UniTuple(array(int32, 1d, C) x 2), Literalint)

This error comes up. So I need a workaround for this. numpy.put() is not supported by numba.

I would be greatful for any ideas.

Thankyou

2
Why do you want to use numba for this operation? This is a build in numpy operation and even though numba might be faster for smaller arrays, for larger arrays it will be almost always be just as fast...mandulaj
Thankyou for your response! This Operation in my example takes place about 3 times in a bigger for loop at every iteration. the Code above is just an example to show what I want to do with numba or what is not working.Louis
I searched the forum for this problem, but could not find any solution. Only regarding the numpy.take() operation I could find but I need the reverse operation of that.Louis

2 Answers

1
votes

If it's not a problem for your to keep the indexList as an array you can use it in conjunction with for loops in the change function to make it compatible with numba:

indexList = np.array([[0,1,3],[0,1,2]]).T

@njit()
def change(xx, filter_list):
    for y, x in filter_list:
        xx[y, x] = 100
    return xx
change(x, indexList)

Note that the indexList has to be transposed in order to have the y, x coordinates along the 1st axis. In other words, it has to have a shape of (n, 2) rather than (2, n) for the n points to be change. Effectively it's now a list of coordinates: [[0, 0],[1, 1],[3, 2]]

1
votes

@mandulaj posted the way to go. Here a little different way I went before mandulaj gave his answer.

With this function I get a deprecation warning...so best way to go with @mandulaj and dont forget to transpose the indexList.

@jit
def change_arr(arr,idx,val): # change values in array by np index array to value
    for i,item in enumerate(idx):
        arr[item[0],item[1]]= val
    return arr