Hello,

I’d like to dynamically call a function based on an integer (fct_selector here).

I have several Python modules, each has a different compute function.

FCT_MODULES = [

a_first_module,

a_second_module,

…

]

@njit

def dispatch(fct_selector: int) → Any:

return FCT_MODULES[selector].compute()

How can I do this ?

Thank you

You can store first-class jitted functions into a typed list and then access the list with an integer index.

Thank you for your response.

I am trying this :

COMPUTE_DOMAINS_FUNCTIONS = List.empty_list(numba.typeof(compute_domains_affine_eq))

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_affine_eq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_affine_geq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_affine_leq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_alldifferent)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_count_eq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_dummy)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_exactly_eq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_lexicographic_leq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_max_eq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_max_leq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_min_eq)

COMPUTE_DOMAINS_FUNCTIONS.append(compute_domains_min_geq)

With (for example) :

@njit(“int64(int32[::1,:], int32[:])”, cache=True)

def compute_domains_dummy(domains: NDArray, data: NDArray) → int:

“”"

A propagator that does nothing.

“”"

return PROP_CONSISTENCY

Of course, all functions have the same signature.

But it does not work :

NumbaTypeSafetyWarning: unsafe cast from type(CPUDispatcher(<function compute_domains_affine_geq at 0x10f62bce0>)) to type(CPUDispatcher(<function compute_domains_affine_eq at 0x10f62bba0>)). Precision may be lost.

l.append(item)

I could not make it work with a global constant for the list.

But I could make it work with:

def init_compute_domains_functions() → List[Callable]:

functions = List.empty_list(types.int64(int32[::1, :], int32[:]).as_type())

functions.append(compute_domains_affine_eq)

functions.append(compute_domains_affine_geq)

functions.append(compute_domains_affine_leq)

functions.append(compute_domains_alldifferent)

functions.append(compute_domains_count_eq)

functions.append(compute_domains_dummy)

functions.append(compute_domains_exactly_eq)

functions.append(compute_domains_lexicographic_leq)

functions.append(compute_domains_max_eq)

functions.append(compute_domains_max_leq)

functions.append(compute_domains_min_eq)

functions.append(compute_domains_min_geq)

return functions

And passing this list to the jitted function that dispatches and executes the compute_domain functions.

BUT it is significantly slower.

I profiled the Python (with NUMBA_DISABLE_JIT=1) and nothing changed.

Could it be the case that accessing the ith element of the type list is slow ?

If the work being done in the function is small, the typed list overhead could be significant.

There are other techniques, like storing pointers to the functions in a numpy array or simply using an if-else construct, which may well be fastest.

Note that first-class functions return zero-initialized values if an exception is thrown. That is, exceptions are not propagated

Hello,

Thank you for your answer.

I was using the if-else already, I’ll give the numpy array of function pointers a try.

Cheers

Yan

Hello,

How can I, from a jitted function, call another jitted function with a pointer ?

Thank you,

Yan

See this post

TLDR. I usually use a custom intrinsic, not sure if the devs have added a standard way since that post.

Thank you very much, this is what I was looking for.

Of course my case was slightly more complex because I have an array of functions that I want to call based on a dynamic index but I was able to make it work !

Cheers,

Yan