Why does it say list rather than List in the function type?
While The function can be executed from the list with no problem, passing flist to another function will fail, (see the working example below) with
mismatch of argument types:
ListType[array(float64, 1d, C)]
vs list(array(float64, 1d, A))<iv=None>
I would be grateful for any pointers on why this happens and how to resolve this. A working code snippet showing this problem is below
import numba
from numba.core import types
from numba.typed import List
from numba import typeof, njit
import numpy as np
# create dummy data
def get_data() -> list:
m = np.linspace(0, 10)
l = np.linspace(0, 10)
d = np.linspace(0, 10)
return List([m, l, d])
# some function
@njit
def foo(l: list) -> None:
print(l[0][0])
print(l[1][0])
print(l[2][0])
# add data to list
dlist = List()
dlist.append(get_data())
# add function to list
flist = numba.typed.List.empty_list(
types.List(types.void)( # return value
types.List(types.float64[:]), # parameter 1
).as_type()
)
flist.append(foo)
# pass data and function list to bar, and execute foo
@njit
def bar(flist,dlist):
flist[0](dlist[0])
print(typeof(flist))
bar(flist,dlist)
The above code is failing because there’s two types of list in Numba and they appear differently in the type system (docs). Consider:
In [1]: from numba import typed, typeof
In [2]: x = typed.List(); x.append(3)
In [3]: y = [3]
In [4]: type(typeof(x))
Out[4]: numba.core.types.containers.ListType
In [5]: type(typeof(y))
Out[5]: numba.core.types.containers.List
the Numba type system type of a typed.List instance is a numba.core.types.containers.ListType whereas the Numba type system type of a python list is a numba.core.types.containers.List.
This matters in the example case above because the typed.List instance flist is being explicitly declared to take reflected lists.
Fixing up the code so the declared types are consistent with the instances present…
import numba
from numba.core import types
from numba.typed import List
from numba import typeof, njit
import numpy as np
# create dummy data
def get_data() -> list:
m = np.linspace(0, 10)
l = np.linspace(0, 10)
d = np.linspace(0, 10)
return List([m, l, d])
# some function
@njit
def foo(l: list) -> None:
print(l[0][0])
print(l[1][0])
print(l[2][0])
# add data to list
dlist = List()
dlist.append(get_data())
# add function to list
flist = numba.typed.List.empty_list(
types.ListType(types.void)( # return value
types.ListType(types.float64[::1]), # parameter 1
).as_type()
)
flist.append(foo)
# pass data and function list to bar, and execute foo
@njit
def bar(flist,dlist):
flist[0](dlist[0])
print(typeof(flist))
bar(flist,dlist)
(also note that it was necessary to make the ListType instance hold C-ordered float64 arrays types.float64[::1] opposed to “any” ordered as obtained via types.float64[:], though this could well be a Numba internal bug in resolving function types).
@luk-f-a might have an opinion/knowledge on the issue with the function type spelling? If it’s something strange it should go into an issue on the tracker. It might simply be that the error is not being caught explicitly or gracefully by the compiler.
if you mean having to use types.float64[::1] instead of types.float64[:], I suspect it’s because, unlike regular function calls (where type conversion is attempted), reading first-class functions from a container takes the function type as fixed and it fails unless it matches exactly. I’m not sure but I think that is what happens here: the function type is constraint and not a variable to the solver.