C APIを使用して大量の配列から多くの値を(順番に)読み込もうとしています。私は別々にboost :: python :: extract(...)を各値に使用するよりも効率的な方法を望みます。最初の値へのポインタを取得し、そのポインタをインクリメントするようなものです。numpyから多くの値を読み取るC API
私はnumpyのAPIドキュメントを読んできましたが、実際にこれを達成する方法は賢明ではありません。誰かが私に例を教えてもらえますか?
C APIを使用して大量の配列から多くの値を(順番に)読み込もうとしています。私は別々にboost :: python :: extract(...)を各値に使用するよりも効率的な方法を望みます。最初の値へのポインタを取得し、そのポインタをインクリメントするようなものです。numpyから多くの値を読み取るC API
私はnumpyのAPIドキュメントを読んできましたが、実際にこれを達成する方法は賢明ではありません。誰かが私に例を教えてもらえますか?
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();
}
は、入力アレイは '乗算(FOOのように、スライス操作の結果である場合、この作業を行うには、[:: 3]、X)'?あなたはちょうどデータへのポインタを取得し、その後、単一のステップを踏むので、ストライドが1つではないときにこれが失敗すると思いますか? –
はい、私はそれを述べておくべきです - 私が書いたコードは、連続した配列に対してのみ働いていました。ソリューションを提供するために私の答えを更新しました。 – Legendre17