28

C++ コードから一部のデータをオブジェクトとして返したいと考えていnumpy.arrayます。を見てみましたboost::python::numericが、そのドキュメントは非常に簡潔です。vector<double>たとえば、(それほど大きくない)をpythonに返す例を取得できますか?データのコピーをしてもかまいません。

4

5 に答える 5

27

更新:私の元の回答(https://github.com/ndarray/Boost.NumPy)で説明されているライブラリは、Boost 1.63の時点でBoost.Pythonに直接統合されているため、スタンドアロンバージョンは非推奨になりました。以下のテキストは、新しい統合バージョンに対応しています(名前空間のみが変更されています)。

Boost.Pythonには、NumPyC-APIの適度に完全なラッパーがBoost.Pythonインターフェイスに含まれるようになりました。これはかなり低レベルであり、コピーせずにC ++データをNumPyとの間でやり取りする方法という、より難しい問題に対処する方法に主に焦点を当てていますが、コピーされたstd ::vectorreturnを次のように実行する方法は次のとおりです。

#include "boost/python/numpy.hpp"

namespace bp = boost::python;
namespace bn = boost::python::numpy;

std::vector<double> myfunc(...);

bn::ndarray mywrapper(...) {
    std::vector<double> v = myfunc(...);
    Py_intptr_t shape[1] = { v.size() };
    bn::ndarray result = bn::zeros(1, shape, bn::dtype::get_builtin<double>());
    std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data()));
    return result;
}

BOOST_PYTHON_MODULE(example) {
    bn::initialize();
    bp::def("myfunc", mywrapper);
}
于 2012-05-22T15:39:31.130 に答える
20

特別なサード パーティの C++ ライブラリをダウンロードする必要がないソリューション (ただし、numpy が必要です)。

#include <numpy/ndarrayobject.h> // ensure you include this header

boost::python::object stdVecToNumpyArray( std::vector<double> const& vec )
{
      npy_intp size = vec.size();

     /* const_cast is rather horrible but we need a writable pointer
        in C++11, vec.data() will do the trick
        but you will still need to const_cast
      */

      double * data = size ? const_cast<double *>(&vec[0]) 
        : static_cast<double *>(NULL); 

    // create a PyObject * from pointer and data 
      PyObject * pyObj = PyArray_SimpleNewFromData( 1, &size, NPY_DOUBLE, data );
      boost::python::handle<> handle( pyObj );
      boost::python::numeric::array arr( handle );

    /* The problem of returning arr is twofold: firstly the user can modify
      the data which will betray the const-correctness 
      Secondly the lifetime of the data is managed by the C++ API and not the 
      lifetime of the numpy array whatsoever. But we have a simple solution..
     */

       return arr.copy(); // copy the object. numpy owns the copy now.
  }

もちろん、double * と size から汎用的な関数を作成し、この情報を抽出して vector から関数を呼び出すこともできます。NPY_TYPESテンプレートを作成することもできますが、データ型から列挙型への何らかのマッピングが必要になります。

于 2013-01-09T10:16:08.050 に答える
2

numpy API を直接使用することは必ずしも難しいことではありませんが、自分のプロジェクトでは定期的に boost::multiarray を使用しており、配列の形状を C++/Python 境界間で自動的に転送すると便利です。だから、ここに私のレシピがあります。http://code.google.com/p/numpy-boost/を使用するか、このバージョンの numpy_boost.hpp ヘッダーを使用してください。これは複数ファイルの boost::python プロジェクトにより適していますが、一部の C++11 を使用しています。次に、boost::python コードから、次のようなものを使用します。

PyObject* myfunc(/*....*/)
{
   // If your data is already in a boost::multiarray object:
   // numpy_boost< double, 1 > to_python( numpy_from_boost_array(result_cm) );
   // otherwise:
   numpy_boost< double, 1> to_python( boost::extents[n] );
   std::copy( my_vector.begin(), my_vector.end(), to_python.begin() );

   PyObject* result = to_python.py_ptr();
   Py_INCREF( result );

   return result;
}
于 2012-05-22T13:41:24.027 に答える
1

利用可能な回答を見て、「これは簡単だろう」と思いました。私は何時間も費やして、答えの些細な例/適応のように見えるものを試みました.

次に、@ maxの回答を正確に実装し(Eigenをインストールする必要がありました)、うまく機能しましたが、それでも適応に問題がありました。私の問題は、ほとんどが (数による) ばかげた構文ミスでしたが、さらに、ベクターがスタックから削除されたように見えた後、コピーされた std::vector のデータへのポインターを使用していました。

この例では、std::vector へのポインターが返されますが、サイズと data() ポインターを返すか、基になるデータへの安定した方法で numpy 配列にアクセスできる他の実装を使用することもできます (つまり、存在):

class_<test_wrap>("test_wrap")
    .add_property("values", +[](test_wrap& self) -> object {
            return wrap(self.pvalues()->data(),self.pvalues()->size());
        })
    ;

を使用した test_wrap の場合std::vector<double>(通常、pvalues() はベクトルを設定せずにポインターを返すだけです):

class test_wrap {
public:
    std::vector<double> mValues;
    std::vector<double>* pvalues() {
        mValues.clear();
        for(double d_ = 0.0; d_ < 4; d_+=0.3)
        {
            mValues.push_back(d_);
        }
        return &mValues;
    }
};

完全な例は Github にあるため、面倒な書き起こしの手順をスキップして、ビルドやライブラリなどについて心配する必要がなくなります。以下を実行するだけで、機能する例を取得できるはずです (必要な機能がインストールされ、パスが設定されている場合)。すでに):

git clone https://github.com/ransage/boost_numpy_example.git
cd boost_numpy_example
# Install virtualenv, numpy if necessary; update path (see below*)
cd build && cmake .. && make && ./test_np.py

これにより、次の出力が得られます。

# cmake/make output
values has type <type 'numpy.ndarray'>
values has len 14
values is [ 0.   0.3  0.6  0.9  1.2  1.5  1.8  2.1  2.4  2.7  3.   3.3  3.6  3.9]

*私の場合、次のようにnumpyをvirtualenvに入れました-@maxの提案に従って実行できる場合、これは不要ですpython -c "import numpy; print numpy.get_include()"

# virtualenv, pip, path unnecessary if your Python has numpy
virtualenv venv
./venv/bin/pip install -r requirements.txt 
export PATH="$(pwd)/venv/bin:$PATH"

楽しむ!:-)

于 2016-04-10T00:17:10.193 に答える