Создание нового скаляра numpy через C API и реализация пользовательского представления

Укороченная версия

Учитывая встроенный тип данных quaternion, как я могу просмотреть массив кватернионов numpy как массив numpy поплавков с дополнительным измерением размера 4 (без копирования памяти)?

Длинная версия

Numpy имеет встроенную поддержку поплавков и сложных поплавков. Мне нужно использовать кватернионы, которые обобщают комплексные числа, но вместо двух компонентов они есть четыре. Уже есть очень хороший пакет, который использует C API для включения кватернионов непосредственно в numpy, что, похоже, делает все операции идеально быстрые. Есть еще несколько функций кватерниона, которые мне нужно добавить, но я думаю, что в основном справлюсь те.

Однако я также хотел бы иметь возможность использовать эти кватернионы в других функциях, которые мне нужно написать, используя удивительный numba пакет. К сожалению, в настоящее время numba не может работать с пользовательскими типами. Но мне не нужны причудливые функции кватерниона в этих нумерованных функциях; Мне просто нужны сами цифры. Поэтому я хотел бы иметь возможность просто преобразовать массив кватернионов в массив поплавков с одним дополнительным измерением (размером 4). В частности, я хотел бы просто использовать данные, которые уже находятся в массиве, без копирования, и просматривать их как новый массив. Я нашел функцию PyArray_View, но я не знаю, как это реализовать.

(Я почти уверен, что данные хранятся в памяти непрерывно, что, как я полагаю, потребуется для их простого просмотра. В частности, /numpy_quaternion.c#L546-L547" rel="nofollow noreferrer">elsize = 8*4 и alignment = 8 в пакете quaternion.)


person Mike    schedule 15.10.2014    source источник


Ответы (1)


Оказалось, это было довольно легко. Магия numpy означает, что это уже возможно. Размышляя об этом, я просто попробовал следующее со сложными числами:

import numpy as np
a = np.array([1+2j, 3+4j, 5+6j])
a.view(np.float).reshape(a.shape[0],2)

И это дало именно то, что я искал. Каким-то образом та же основная идея работает с типом кватерниона. Я предполагаю, что внутренности просто полагаются на это elsize, делят на sizeof(float) и используют это, чтобы установить новый размер в последнем измерении???

Чтобы ответить на мой собственный вопрос, ту же идею можно применить к модулю кватерниона:

import numpy as np, quaternions
a = np.array([np.quaternion(1,2,3,4), np.quaternion(5,6,7,8), np.quaternion(9,0,1,2)])
a.view(np.float).reshape(a.shape[0],4)

Комбинированное преобразование представления и изменение формы, похоже, занимает около 1 микросекунды на моем ноутбуке, независимо от размера входного массива (предположительно, потому, что нет копирования памяти, кроме нескольких членов в каком-то базовом объекте python).

Вышесказанное справедливо для простых одномерных массивов кватернионов. Чтобы применить его к общим формам, я просто пишу функцию внутри пространства имен кватерниона:

def as_float_array(a):
    "View the quaternion array as an array of floats with one extra dimension of size 4"
    return a.view(np.float).reshape(a.shape+(4,))

Различные формы, похоже, не сильно замедляют работу функции.

Кроме того, легко преобразовать обратно из массива с плавающей запятой в массив кватерниона:

def as_quat_array(a):
    "View a float array as an array of floats with one extra dimension of size 4"
    if(a.shape[-1]==4) :
        return a.view(np.quaternion).reshape(a.shape[:-1])
    return a.view(np.quaternion).reshape(a.shape[:-1]+(a.shape[-1]//4,))
person Mike    schedule 15.10.2014