Есть указатель на данные. Нужен массив Numpy в порядке Фортрана. Хотите использовать Cython - PullRequest
4 голосов
/ 03 декабря 2011

Это очень распространенный вариант использования для меня.У меня есть функция C, которая возвращает мне указатель на double:

 //myheader.h
 double *mycfuntion(...)

Я знаю размеры возвращаемых данных.Я также знаю, что данные Fortran упорядочены.Я хочу написать Cython "shim", чтобы получить данные в Python в виде массива Numpy:

#myshim.pyx
import numpy
cimport numpy as cnumpy

cnumpy.import_array()

cdef extern from "myheader.h" :
     double *mycfunction(...)

def mypyfunc(...) :
     cdef double *data = mycfunction(...)
          **MAGIC**
     return outarray

МАГИЧЕСКИЕ идеи

(A) cdef cnumpy.ndarray[ cnumpy.double_t, mode='fortran', ...] outarray
Это был бы самый удобный способ ведения дел.Здесь есть кое-что критическое, что я упускаю из-за того, как превратить указатель data в буфер, который я могу передать конструктору cnumpy.ndarray.Я пробовал:

cdef cnumpy.ndarray[ cnumpy.double_t, mode='fortran', ...] outarray
cdef bytes databuffer = <char *>data
outarray = numpy.ndarray(buffer=databuffer, dtype=numpy.double, ...)

Этот подход постоянно терпит неудачу с TypeError: buffer is too small for requested array

(B) Numpy C-API
, который я использовал cnumpy.PyArray_SimpleNewFromData(...) много от Cython.Работает просто отлично.Проблема в том, что он не поддерживает аргумент flags , поэтому я не могу сказать, чтобы он создавал массив Fortran.Альтернатива, которую я использовал в реализациях на чистом C: PyArray_NewFromDescr(...).Он принимает флаги .Этот подход многословен и болезнен и означает получение некоторых символов из numpy через блок extern, которые еще не импортированы.Должен быть лучший способ.


Я гуглял свое лицо по этой проблеме, но ничего очевидного не появилось.Может быть, я идиот.Или просто сон.Ура!

1 Ответ

2 голосов
/ 05 декабря 2011

Это немного хакерски, но вы можете изменить порядок своих измерений, а затем вернуть транспонирование.Это должно исправить ваш шаг, но не копировать данные.

cimport numpy as cnp
cnp.import_array()

cdef double a1[10]
for i in range(10):
    a1[i] = i

# C order
a2 = cnp.PyArray_SimpleNewFromData(2, [2, 5], cnp.NPY_FLOAT64, a1)
# fortran order
a3 = cnp.PyArray_SimpleNewFromData(2, [5, 2], cnp.NPY_FLOAT64, a1).T
# a2 and a3 point to the same data
a2[0,0] = 10.
print a2
print a3
...