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?