====== 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 : 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) Exemple code (''my_little_poney.cpp'') : #include #include 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); } 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 : template struct nparray_accessor : public xif::multiarr { nparray_accessor (np::ndarray& ndarr) : xif::multiarr( (T*)ndarr.get_data(), [&ndarr] (size_t d) -> size_t { return ndarr.shape(d); } ) {} }; ''nparray_accessor'' 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/]].