2010-12-12 4 views
9

ログスペース内の配列の行を正規化するC関数があります(数値アンダーフローを防ぎます)。次のようにCでnumpyを拡張するときに列連続配列を考慮する方法

私のC-関数のプロトタイプは次のとおりです。

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

あなたはそれが配列へのポインタを取り、場所に変更していることがわかります。もちろん、Cコードは、データがC連続配列、すなわち行連続して保存されていることを前提としています。

次のようにIはCython(輸入省略cdef extern from)を使用して機能をラップ:

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 

時間numpyの、アレイのほとんどが行連続しており、機能が正常に動作します。しかし、numpy配列が以前に転置された場合、データはコピーされず、データへの新しいビューだけが返されます。この場合、配列はもはや行に隣接していないので、私の関数は失敗します。

私は移調後、それがC-の連続となるように、Fortranの連続順序を持つように配列を定義することによって、これを回避することができます

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

明らかにそれは非常にエラーが発生しやすいですし、ユーザーが取ることがあります配列が正しい順序であることに気をつけます。これはユーザーがPythonで気にする必要のないものです。

行と列の連続した配列でこの作業を行うにはどうすればよいですか?私は、Cythonで何らかの配列順序のチェックが行なわれることを前提としています。もちろん、私はデータを新しい配列にコピーする必要のないソリューションを好むだろうが、私はそれが必要であるとほとんど仮定している。あなたが本当に保証行連続順序で(リアルアレイ上に表示することができます)、入力配列のコピーを作成したいです。この場合

答えて

7

CおよびFortranオーダーでコピーを行わずに配列をサポートする場合、C関数は両方のオーダーをサポートするのに十分な柔軟性が必要です。これは、C関数にnumpyの配列の一歩を渡すことによって達成することができます:あなたのCにmat[row*ncol + col]のすべての発生を置き換え、その後

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 

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

とCythonコールにプロトタイプを変更しますコードmat[row*rowstride + col*colstride]

+0

2010年のこの回答はまだ現在のものですか、これを実現するためのよりよい方法はありますか? –

+0

@larsmans:「これ」の意味を正確には分かりません。Fortran-CおよびC連続二次元配列の両方を扱うことができるC関数を書くことは、これがあなたが望むならば、このように動作します。あなたの配列がコピーされても大丈夫なら、他の解決策があります(2010年もありました)。 –

2

。 (Cの部分があまりにもあります)numpyのの正確なarray interfaceを見てみ考慮し、また

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

:あなたはこのようなもので、これを達成することができます。

0

+1は、答えがうまくいってくれました。 dstack はF_連続配列を返します。

# 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) 
関連する問題