1

I recently discovered that numba does indeed support function pointers: How to update a jitclass variable with its string name by passing a setter function to the jitclass itself?. Is it possible to construct an array of such pointers to a function?

Here is a MCVE:

from numba import float64
from numba.experimental import jitclass

t = None

@jitclass(spec={'a': float64,
                'ptrs': t[:]})
class Test:
    def __init__(self):
        self.a = 0
        self.ptrs = np.array([self.x, self.y])
    def x(self):
        self.a += 1
    def y(self):
        self.a += 2
    def increment(self, n):
        self.ptrs[n](self)

t = Test()
print(t.a)     # Desired: 0
t.increment(0)
print(t.a)     # Desired: 1
t.increment(1)
print(t.a)     # Desired: 3

Clearly with t = None, this raises an error, even without the [:] index to indicate an array.

If I set t = void, I get an error on the line t = Test():

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\experimental\jitclass\base.py", line 122, in __call__
    return cls._ctor(*bind.args[1:], **bind.kwargs)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 439, in _compile_for_args
    raise e
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 372, in _compile_for_args
    return_val = self.compile(tuple(argtypes))
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 909, in compile
    cres = self._compiler.compile(args, return_type)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 79, in compile
    status, retval = self._compile_cached(args, return_type)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 93, in _compile_cached
    retval = self._compile_core(args, return_type)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 106, in _compile_core
    cres = compiler.compile_extra(self.targetdescr.typing_context,
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 606, in compile_extra
    return pipeline.compile_extra(func)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 353, in compile_extra
    return self._compile_bytecode()
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 415, in _compile_bytecode
    return self._compile_core()
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 395, in _compile_core
    raise e
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 386, in _compile_core
    pm.run(self.state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 339, in run
    raise patched_exception
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 330, in run
    self._runPass(idx, pass_inst, state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_lock.py", line 35, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 289, in _runPass
    mutated |= check(pss.run_pass, internal_state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 262, in check
    mangled = func(compiler_state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\typed_passes.py", line 463, in run_pass
    NativeLowering().run_pass(state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\typed_passes.py", line 386, in run_pass
    lower.create_cpython_wrapper(flags.release_gil)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\lowering.py", line 242, in create_cpython_wrapper
    self.context.create_cpython_wrapper(self.library, self.fndesc,
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\cpu.py", line 162, in create_cpython_wrapper
    builder.build()
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\callwrapper.py", line 122, in build
    self.build_wrapper(api, builder, closure, args, kws)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\callwrapper.py", line 187, in build_wrapper
    obj = api.from_native_return(retty, retval, env_manager)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\pythonapi.py", line 1396, in from_native_return
    out = self.from_native_value(typ, val, env_manager)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\pythonapi.py", line 1410, in from_native_value
    return impl(typ, val, c)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\experimental\jitclass\boxing.py", line 139, in _box_class_instance
    box_subclassed = _specialize_box(typ)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\experimental\jitclass\boxing.py", line 122, in _specialize_box
    fast_fget = fget.compile((typ,))
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 909, in compile
    cres = self._compiler.compile(args, return_type)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 79, in compile
    status, retval = self._compile_cached(args, return_type)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 93, in _compile_cached
    retval = self._compile_core(args, return_type)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 106, in _compile_core
    cres = compiler.compile_extra(self.targetdescr.typing_context,
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 606, in compile_extra
    return pipeline.compile_extra(func)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 353, in compile_extra
    return self._compile_bytecode()
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 415, in _compile_bytecode
    return self._compile_core()
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 395, in _compile_core
    raise e
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler.py", line 386, in _compile_core
    pm.run(self.state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 339, in run
    raise patched_exception
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 330, in run
    self._runPass(idx, pass_inst, state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_lock.py", line 35, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 289, in _runPass
    mutated |= check(pss.run_pass, internal_state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\compiler_machinery.py", line 262, in check
    mangled = func(compiler_state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\typed_passes.py", line 463, in run_pass
    NativeLowering().run_pass(state)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\typed_passes.py", line 386, in run_pass
    lower.create_cpython_wrapper(flags.release_gil)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\lowering.py", line 242, in create_cpython_wrapper
    self.context.create_cpython_wrapper(self.library, self.fndesc,
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\cpu.py", line 162, in create_cpython_wrapper
    builder.build()
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\callwrapper.py", line 122, in build
    self.build_wrapper(api, builder, closure, args, kws)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\callwrapper.py", line 187, in build_wrapper
    obj = api.from_native_return(retty, retval, env_manager)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\pythonapi.py", line 1396, in from_native_return
    out = self.from_native_value(typ, val, env_manager)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\pythonapi.py", line 1410, in from_native_value
    return impl(typ, val, c)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\boxing.py", line 397, in box_array
    np_dtype = numpy_support.as_dtype(typ.dtype)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\np\numpy_support.py", line 156, in as_dtype
    raise NotImplementedError("%r cannot be represented as a Numpy dtype"
NotImplementedError: Failed in nopython mode pipeline (step: nopython mode backend)
Failed in nopython mode pipeline (step: nopython mode backend)
none cannot be represented as a Numpy dtype

I then tried setting t to an array of function pointers to x and y:

from numba import float64, intp, void, deferred_type
tt = deferred_type()
t = void(tt, intp)

The error from 'ptrs': t[:]}) was:

Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
TypeError: 'Signature' object is not subscriptable

Finally, I tried t = void. This gave the error during compilation on the line t = Test():

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\experimental\jitclass\base.py", line 122, in __call__
    return cls._ctor(*bind.args[1:], **bind.kwargs)
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 420, in _compile_for_args
    error_rewrite(e, 'typing')
  File "C:\Users\madphysicist\Anaconda3\lib\site-packages\numba\core\dispatcher.py", line 361, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
NameError: name 'np' is not defined
During: resolving callee type: jitclass.Test#1bbda3d32e0<a:float64,ptrs:array(none, 1d, A)>
During: typing of call at <string> (3)

During: resolving callee type: jitclass.Test#1bbda3d32e0<a:float64,ptrs:array(none, 1d, A)>
During: typing of call at <string> (3)


File "<string>", line 3:
<source missing, REPL/exec in use?>

So how can I make an array of function pointers?

1 Answer 1

1

Storing Numba functions into a Numpy array is not supported yet. At least not in nopython mode in the version 0.54.1 (and previous ones).

One way to check that experimentally is to simply edit the documentation code and store the result in an array and then let Numba deduce the types accordingly. Numba fail by arguing the dtype of the array is not supported.

Another way to check that is to read the code of the numpy_support.py in the repository. This file contains the currently supported types. I listed the following:

Basic types:
    - bool
    - int8
    - int16
    - int32
    - int64
    - uint8
    - uint16
    - uint32
    - uint64
    - float32
    - float64
    - complex64
    - complex128

Advanced types:
    - Datetime
    - Timedelta
    - CharSeq (mark as 'S' in Numpy)
    - UnicodeCharSeq (mark as 'U' in Numpy)
    - Numpy structured types (containing other ones like Numpy does)

Generic type:
    - object (unsupported in nopython mode since the type inference cannot work with it)

Other (unknown) types:
    - EnumMember
    - NumberClass
    - NestedArray
Sign up to request clarification or add additional context in comments.

1 Comment

I will select in a bit if nothing better comes up.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.