Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exposing std::vector<double> with boost.python

I have written some C++ code that generates a std::vector.

I also have a python script that manipulates some data that, for now, I am declaring like this (below).

import numpy
x = numpy.random.randn(1000)
y = numpy.random.randn(1000)

I can run the script fine. From my C++ code:

    using namespace boost::python;
    try{
            Py_Initialize();
            object main = import("__main__");
            object global(main.attr("__dict__"));
            object result = exec_file("scatterPlot.py", global, global);
            Py_Finalize();
    }
    catch(error_already_set){
            PyErr_Print();
    }

    return;

I have no idea how to get my C++ data to python. I've around quite a bit, but there doesn't seem to be anything definitive.

I have in my C++

BOOST_PYTHON_MODULE(vector_indexing_suite_ext){
        boost::python::class_<std::vector<double> >("PyVec")
        .def(boost::python::vector_indexing_suite<std::vector<double> >());
}

This seems to work, but as I understand, it only provides a class "PyVec" for my python script but not the data I need. Am I wrong?

I've also seen some other people use boost::shared_ptr in a python mailing list.

I also found this example but found it confusing.

I can think of a few approaches

  1. Pass something to the boost::python::exec_file method
  2. Using the boost_indexing_suite_ext
  3. Uinsg boost::shared_ptr

Which approach is easiest to get going? No approach seems clear to me.

Here are some more links I've looked at: from the boost website from the python website another mailing list thread

UPDATE:

This works for passing an int to my python code like below

int main(){
        int five_squared=0;
        int a =3;
        try {   
                Py_Initialize();
                object main_module = import("__main__");
                object main_namespace = main_module.attr("__dict__");
                main_namespace["var"]=a;
                object ignored = exec("result = 5 ** var", main_namespace);
                five_squared = extract<int>(main_namespace["result"]);
        } catch( error_already_set ) {
                PyErr_Print();
        }
        std::cout << five_squared << std::endl;
        return 0;
}

But I want to pass a vector, when I try to do that in a similar fashion as above I get this error

TypeError: No to_python (by-value) converter found for C++ type: std::vector >

So, obviously I need to tell python how to deal with std::vector. I think this code could help with that.

BOOST_PYTHON_MODULE(vector_indexing_suite_ext){
        boost::python::class_<std::vector<double> >("PyVec")
        .def(boost::python::vector_indexing_suite<std::vector<double> >());
}

But since std::vector is pretty common, there must be a defined way to do this... right?

like image 720
devin Avatar asked Dec 08 '22 05:12

devin


2 Answers

The following code works for me (Python 2.6, Boost 1.39). This is almost the same as your code, except without the BOOST_PYTHON_MODULE line itself (but with the class_ definition for the vector). BOOST_PYTHON_MODULE only needs to be used when creating extension modules.

#include <iostream>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;
using namespace std;

int main()
{
    vector<double> vec;
    vec.push_back(1.2);
    vec.push_back(3.4);
    try {   
            Py_Initialize();

            boost::python::class_<std::vector<double> >("PyVec")
            .def(boost::python::vector_indexing_suite<std::vector<double> >());

            object main_module = import("__main__");
            object globals = main_module.attr("__dict__");
            globals["var"]=vec;
            object ignored = exec("result = sum(var)", globals, globals);
            double result = extract<double>(globals["result"]);
            std::cout << result << std::endl;
    } catch( error_already_set ) {
            PyErr_Print();
    }
    return 0;
}
like image 159
interjay Avatar answered Dec 27 '22 22:12

interjay


I'm not sure if I understand correctly. After exporting your class "PyVec" which can hold std::vector<double>, you can export any c++ function taking vector as input or return type. So of course you can populate your vector within c++ and access this data in Python with the interfaced type "PyVec".

like image 42
rafak Avatar answered Dec 27 '22 21:12

rafak