11

対数空間で配列の行を正規化する C 関数があります (これにより、数値のアンダーフローが防止されます)。

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

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

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

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-arrays は行が連続しており、関数は正常に動作します。ただし、numpy-array が以前に転置されている場合、データはコピーされず、データへの新しいビューだけが返されます。この場合、配列が行に連続していないため、関数は失敗します。

これを回避するには、配列を Fortran 連続順序で定義して、転置後に C 連続になるようにします。

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

明らかに、これは非常にエラーが発生しやすく、ユーザーは配列が正しい順序になっていることに注意する必要があります。これは、ユーザーが Python で気にする必要のないことです。

行と列が連続する配列の両方でこれを機能させる最善の方法は何ですか? Cython でのある種の配列順序チェックが進むべき道だと思います。もちろん、データを新しい配列にコピーする必要のない解決策が望ましいと思いますが、それは必要だと思います。

4

3 に答える 3

8

配列をコピーせずに C と Fortran の順序でサポートしたい場合、C 関数は両方の順序をサポートするのに十分柔軟である必要があります。これは、NumPy 配列のストライドを C 関数に渡すことで実現できます。プロトタイプを次のように変更します。

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

そして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

mat[row*ncol + col]次に、 C コード内のすべての出現箇所を ] に置き換えますmat[row*rowstride + col*colstride

于 2010-12-12T15:53:23.690 に答える
3

この場合、実際には、行の連続した順序が保証された入力配列(実際の配列のビューである可能性があります)のコピーを作成する必要があります。これは、次のような方法で実現できます。

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

また、Numpyの正確な配列インターフェイスを確認することを検討してください(C部分もあります)。

于 2010-12-12T13:41:16.117 に答える
0

その答えは、dstack が 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)
于 2011-05-07T13:25:00.510 に答える