Возможно ли создать numpy.ndarray, который содержит комплексные целые числа?

Я хотел бы создать объекты numpy.ndarray, которые содержат в них комплексные целочисленные значения. NumPy имеет встроенную встроенную поддержку, но только для форматов с плавающей запятой (float и double); Например, я могу создать ndarray с dtype='cfloat', но аналогичного dtype='cint16' не существует. Я хотел бы иметь возможность создавать массивы, содержащие сложные значения, представленные с использованием 8- или 16-разрядных целых чисел.

Я нашел этот почтовый лист с 2007 года, где кто-то спросил о такой поддержке. Единственным обходным решением, которое они рекомендовали, было определение нового dtype, содержащего пары целых чисел. Кажется, что каждый элемент массива представляет собой набор из двух значений, но не ясно, какую еще работу нужно выполнить, чтобы сделать результирующий тип данных без проблем работать с арифметическими функциями.

Я также рассмотрел другой подход, основанный на регистрации пользовательских типов с NumPy. У меня нет проблем с переходом на C API, чтобы настроить его, если он будет работать хорошо. Тем не менее, документация для структуры дескриптора типа, похоже, предполагает, что поле типа kind поддерживает только целые числа с подписью/без знака, с плавающей запятой и комплексные числовые типы с плавающей запятой. Непонятно, что я мог бы найти где угодно, пытаясь определить сложный целочисленный тип.

Любые рекомендации относительно подхода, который может работать?

Изменить: Еще одна вещь; любая выбранная мной схема должна поддаваться обертке существующих сложных целочисленных буферов без выполнения копии. То есть, я хотел бы иметь возможность использовать PyArray_SimpleNewFromData(), чтобы выставить буфер на Python, не создавая первую копию буфера. Буфер будет уже в чередующемся реальном/мнимом формате и будет либо массивом int8_t, либо int16_t.

Ответ 1

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

dtype = np.dtype([('re', np.int16), ('im', np.int16)])

Это не идеально, но он адекватно описывает данные. Я использую его для загрузки в память без удвоения размера данных. Он также имеет то преимущество, что он может загружать и хранить прозрачно с помощью HDF5.

DATATYPE  H5T_COMPOUND {
    H5T_STD_I16LE "re";
    H5T_STD_I16LE "im";
}

Использование простое, просто другое.

x = np.zeros((3,3),dtype)
x[0,0]['re'] = 1
x[0,0]['im'] = 2
x
>> array([[(1, 2), (0, 0), (0, 0)],
>>        [(0, 0), (0, 0), (0, 0)],
>>        [(0, 0), (0, 0), (0, 0)]], 
>>  dtype=[('re', '<i2'), ('im', '<i2')])

Чтобы сделать математику с ней, я конвертирую в собственный комплексный тип float. Очевидный подход не работает, но это также не так сложно.

y = x.astype(np.complex64) # doesn't work, only gets the real part
y = x['re'] + 1.j*x['im']  # works, but slow and big
y = x.view(np.int16).astype(np.float32).view(np.complex64)
y
>> array([[ 1.+2.j,  0.+0.j,  0.+0.j],
>>        [ 0.+0.j,  0.+0.j,  0.+0.j],
>>        [ 0.+0.j,  0.+0.j,  0.+0.j]], dtype=complex64)

Этот последний подход преобразования, основанный на fooobar.com/questions/484608/...

Ответ 2

Python и, следовательно, Numpy поддерживает комплексные числа, если вам нужны комплексные целые числа, просто используйте np.round или игнорируйте десятичную часть.

например.

import numpy as np
#Create 100 complex numbers in a 1D array
a=100*np.random.sample(100)+(100*np.random.sample(100)*1j)
#Reshape to a 2D array
np.round(a)
a.reshape(10,10)

#Get the real and imag parts of a couple x/y points as integers
print int(a[1:2].real)
print int(a[3:4].imag)