2012-02-03 45 views
3

C APIを使用して大量の配列から多くの値を(順番に)読み込もうとしています。私は別々にboost :: python :: extract(...)を各値に使用するよりも効率的な方法を望みます。最初の値へのポインタを取得し、そのポインタをインクリメントするようなものです。numpyから多くの値を読み取るC API

私はnumpyのAPIドキュメントを読んできましたが、実際にこれを達成する方法は賢明ではありません。誰かが私に例を教えてもらえますか?

答えて

4

Boost :: Python APIでは、これを直接行うことはできません。あなたはNumpy C APIを使ってそれを行うことができます。 PyObject*へのアクセスは、ptr()メソッドboost::python::objectを使用して実行できます。データへのアクセスはPyArray_DATA(PyObject*)を使用して取得できます。

ここでは、2d Numpy配列に数値を乗算する例を示します。私はいくつかの問題はMac OS(すなわち、numpyのヘッダがどこにあるか)上でこれをコンパイルする方法を見つけ出すを持っていたので、私はここにこれを追加します:Pythonで

import numpy; print numpy.get_include() 

を実行すると、正しいパスを含める提供します。たとえば、cmake Findモジュールでこれを使用できます(thisなどを参照してください。PYTHON_EXECUTABLE変数を自分で設定する必要があります)。

更新: Iは、入力配列が連続していない場合を処理するためのコードを変更した - あなたがスライスを使用するとき、これはarr[::2, ::2]のように、例えば起こります。これを処理する最も簡単な方法はPyArray_FROM_OTFです。配列がすでに連続した形式でない限り、配列のコピーを作成することに注意してください。この手法の利点は、入力が任意の種類のネストされたシーケンス(例えば、リストのリスト)である場合を扱うことができることである。

アレイが非常に大きく、コピーを避けることが望ましい場合は、PyArray_STRIDESを使用して、データへのアクセスに役立つストライド情報を取得できます。 http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html

から配列aの要素(i[0], i[1], ..., i[n])のバイトオフセットは、次のとおりです。

offset = sum(np.array(i) * a.strides)

(これはオフセットバイトですので、あなたにそれを追加する必要があることに注意してください結果がPyArray_BYTESの場合の場合は最終的なデータ型にキャストしますが、配列が不適切に整列されている場合や、誤ったバイトがある場合は役に立ちませんR)

ここでサンプルコードは次のとおり

#include <boost/python.hpp> 

#include <exception> 

#include <numpy/arrayobject.h> 

using namespace boost::python; 

struct WrongSizeError : public std::exception { 
    const char* what() const throw() { return "Unsupported array size."; } 
}; 

struct WrongTypeError : public std::exception { 
    const char* what() const throw() { return "Unsupported array type."; } 
}; 

// Boost::Python needs the translators 
void translate_sz(const WrongSizeError& e) 
{ 
    PyErr_SetString(PyExc_RuntimeError, e.what()); 
} 

void translate_ty(const WrongTypeError& e) 
{ 
    PyErr_SetString(PyExc_RuntimeError, e.what()); 
} 

// multiply matrix of double (m) by f 
object multiply(numeric::array m, double f) 
{ 
    PyObject* m_obj = PyArray_FROM_OTF(m.ptr(), NPY_DOUBLE, NPY_IN_ARRAY); 
    if (!m_obj) 
    throw WrongTypeError(); 

    // to avoid memory leaks, let a Boost::Python object manage the array 
    object temp(handle<>(m_obj)); 

    // check that m is a matrix of doubles 
    int k = PyArray_NDIM(m_obj); 
    if (k != 2) 
    throw WrongSizeError(); 

    // get direct access to the array data 
    const double* data = static_cast<const double*>(PyArray_DATA(m_obj)); 

    // make the output array, and get access to its data 
    PyObject* res = PyArray_SimpleNew(2, PyArray_DIMS(m_obj), NPY_DOUBLE); 
    double* res_data = static_cast<double*>(PyArray_DATA(res)); 

    const unsigned size = PyArray_SIZE(m_obj); // number of elements in array 
    for (unsigned i = 0; i < size; ++i) 
    res_data[i] = f*data[i]; 

    return object(handle<>(res)); // go back to using Boost::Python constructs 
} 

BOOST_PYTHON_MODULE(test) 
{ 
    // register exception translators 
    register_exception_translator<WrongSizeError>(&translate_sz); 
    register_exception_translator<WrongTypeError>(&translate_ty); 

    // tell Boost::Python under what name the array is known 
    numeric::array::set_module_and_type("numpy", "ndarray"); 
    def("multiply", multiply); 

    // initialize the Numpy C API 
    import_array(); 
} 
+0

は、入力アレイは '乗算(FOOのように、スライス操作の結果である場合、この作業を行うには、[:: 3]、X)'?あなたはちょうどデータへのポインタを取得し、その後、単一のステップを踏むので、ストライドが1つではないときにこれが失敗すると思いますか? –

+0

はい、私はそれを述べておくべきです - 私が書いたコードは、連続した配列に対してのみ働いていました。ソリューションを提供するために私の答えを更新しました。 – Legendre17

関連する問題