2010-12-12 27 views
9

Tôi có hàm C để bình thường hóa các hàng của mảng trong không gian nhật ký (điều này ngăn chặn tràn số).Cách tính toán mảng tiếp giáp với cột khi mở rộng numpy bằng C

Nguyên mẫu của C-chức năng của tôi là như sau:

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

Bạn có thể thấy rằng phải mất một con trỏ đến một mảng và sửa đổi nó tại chỗ. C-code của khóa học giả định dữ liệu được lưu dưới dạng một mảng C tiếp giáp, tức là hàng tiếp giáp.

tôi quấn chức năng như sau sử dụng Cython (nhập khẩu và cdef extern from bỏ qua):

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 

Phần lớn thời gian NumPy-mảng là hàng tiếp giáp và chức năng hoạt động tốt. Tuy nhiên, nếu một mảng numpy trước đây đã được transposed dữ liệu không được sao chép xung quanh nhưng chỉ là một cái nhìn mới vào dữ liệu được trả về. Trong trường hợp này, hàm của tôi không thành công vì mảng không còn tiếp giáp với hàng.

tôi có thể làm được việc này bằng cách định nghĩa mảng có thứ tự Fortran tiếp giáp, như vậy sau khi transposing nó sẽ là C tiếp giáp:

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

Rõ ràng đó là rất dễ bị lỗi và người dùng phải mất quan tâm rằng mảng là đúng thứ tự mà là một cái gì đó mà người dùng không cần phải quan tâm trong Python.

Cách tốt nhất để tôi có thể thực hiện công việc này với cả mảng tiếp giáp hàng và cột là gì? Tôi cho rằng một số loại kiểm tra thứ tự mảng trong Cython là con đường để đi. Tất nhiên, tôi thích một giải pháp mà không cần phải sao chép dữ liệu vào một mảng mới, nhưng tôi gần như giả định đó là cần thiết.

Trả lời

7

Nếu bạn muốn hỗ trợ các mảng theo thứ tự C và Fortran mà không cần sao chép, hàm C của bạn cần đủ linh hoạt để hỗ trợ cả hai thứ tự. Điều này có thể đạt được bằng cách đi qua các bước tiến của mảng NumPy đến chức năng C: Thay đổi nguyên mẫu để

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

và cuộc gọi Cython để

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 

Sau đó, thay thế tất cả các xuất hiện của mat[row*ncol + col] trong C của bạn mã số mat[row*rowstride + col*colstride].

+0

Câu trả lời này có từ năm 2010 vẫn là hiện tại hay có cách nào tốt hơn để đạt được điều này ngay bây giờ không? –

+0

@larsmans: Tôi không biết chính xác những gì bạn muốn nói "này".Viết một hàm C có thể xử lý cả hai mảng hai chiều liền kề và C tiếp giáp của Fortran vẫn hoạt động theo cách này, nếu đây là những gì bạn muốn. Nếu nó là ok rằng mảng của bạn được sao chép, có (và đã được trong năm 2010) các giải pháp khác. –

2

Trong trường hợp này bạn thực sự muốn tạo một bản sao của mảng đầu vào (có thể một cái nhìn vào một thực mảng ) với thứ tự hàng tiếp giáp đảm bảo. Bạn có thể đạt được điều này với một cái gì đó như thế này:

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

Ngoài ra, hãy xem xét chính xác array interface của Numpy (có phần C).

0

+1 đến Sven, câu trả lời của bạn giải quyết được hình ảnh xác thực (tốt, đã cho tôi) rằng dstack trả về một mảng 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) 
Các vấn đề liên quan