2013-03-22 14 views
13

robię pewne obliczenia w C++ przy pomocy Eigen Biblioteki funkcja jest tak:wezwanie C++ przy użyciu funkcji Eigen biblioteki w python

MatrixXd Cov(MatrixXd Data) 
{ 

    VectorXd meanVector; 
    ... 
    return Covariance; 
} 

..w funkcji okład Pythona:

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); 

    } 

Oczywiście, Python nie zna "zdefiniowanego obiektu", nie może przetłumaczyć '' MatrixXd '' na '' Object '', myślę, że jest to rodzaj "tablicy", a nie " "obiekt"

Jak mogę to zrobić bez użycia boost?

+1

Możesz użyć [SWIG] (http://www.swig.org/) do wygenerowania opakowania C++, aby Python znał interfejs twojej klasy. Niestety nie znam szczegółów tego procesu, ponieważ sam tego nie zrobiłem (wykorzystałem tylko bibliotekę, w której zostało to zrobione), dlatego nie jest to odpowiedź, a komentarz. – wakjah

+1

Czy możesz potwierdzić, że chcesz utworzyć rozszerzenie C++ dla Pythona? Innymi słowy chcesz, aby twoja funkcja C++ Cov() była dostępna dla twojego skryptu Python? Jeśli tak, to w zasadzie chcesz użyć funkcji PyArg_ * do wyodrębnienia danych z argumentów funkcji Pythona do zmiennej C++ (nie do PyObject, jak to zrobiono powyżej), a następnie użyj funkcji PyBuild *, aby przekazać wynik z powrotem do Pythona. Jeśli podasz kod Pythona, który pokazuje przykład użycia, możemy wysłać odpowiedź. – Schollii

+8

Wspomniałeś, że nie możesz użyć wzmocnienia. Ale SWIG to narzędzie, którego użyłem dużo, ponieważ generuje kod C++, który wykonuje wszystkie wywołania PyArg i PyBuild itd., Z wyjątkową propagacją itp. Wszystko, co musisz zrobić, aby użyć SWIG, zainstaluj go na swoim komputerze, stwórz Plik .i, który zawiera .h twojej klasy MatrixXd i funkcję Cov, uruchom ją, zbuduj bibliotekę wygenerowaną przez SWIG i uruchom Pythona: możesz wtedy wywołać swój Cov z Pythona, w ogóle nie będziesz miał C API! – Schollii

Odpowiedz

6

W przypadku łączenia modułów numerycznych napisanych w różnych językach, dobrą praktyką jest utrzymanie możliwie płaskiej wymiany danych.

najbardziej płaską przedstawieniem libeigen rzeczywistym macierzy jest macierz prądu przemiennego typu rzeczywistego (float lub podwójne)

oto C++ ¹ próbki


#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); 
} 

Poniżej 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]) 

być używany jak

python2.7 setup_eigen_python.py install --user 

i tutaj jest trochę kierowca testowy


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) 

¹Especially, ale zdecydowanie nie ograniczone do, ponieważ konieczności uzyskania bez wspomagania wolałby korzystać z funkcji standardowego języka C++ 2011 e auto i std::unique_ptr, ale nie wiedziałem, czy QO ma wystarczające poparcie dla tego.

Powiązane problemy