2010-12-12 4 views
9

Mam funkcję C, aby znormalizować wiersze tablicy w przestrzeni logu (to zapobiega niedomiarze liczbowym).Jak obliczyć tablicę ciągnącymi się w kolumnie przy rozszerzeniu numpy z C

Prototyp moim C-funkcji jest następująca:

void normalize_logspace_matrix(size_t nrow, size_t ncol, double* mat); 

Widać, że ma wskaźnik do tablicy i modyfikuje go w miejscu. Kod C oczywiście zakłada, że ​​dane są zapisywane jako tablica przylegająca do C, to znaczy sąsiadujące ze sobą.

ja owinąć funkcję w następujący sposób używając Cython (import i cdef extern from pominięta):

def normalize_logspace(np.ndarray[np.double_t, ndim=2] mat): 
    cdef Py_ssize_t n, d 
    n = mat.shape[0] 
    d = mat.shape[1] 
    normalize_logspace_matrix(n, d, <double*> mat.data) 
    return mat 

większość czasu NumPy-macierze są przyległe wierszy i funkcja działa poprawnie. Jeśli jednak tablica numpy została wcześniej transponowana, dane nie są kopiowane, ale zwracany jest tylko nowy widok danych. W tym przypadku moja funkcja nie działa, ponieważ tablica nie jest już ciągła w rzędzie.

mogę obejść ten problem, definiując tablicę mieć Fortran-ciągły porządek, tak, że po transpozycji będzie to C-Sąsiadujące:

A = np.array([some_func(d) for d in range(D)], order='F').T 
A = normalize_logspace(A) 

Oczywiście to jest bardzo podatne na błędy, a użytkownik musi podjąć dbamy o to, aby tablica była w poprawnej kolejności, czyli o czym nie powinien dbać użytkownik w Pythonie.

Jaki jest najlepszy sposób, w jaki mogę to zrobić z tablicami, które sąsiadują z wierszami i kolumnami? Zakładam, że w pewnym sensie sprawdzanie kolejności tablic w Cython jest drogą do zrobienia. Oczywiście wolałbym rozwiązanie, które nie wymaga kopiowania danych do nowej tablicy, ale prawie zakładam, że jest to konieczne.

Odpowiedz

7

Jeśli chcesz wesprzeć tablice w porządku C i Fortran bez kopiowania, funkcja C musi być wystarczająco elastyczna, aby obsługiwać oba zamówienia. Można to osiągnąć poprzez przepuszczanie postępy tablicy numpy do funkcji C: Zmiana prototypu do

void normalize_logspace_matrix(size_t nrow, size_t ncol, 
           size_t rowstride, size_t colstride, 
           double* mat); 

i połączenia Cython do

def normalize_logspace(np.ndarray[np.double_t, ndim=2] mat): 
    cdef Py_ssize_t n, d, rowstride, colstride 
    n = mat.shape[0] 
    d = mat.shape[1] 
    rowstride = mat.strides[0] // mat.itemsize 
    colstride = mat.strides[1] // mat.itemsize 
    normalize_logspace_matrix(n, d, rowstride, colstride, <double*> mat.data) 
    return mat 

Następnie zastąpić każde wystąpienie mat[row*ncol + col] w C kod: mat[row*rowstride + col*colstride].

+0

Czy ta odpowiedź z 2010 roku jest wciąż aktualna, czy jest lepszy sposób na osiągnięcie tego teraz? –

+0

@ larsmans: Nie wiem dokładnie, co masz na myśli przez "to".Pisanie funkcji C, która może obsłużyć zarówno dwuwymiarowe tablice sąsiadujące z Fortranem, jak i przylegające do C, nadal działa w ten sposób, jeśli tego właśnie chcesz. Jeśli jest dobrze, że twoje tablice zostaną skopiowane, istnieją (i były w 2010 roku) inne rozwiązania. –

2

W tym przypadku naprawdę chcesz stworzyć kopię tablicy wejściowej (który może być widok na rzeczywistym tablicy) z gwarantowaną row-przyległe kolejności. Można to osiągnąć przy czymś takim:

a = numpy.array(A, copy=True, order='C') 

także rozważyć przyjrzeniu się dokładnie array interface z NumPy (istnieje też część C).

0

+1 do Svena, którego odpowiedź rozwiązuje problem (dobrze, mnie) , który dstack zwraca tablicę F_contiguous?!

# don't use dstack to stack a,a,a -> rgb for a C func 

import sys 
import numpy as np 

h = 2 
w = 4 
dim = 3 
exec("\n".join(sys.argv[1:])) # run this.py h= ... 

a = np.arange(h*w, dtype=np.uint8) .reshape((h,w)) 
rgb = np.empty((h,w,dim), dtype=np.uint8) 
rgb[:,:,0] = rgb[:,:,1] = rgb[:,:,2] = a 
print "rgb:", rgb 
print "rgb.flags:", rgb.flags # C_contiguous 
print "rgb.strides:", rgb.strides # (12, 3, 1) 

dstack = np.dstack((a, a, a)) 
print "dstack:", dstack 
print "dstack.flags:", dstack.flags # F_contiguous 
print "dstack.strides:", dstack.strides # (1, 2, 8) 
Powiązane problemy