2014-11-08 2 views
0

Я пытаюсь выставить eigen3 в python с помощью Boost.Python.Функция Python как аргумент в C++

я не могу найти способ, чтобы разоблачить functionunaryExpr (const CustomUnaryOp &func=CustomUnaryOp())

То, что я хотел бы иметь что-то, что позволит мне что-то вроде этого:

питона

import libMatrix as mat 
a = mat.Matrix(10, 10) 
mat.unary_expr(lambda x : 1) 

У вас есть какие-либо идея ?? Это может выглядеть так:

void unary_expr(Matrix const& self, PyObject* callable_object) 
{ 
    cpp_callable = ??(callable_object) 
    self.unaryEpxr(cpp_callable); 
} 

=== То, что я пробовал: ============================== ============

1) Я пытался использовать простое определение CallBack

typedef double(*UnaryExprType)(double); 
void unary_expr(Matrix const& self, UnaryExprType a); 
    { 
     self.unaryEpxr(a); 
    } 

но бустер не преобразует функцию питона в UnaryExprType.

2) Я пытался использовать implement a structPythonCallBack. Тем не менее, это не сработало, у меня есть ошибка, что подпись python не соответствует сигнатуре C++.

struct PythonCallBackBase 
{ 
public: 
    virtual ~PythonCallBackBase() {} 
    virtual double operator() (double const & x) { return 0; } 
}; 

struct PythonCallBack : PythonCallBackBase, boost::python::wrapper<PythonCallBackBase> 
{ 
public: 
    typedef boost::python::wrapper<PythonCallBackBase> wrap; 

    double default_op(double const & x) 
    { 
     return 0; 
    } 

    double operator() (double const & x) 
    { 
     if (boost::python::override f = wrap::get_override("__call__")) 
      return f(x); 
     return PythonCallBackBase::operator()(x); 
    } 
}; 

void unary_expr(Matrix const& self, PythonCallBack a) 
{ 
    self.unaryEpxr(a); 
} 

Сообщение об ошибке

ArgumentError: Python argument types in 
    Matrix.unary_expr(Matrix, Boost.Python.class) 
did not match C++ signature: 
    unary_expr(Eigen::Matrix<double, -1, -1, 0, -1, -1>, PythonCallBack) 
    unary_expr(Eigen::Matrix<double, -1, -1, 0, -1, -1>, double (*)(double)) 
+0

кажется, что это невозможно. http://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html – Setepenre

ответ

1

Boost.Python позволяет свести к минимуму необходимость взаимодействия с PyObject, и часто можно просто использовать boost::python::object таким же образом, что они с объектом в Python. Например, если func является boost::python::object, который относится к lambda x: 1, то здесь следующее использование Boost.Python с аннотациями комментарии Python:

// >>> func = lambda x: 1 
boost::python::object func = ...; 
// >>> result = func(42) 
boost::python::object result = func(42); 
// >>> assert(1 == result) 
assert(1 == boost::python::extract<int>(result)); 

В этом случае, как код C++, вероятно, ожидая возвращения функтора в Значение типа C++, а не общее boost::python::object, можно использовать тип оболочки для адаптации функтора.

/// @brief Auxiliary type that adapts a Boost.Python object to a 
///  unary functor with an explicit return type. 
template <typename Arg, typename Result> 
class py_unary_functor 
{ 
public: 

    typedef Arg argument_type; 
    typedef Result result_type; 

    py_unary_functor(boost::python::object object) 
    : object_(object) 
    {} 

    result_type operator()(argument_type a1) 
    { 
    return boost::python::extract<result_type>(object_(a1))(); 
    } 

private: 
    boost::python::object object_; 
}; 

Вот полный минимальный пример:

#include <boost/python.hpp> 

/// @brief Mockup matrix class. 
struct matrix 
{ 
    template <typename CustomUnaryOp> 
    void unaryExpr(CustomUnaryOp func) 
    { 
    value = func(value); 
    } 

    double value; 
}; 

/// @brief Auxiliary type that adapts a Boost.Python object to a 
///  unary functor with an explicit return type. 
template <typename Arg, typename Result> 
class py_unary_functor 
{ 
public: 

    typedef Arg argument_type; 
    typedef Result result_type; 

    py_unary_functor(boost::python::object object) 
    : object_(object) 
    {} 

    result_type operator()(argument_type a1) 
    { 
    return boost::python::extract<result_type>(object_(a1))(); 
    } 

private: 
    boost::python::object object_; 
}; 

/// @brief Auxiliary function used to adapt matrix::unaryExpr. 
void matrix_unaryExpr(
    matrix& self, 
    boost::python::object object) 
{ 
    py_unary_functor<double, double> func(object); 
    return self.unaryExpr(func); 
} 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::class_<matrix>("Matrix") 
    // Expose auxiliary function. 
    .def("unaryExpr", &matrix_unaryExpr) 
    .add_property("value", &matrix::value, &matrix::value) 
    ; 
} 

Интерактивное использование:

>>> import example 
>>> matrix = example.Matrix() 
>>> matrix.value = 21 
>>> assert(21 == matrix.value) 
>>> matrix.unaryExpr(lambda x: x*2) 
>>> assert(42 == matrix.value) 
Смежные вопросы