Spec-Zone.ru › NumPy 1.10

Обобщённый универсальный API функций

Существует общая потребность в циклическом переборе не только функций над скалярами, но и над векторами (или массивами). Эта концепция реализована в Numpy путём обобщения универсальных функций (ufuncs). В обычных ufuncs элементарная функция ограничена операциями по элементу, тогда как обобщённая версия (gufuncs) поддерживает операции «подмассива» по «подмассиву». Библиотека векторов Perl PDL предоставляет подобную функциональность, и её термины используются далее.

Каждая обобщённая ufunc содержит информацию о том, какова «базовая» размерность ввода, а также соответствующая размерность вывода (у функций по элементам — нулевая базовая размерность). Список базовых размерностей для всех аргументов называется «подписью» ufunc. Например, у функции numpy.add подпись (),()->() определяет два скалярных входа и один скалярный вывод.

Другой пример — функция inner1d(a, b) с подписью (i),(i)->(). Она применяет скалярное произведение по последней оси каждого входа, но сохраняет остальные индексы. Например, если a имеет форму (3, 5, N) и b имеет форму (5, N), то будет возвращён вывод с формой (3,5). Подлежащая элементарная функция вызывается 3 * 5 раз. В подписи мы указываем одну базовую размерность (i) для каждого входа и ноль базовых размерностей () для вывода, поскольку она принимает два одномерных массива и возвращает скаляр. Используя то же имя i, мы указываем, что соответствующие две размерности должны иметь одинаковый размер.

Размерности, выходящие за пределы базовых размерностей, называются «циклическими» размерностями. В приведённом выше примере это соответствует (3, 5).

Подпись определяет, как размерности каждого входного/выходного массива разбиваются на базовые и циклические размерности:

  1. Каждая размерность в подписи сопоставляется с размерностью соответствующего входного массива, начиная с конца кортежа формы. Это базовые размерности, и они должны быть в массивах, иначе будет поднято исключение.
  2. Базовые размерности, назначенные одному и тому же имени в подписи (например, i в inner1d's (i),(i)->()) должны иметь точно совпадающие размеры, никакое вещание не выполняется.
  3. Базовые размерности удаляются из всех входов, а оставшиеся размерности вещаются вместе, определяя циклические размерности.
  4. Форма каждого вывода определяется из циклических размерностей плюс базовые размерности вывода.

Как правило, размер всех базовых размерностей в выводе определяется размером базовой размерности с тем же именем в входном массиве. Это не является требованием, и можно определить подпись, где имя появляется впервые в выводе, хотя при вызове такой функции следует соблюдать некоторые меры предосторожности. Примером может служить функция euclidean_pdist(a), с подписью (n,d)->(p), которая, имея массив из n d-мерных векторов, вычисляет все уникальные парные евклидовы расстояния между ними. Таким образом, размерность вывода p должна быть равна n * (n - 1) / 2, но ответственность за передачу массива вывода с правильным размером лежит на вызывающей стороне. Если размер базовой размерности вывода нельзя определить из переданного входного или выходного массива, будет поднято исключение.

Примечание: до Numpy 1.10.0 применялись менее строгие проверки: отсутствующие базовые размерности создавались путём добавления 1 в начало формы по мере необходимости, базовые размерности с одинаковым именем вещались вместе, а неопределённые размерности создавались с размером 1.

Определения

Элементарная функция
Каждая ufunc состоит из элементарной функции, выполняющей самую базовую операцию над наименьшей частью аргументов массива (например, сложение двух чисел является самой базовой операцией при сложении двух массивов). Ufunc применяет элементарную функцию несколько раз к различным частям массивов. Вход/выход элементарных функций могут быть векторами; например, элементарная функция inner1d принимает два вектора в качестве входных данных.
Подпись
Подпись — это строка, описывающая размерности ввода/вывода элементарной функции ufunc. Более подробная информация приведена в разделе ниже.
Базовая размерность
Размерность каждого ввода/вывода элементарной функции определяется её базовыми размерностями (нулевые базовые размерности соответствуют скалярному вводу/выводу). Базовые размерности сопоставляются с последними размерностями входных/выходных массивов.
Имя размерности
Имя размерности представляет собой базовую размерность в подписи. Разные размерности могут иметь одинаковое имя, что указывает на то, что они имеют одинаковый размер.
Индекс размерности
Индекс размерности — это целое число, представляющее имя размерности. Он перечисляет имена размерностей в соответствии с порядком первого появления каждого имени в подписи.

Подробности подписи

Подпись определяет «базовую» размерность входных и выходных переменных, а также определяет сокращение размерностей. Подпись представлена строкой следующего формата:

  • Базовые размерности каждого входного или выходного массива представлены списком имён размерностей в скобках, (i_1,...,i_N); скалярный вход/выход обозначается как (). Вместо i_1, i_2, и т. д., можно использовать любое допустимое имя переменной Python.
  • Списки размерностей для разных аргументов разделяются символом ",". Аргументы ввода/вывода разделяются символом "->".
  • Если одно и то же имя размерности используется в нескольких местах, это накладывает ограничение на то, что соответствующие размерности должны иметь одинаковый размер.

Формальный синтаксис подписей выглядит следующим образом:

<Signature>            ::= <Input arguments> "->" <Output arguments>
<Input arguments>      ::= <Argument list>
<Output arguments>     ::= <Argument list>
<Argument list>        ::= nil | <Argument> | <Argument> "," <Argument list>
<Argument>             ::= "(" <Core dimension list> ")"
<Core dimension list>  ::= nil | <Dimension name> |
                           <Dimension name> "," <Core dimension list>
<Dimension name>       ::= valid Python variable name

Примечания:

  1. Все кавычки для ясности.
  2. Базовые размерности, которые имеют одинаковое имя, должны иметь точно такой же размер. Каждое имя размерности обычно соответствует одному уровню цикличности в реализации элементарной функции.
  3. Пробелы игнорируются.

Вот несколько примеров подписей:

add (),()->()
inner1d (i),(i)->()
sum1d (i)->()
dot2d (m,n),(n,p)->(m,p) умножение матриц
outer_inner (i,t),(j,t)->(i,j) внутреннее произведение по последней размерности, внешнее произведение по предпоследней, а цикл/вещание по остальным.

C-API для реализации элементарных функций

Текущий интерфейс остаётся неизменным, и PyUFunc_FromFuncAndData по-прежнему можно использовать для реализации (специализированных) ufuncs, состоящих из скалярных элементарных функций.

Можно использовать PyUFunc_FromFuncAndDataAndSignature для объявления более общей ufunc. Список аргументов такой же, как PyUFunc_FromFuncAndData, с дополнительным аргументом, указывающим подпись как строку C.

Кроме того, функция обратного вызова имеет тот же тип, что и раньше, void (*foo)(char **args, intp *dimensions, intp *steps, void *func). При вызове args — это список длиной nargs, содержащий данные всех входных/выходных аргументов. Для скалярной элементарной функции steps также имеет длину nargs, обозначая шаги, используемые для аргументов. dimensions — указатель на единственное целое число, определяющее размер оси, по которой выполняется цикл.

Для нетривиальной подписи dimensions также будет содержать размеры базовых размерностей, начиная со второго элемента. Для каждого уникального имени размерности предоставляется только один размер, а размеры предоставляются в соответствии с первым появлением имени размерности в подписи.

Первые nargs элементов steps остаются такими же, как и для скалярных ufuncs. Следующие элементы содержат шаги всех базовых размерностей для всех аргументов в порядке.

Например, рассмотрим ufunc с подписью (i,j),(i)->(). В этом случае args будет содержать три указателя на данные входных/выходных массивов a, b, c. Кроме того, dimensions будет [N, I, J] для определения размера N цикла и размеров I и J для базовых размерностей i и j. Наконец, steps будет [a_N, b_N, c_N, a_i, a_j, b_i], содержащий все необходимые шаги.

© 2008–2016 NumPy Developers
Licensed under the NumPy License.
https://docs.scipy.org/doc/numpy-1.10.1/reference/c-api.generalized-ufuncs.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API