I sure do!
numba has 2 different jit modes, 'object' mode and 'nopython' mode. Object mode runs no faster, or indeed sometimes slower than regular python. A lot of datatypes aren't supported within nopython mode, so jit functions that contain an custom classes, or dicts will product object mode code instead.
There is one caveat. Object mode code will run faster than regular python if it contains many loops that can be 'loop-jitted' I have no idea how this works, or how you can tell. I just trial and errored until I got it right.
You can see if a function works in nopython mode by decorating with @njit or @jit(nopython=True)
Create any necessary numpy arrays outside the jitted functions, and pass them in, don't create arrays inside jit functions. (I think returning new arrays used to be not supported. I think now it is supported but it is slightly slower)
How my code works:
I have 3 functions: 2 of them work in nopython mode and the third one takes advatage of loop-jitting.
def get_neighbours(point, rows, cols): # takes a point as a tuple (x,y) and returns all of its neighbours that aren't off the map. Not strictly necessary as it's own function but it makes the loops cleaner without a performance penalty
def explore_point(point_to_explore, rows, cols, inarray, dmask):
takes a point, runs get_neighbours() on it. Iterates through list it gets back.
for each neighbour, checks if dmask[neighbour] ==0
(# dmask is a numpy array initialized to zeros with the same shape as
the map. (inarray is the map)
inarray[neighbour] += (inarray[point_to_explore] + 1) #key piece of logic
This function then returns all of the neighbours it found that were not yet explored. (aka their mask was 0)
Third function runs the brushfire algorithm, and calls explore_point() in a loop it is decorated with @jit and runs in object mode. That being said, I dont use any halite special objects in it. Everything it knows about is either an array, a tuple or a list. I realize this is coming to the end of my post and I probably should've put it at the beginning, but don't pass any halite objects into a jit function, it is guaranteed to be slow then.
create a numpy array with the same shape as the map and set every cell that contains a unit to a 1. That array becomes the mask, and gets passed in to tell the algorithm which points are unpassable.
def jitfront(inarray, point, dmask ):
pointstoexplore = collections.deque() #This is why it runs in object mode. You can use a list if you want and it will compile in nopython mode and be an order of magnitude faster, but things seem to get weird for me.
epoint = pointstoexplore.popleft()
for nextoexplore in explore_point(epoint, rows, cols, inarray, dmask):
I realize the formatting is all horrible. Hopefully finding out where the indents are will be part of the fun