Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
procedures:boost_python [2016/11/12 03:14]
xif
procedures:boost_python [2016/11/12 03:21] (current)
xif [NumPy arrays]
Line 1: Line 1:
 +====== Boost.Python on OS X with NumPy ======
  
 +Ur python program too slow at calculating the boiling point of tungsten under a 600bar atmosphere of francium fluoride ? Too baaad...\\
 +Well, let's implement some part of it in C++ using [[http://​boostorg.github.io/​python/​|Boost.Python]] with its NumPy brand new module. That's easy, I promise.\\
 +This tuto uses Python 3.4, installed from [[https://​www.python.org/​downloads/​mac-osx/​]]. Should be easily adapted to other versions.
 +
 +===== Build Boost.Python =====
 +
 +  - Download Boost (dev version) : ''​git clone --recursive https://​github.com/​boostorg/​boost.git modular-boost''​
 +  - ''​./​bootstrap.sh --with-libraries=python --with-python-version=3.4 --with-python-root=/​Library/​Frameworks/​Python.framework/​Versions/​3.4/​bin/​python3.4''​
 +  - ''​sudo ./b2 toolset=clang cxxflags="​-stdlib=libc++ -std=c++0x"​ linkflags="​-stdlib=libc++"​ -j2 install''​
 +  - If it works, you should see ''/​usr/​local/​lib/​libboost_python3.a''​ and ''/​usr/​local/​lib/​libboost_numpy3.a''​.
 +
 +===== Example Python module =====
 +
 +Exemple Makefile :
 +<code make>
 +NAME = gauss_seidel
 +CXX = clang++
 +CXXFLAGS += -Wall -std=c++1y
 +PYTHON_VER = 3.4
 +
 +NUMPY_ROOT = $(shell pip$(PYTHON_VER) show numpy | grep "​Location:"​ | cut -d" " -f2-)
 +CXXFLAGS += -fPIC $(shell python$(PYTHON_VER)-config --cflags) -I$(NUMPY_ROOT)/​numpy/​core/​include
 +LDFLAGS += -fPIC $(shell python$(PYTHON_VER)-config --ldflags)
 +#LDFLAGS += -lboost_python3 -lboost_numpy3 ​ # Fails at module import
 +LDFLAGS += /​usr/​local/​lib/​libboost_python3.a /​usr/​local/​lib/​libboost_numpy3.a
 +
 +all: $(NAME).o
 + $(CXX) -shared $^ $(LDFLAGS) -o $(NAME).so
 +
 +$(NAME).o: $(NAME).cpp
 +
 +%.o: %.cpp
 + $(CXX) -o $@ -c $< $(CXXFLAGS) ​
 +</​code>​
 +
 +Exemple code (''​my_little_poney.cpp''​) :
 +<code cpp>
 +#include <​boost/​python.hpp>​
 +#include <​boost/​python/​numpy.hpp>​
 +
 +namespace py = boost::​python;​
 +namespace np = boost::​python::​numpy;​
 +
 +np::ndarray shift_col (int k, np::ndarray M) {
 + size_t n = M.shape(0), p = M.shape(1);
 + np::​ndarray R = np::​empty(py::​make_tuple(n,​p),​ M.get_dtype());​
 + for (size_t i = 0; i < n; ++i) {
 + for (size_t j = 0; j < p; ++j) {
 + R[i][(j+k)%p] = M[i][j];
 + }
 + }
 + return R;
 +}
 +
 +BOOST_PYTHON_MODULE(my_little_poney) {
 + np::​initialize();​
 + py::​def("​shift_col",​ shift_col);
 +}
 +</​code>​
 +
 +Then build with ''​make''​. It will create a ''​my_little_poney.so''​ dynamic lib which can be loaded as a python module with ''​import my_little_poney''​.
 +
 +==== NumPy arrays ====
 +
 +Here is the issue : all operation made with ''​array[i][j]''​ are executed through the python interpreter and are very inefficient.
 +You can use the ''​xif::​multiarr''​ warper from [[http://​dev.xif.fr:​7979/​xifutils/​|xifutils]] to access directly and easily ''​ndarray''​s : <code cpp>
 +template <​typename T, size_t dim>
 +struct nparray_accessor : public xif::​multiarr<​T,​dim>​ {
 + nparray_accessor (np::​ndarray&​ ndarr) : xif::​multiarr<​T,​dim>​( ​
 + (T*)ndarr.get_data(), ​
 + [&​ndarr] (size_t d) -> size_t { return ndarr.shape(d);​ }
 + ) {}
 +};
 +</​code>​
 +''​nparray_accessor<​T,​dim>''​ takes ''​T''​ as the data type (should match the ''​ndarray'''​s ''​dtype''​) and ''​dim''​ the number of dimensions.
 +
 +Documentation about Boost.Python.NumPy : [[http://​boostorg.github.io/​python/​develop/​doc/​html/​numpy/​]].