【问题标题】:call C++ using Eigen Library function in python在python中使用特征库函数调用C++
【发布时间】:2013-03-12 11:59:09
【问题描述】:

我在 Eigen Library 的帮助下用 C++ 做一些计算,函数是这样的:

MatrixXd Cov(MatrixXd Data)
{

  VectorXd meanVector;
  ...
  return Covariance;
}

..在 wrap python 函数中:

static PyObject *Wrap_Cov(PyObject *self,PyObject *args)
{   
      Pyobject *Objectdata;

      if(!PyArg_ParseTuple(args,"O", &ObjectData))
        return NULL;

      Cov(ObjectData);

      return Py_BuildValue("O",&covariance_answer);

  }

显然,Python 不知道我定义的 ''object'',它无法将 ''MatrixXd'' 转换为 ''Object'',我认为它是某种 ''array'',而不是 ' '对象''

如何在不使用 boost 的情况下做到这一点?

【问题讨论】:

  • 您可以使用SWIG 生成C++ 包装器,以便Python 知道您的类的接口。不幸的是,我不知道这个过程的细节,因为我自己没有做过(只使用了一个已经做过的库),这就是为什么这是评论而不是答案。
  • 你能确认你想为 Python 创建一个 C++ 扩展吗?换句话说,您想让您的 C++ Cov() 函数可用于您的 Python 脚本吗?如果是这样,您基本上想使用 PyArg_* 函数将 Python 函数参数中的数据提取到 C++ 变量中(而不是您上面所做的 PyObject),然后使用 PyBuild* 函数将结果传递回 Python。如果您提供显示示例用例的 python 代码,那么我们可以发布答案。
  • 你提到你不能使用 boost。但是 SWIG 是一个我经常使用的工具,因为它生成 C++ 代码,可以为您执行所有 PyArg 和 PyBuild 等调用,以及异常传播等。使用 SWIG 所需要做的就是将它安装在您的计算机上,创建一个包含 MatrixXd 类和 Cov 函数的 .h 的 .i 文件,运行它,构建 SWIG 生成的库,然后启动 Python:然后你可以从 Python 调用你的 Cov,你将没有 C API 可以使用!
  • @Schollii:哇,谢谢!这是一个很好的建议。在我的个人项目中,我会尽量记住这一点。
  • 你想要一个 Cython 或 SWIG 解决方案,还是想要这个用纯 C 编写的包装器?

标签: python c++ matrix eigen python-c-api


【解决方案1】:

如果连接用不同语言编写的数字模块,最好保持数据交换尽可能平坦。

libeigen 实矩阵的最扁平表示是实数类型(浮点或双精度)的 c 数组

这是一个 C++¹ 示例


#include <stdexcept>
#include <iostream>
#include <string>
#include <sstream>
#include <python2.7/Python.h>
#include <eigen3/Eigen/Dense>


using std::size_t;
typedef double real_t;

typedef Eigen::Matrix<real_t, Eigen::Dynamic, Eigen::Dynamic> 
        Matrix;

static PyObject* p_eigen_python_error(NULL);

static PyObject *
randomDxDMatrix(PyObject *self, PyObject *args) {
    PyObject* p(NULL);
    PyObject* item(NULL);    

    try{
        size_t d(0);

        PyArg_ParseTuple(args, "L", &d);
        Matrix M = Matrix::Random(d,d);

        size_t length = d * d;

        p = PyList_New(length);

        if (p == NULL) {
            std::stringstream msg;
            msg << "Could not allocate a Pylist of "
                << d << "x" << d << " = " << d*d 
                << " size for the return Object";
            throw std::runtime_error(msg.str().c_str());
        } else {
            for (size_t i = 0; i < length; ++i) {
                item = PyFloat_FromDouble(M.data()[i]);
                PyList_SET_ITEM(p, i, item);
            }   
        }

    } catch (const std::exception& e) {
        delete p; p = NULL;
        delete item; item = NULL;

        std::string msg = ("randomDxDMatrix failed: ");
        msg += e.what();
        PyErr_SetString(p_eigen_python_error, msg.c_str());
    }

    return p;
}

static PyMethodDef EigenMethods[] = {
    {"randomDxDMatrix",  randomDxDMatrix, METH_VARARGS, 
    "Gets a random DxD matrix column-major as a list of (python) floats"},
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

PyMODINIT_FUNC
initeigen_python(void) {

    PyObject* p;

    p = Py_InitModule("eigen_python", EigenMethods);
    if (p == NULL)
        return;

    p_eigen_python_error = PyErr_NewException(
                                const_cast<char*>("eigen_python.error"), 
                                NULL, NULL
                            );
    Py_INCREF(p_eigen_python_error);
    PyModule_AddObject(p, "error", p_eigen_python_error);
}

这里是 setup_eigen_python.py


from distutils.core import setup, Extension

cpp_args = ['-Wall', '-pedantic']
cxx_args = ['-std=c++11'].extend(cpp_args)

module_eigen_python = Extension('eigen_python',
                          define_macros = [('MAJOR_VERSION', '0'),
                                            ('MINOR_VERSION', '1')],
                          include_dirs = ['/usr/local/include'],
                          sources = ['eigen_python.cpp'],
                          extra_compile_args = cpp_args
#                          sources = ['eigen_python.cxx'],
#                          extra_compile_args = cxx_args
                      )

setup (name = 'eigen_python',
       version = '0.1',
       description = 'This is just a demo',
       author = 'Solkar',
       url = 'http://stackoverflow.com/questions' 
         + '/15573557/call-c-using-eigen-library-function-in-python',
       long_description = 'just a toy',
       ext_modules = [module_eigen_python])

一样使用
python2.7 setup_eigen_python.py install --user

这里有一个小测试驱动程序


import eigen_python as ep
import numpy as np

DIM = 4

M = np.array(ep.randomDxDMatrix(DIM), order="F")
M.shape= DIM,DIM

print(M) 

¹特别是,但到目前为止不限于,因为必须在没有提升的情况下相处,会更喜欢使用 C++ 2011 标准的功能,如 autostd::unique_ptr,但我不知道 QO 是否有足够的支持这。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 2013-05-14
    • 2022-01-05
    • 1970-01-01
    • 2016-10-05
    相关资源
    最近更新 更多