Итерация по кортежу во время jit-компиляции в numba - PullRequest
0 голосов
/ 27 сентября 2018

Есть ли способ в объединенной функции numba для оценки каждой функции в кортеже (или списке) функций во время компиляции?

Обратите внимание, что этот вопрос о как использоватьЦикл Python для создания jit-кода во время компиляции , а не итерации по кортежу во время выполнения, что, я знаю, не поддерживается.

Полный нерабочий пример приведен ниже, но суть егочто следующее работает:

@jit(nopython=True)
def do_stuff(func_tuple):
    results = []
    results.append(func_tuple[0]())
    results.append(func_tuple[1]())
    results.append(func_tuple[2]())
    results.append(func_tuple[3]())
    return results

, а следующее - нет:

@jit(nopython=True)
def do_stuff_2(func_tuple):
    results = []
    for i in range(4):
        results.append(func_tuple[i]())
    return results

Сообщение об ошибке выглядит следующим образом, и его значение совершенно ясно: индексация в такой кортеж неподдерживается во время выполнения.

Invalid usage of getitem with parameters ((type(CPUDispatcher(<function f1 at 0x116968268>)), type(CPUDispatcher(<function f2 at 0x1169688c8>)), type(CPUDispatcher(<function f3 at 0x1169a1b70>)), type(CPUDispatcher(<function f4 at 0x1169a1f28>))), int64)
 * parameterized
[1] During: typing of intrinsic-call at numba_minimal_not_working_example_2.py (36)

File "numba_minimal_not_working_example_2.py", line 36:
def do_stuff_2(func_tuple):
    <source elided>
    for i in range(4):
        results.append(func_tuple[i]())
  ^

Однако мне нужно, чтобы индексирование происходило только во время компиляции - я просто хочу генерировать функции, подобные do_stuff, но делать это автоматически в зависимости от количества элементов в кортеже.

В принципе это может произойти во время компиляции, потому что numba считает длину кортежа частью его типа.Но я не смог понять, как это сделать.Я пробовал различные трюки с использованием рекурсии и / или декоратора @generated_jit, но мне не удалось найти что-то, что работает.Есть ли способ достичь этого?

Вот полный пример:

from numba import jit

@jit(nopython=True)
def f1():
    return 1

@jit(nopython=True)
def f2():
    return 2

@jit(nopython=True)
def f3():
    return 3

@jit(nopython=True)
def f4():
    return 4

func_tuple = (f1, f2, f3, f4)

# this works:
@jit(nopython=True)
def do_stuff(func_tuple):
    results = []
    results.append(func_tuple[0]())
    results.append(func_tuple[1]())
    results.append(func_tuple[2]())
    results.append(func_tuple[3]())
    return results

# but this does not:
@jit(nopython=True)
def do_stuff_2(func_tuple):
    results = []
    for i in range(4):
        results.append(func_tuple[i]())
    return results

# this doesn't either (similar error to do_stuff_2).
@jit(nopython=True)
def do_stuff_3(func_tuple):
    results = [f() for f in func_tuple]
    return results


print(do_stuff(func_tuple)) # prints '[1, 2, 3, 4]'

print(do_stuff_2(func_tuple)) # gives the error above

#print(do_stuff_3(func_tuple)) # gives a similar error

1 Ответ

0 голосов
/ 27 сентября 2018

Это на самом деле известное ограничение Numba .Это также как-то упоминается в трассировке, которую вы получаете .

По сути, когда вы запрашиваете @jit вашу функцию, Numba не может правильно определить типы для скомпилированного кода.

Одним из обходных путей может быть использование @jit(nopython=False) на do_stuff_2(), которое затем сможет обрабатывать такой код, используя систему объектов Python.Вместо этого вы не сможете @jit функцию do_stuff_3(), даже с nopython=False, поскольку numba не поддерживает понимания (по крайней мере, до версии 0.39.0).

...