Numba 0.46.0 Release Demo

This notebook contains a demonstration of new features present in the 0.46.0 release of Numba. Whilst release notes are produced as part of the CHANGE_LOG, there's nothing like seeing code in action! It should be noted that this release does not contain a huge amount of changes to user facing support. A lot of the changes to the code base this time around were to continue to enhance Numba's use as a compiler toolkit and add features for advanced users/developers.

Some exciting news... The Numba team finally started working on, the colloquially named, "scumba" project, to add SciPy support in Numba, the project is called numba-scipy (it's expected that there may be other numba-XYZ projects). This project also demonstrates a new feature added in this release, that Numba now has a formal way to register a project with Numba itself via an auto-discovery mechanism. Read more about this mechanism here. A demonstration of numba-scipy appears later in this notebook.

For users of Numba, demonstrations of new features include:

In addition, predominantly for library developers/compiler engineers, new features include:

  • The addition of the 'inline' kwarg to both the @numba.jit family of decorators and @numba.extending.overload.
  • A new compiler API to permit extension and definition of:
    • The compiler itself.
    • The compiler pipeline.
    • Compiler passes.
  • Support for module at a time jit application.

These are demonstrated in a separate notebook here.

First, import the necessary from Numba and NumPy...

In [ ]:
from numba import jit, njit, config, __version__, errors
from numba.extending import overload
import numba
import numpy as np
assert tuple(int(x) for x in __version__.split('.')[:2]) >= (0, 46)

🎉 Using SciPy from Numba 🎉

As noted above, the 0.46 release cycle saw the Numba core developers start work on a new community driven project called numba-scipy. This project adds support for using SciPy functions in Numba JIT'd code, at present it's in its very infancy but, with thanks to external contributors, some functionality is already present (docs are here). Below is an example of using scipy.special.* functions in JIT code.

In [ ]:
from scipy import special

@njit
def call_scipy_in_jitted_code():
    print("special.beta(1.2, 3.4)", special.beta(1.2, 3.4))
    print("special.j0(5.6)       ", special.j0(5.6))
    
call_scipy_in_jitted_code()

The above also nicely highlights the automatic extension registration working (docs are here), note how numba-scipy did not need to be imported to make use of the scipy.special functions, all that was needed was to install numba-scipy package in the current Python environment.

It should be noted that contributions to numba-scipy are welcomed, a good place to start is the contributing guide to get set up and then the guide to @overloading.

Newly supported NumPy functions/features

This release contains a number of newly supported NumPy functions, all written by contributors from the Numba community:

  • The long awaited support for np.cross is added along with the extension numba.numpy_extensions.cross2d for cases where both inputs have shape[-1] == 2.
  • The repeatedly requested np.array_equal is now supported.
  • Also now supported are:
    • np.count_nonzero
    • np.append
    • np.triu_indices
    • np.tril_indices
    • np.triu_indices_from
    • np.tril_indices_from

A quick demo of the above:

In [ ]:
from numba import numpy_extensions

@njit
def numpy_new():

    arr = np.array([[0, 2], [3 ,0]])
        
    # np.count_nonzero
    print("np.count_nonzero:\n", np.count_nonzero(arr))
    
    # np.append
    print("np.append:\n", np.append(arr, arr))

    # np.array_equal
    print("np.array_equal:\n", np.array_equal(arr, arr))
    
    # np.tri{u,l}_indices
    print("np.triu_indices:\n",np.triu_indices(4, k=2))
    print("np.tril_indices:\n",np.tril_indices(3, k=2))
    
    # np.tri{u,l}_indices_from
    print("np.triu_indices_from:\n",np.triu_indices_from(arr, k=0))
    print("np.tril_indices_from:\n",np.tril_indices_from(arr, k=2))
    
    # np.cross
    a = np.array([[1, 2, 3], [4, 5, 6]])
    b = np.array([[4, 5, 6], [1, 2, 3]])
    print("np.cross", np.cross(a, b))
    
    # np.cross, works fine unless `shape[-1] == 2` for both inputs
    # where it becomes impossible to statically determine the shape
    # of the return type, in this case replace `np.cross` with the
    # `numba.numpy_extensions.cross2d` function. e.g.
    c = np.array([[1, 2], [4, 5]])
    d = np.array([[4, 5], [1, 2]])
    print("numpy_extensions.cross2d", numpy_extensions.cross2d(c, d))
    
numpy_new()

dtype support in np.sum

Numba 0.46 has support added for the dtype kwarg in np.sum and np.ndarray.sum, this has been repeatedly requested and was kindly implemented by a member of the Numba community. A quick demo:

In [ ]:
@njit
def np_sum_demo():
    x = np.arange(10)
    x_sum = x.sum(dtype=np.complex128)
    
    y = np.arange(24).reshape((4, 6)).astype(np.uint8)
    y_sum = np.sum(y, axis=1, dtype=np.uint16)
    
    return (x_sum, y_sum)

print(np_sum_demo())

NumPy unicode array support

With thanks to another contributor from the Numba community, Numba can now consume and operate on NumPy arrays with a unicode dtype.

In [ ]:
from numba.typed import List
@njit
def unicode_array_demo(arr):
    acc = List()
    for i in (13, 20, 12, 1, 0, 28, 8, 18, 28, 27, 26):
        acc.append(str(arr[i]))
    return ''.join(acc)

arr = np.array([chr(x) for x in range(ord('a'), ord('a') + 26)] + ['⚡', '🐍', chr(32)])
unicode_array_demo(arr)

Miscellaneous features

Some new features were added that don't fit anywhere in particular but are still very useful...

Just one in this section for 0.46, .count() is supported on Unicode strings (also contributed by a Numba community member!).

In [ ]:
@njit
def demo_misc():
     print("n🐍u🐍m🐍b🐍a⚡".count("🐍")) # count the snakes

demo_misc()