2013-03-22 11 views
13

sto facendo alcuni calcoli in C++ con l'aiuto di Eigen Biblioteca, la funzione è simile a questo:chiamata C++ utilizzando la funzione Eigen Biblioteca in python

MatrixXd Cov(MatrixXd Data) 
{ 

    VectorXd meanVector; 
    ... 
    return Covariance; 
} 

..nel la funzione di involucro di pitone:

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

    } 

Ovviamente, Python non conosce l''' oggetto '' che ho definito, non può tradurre '' MatrixXd '' in '' Oggetto '', penso che siano alcuni tipi di '' array '', non ' 'oggetto' '

Come posso fare questo senza utilizzare Boost?

+1

È possibile utilizzare [SWIG] (http://www.swig.org/) per generare un wrapper C++ in modo che Python conosca l'interfaccia della classe. Sfortunatamente non conosco le specifiche di questo processo, poiché non l'ho fatto da solo (ho usato solo una libreria dove era stato fatto), motivo per cui questo è un commento non una risposta. – wakjah

+1

Puoi confermare che vuoi creare un'estensione C++ per Python? In altre parole, vuoi rendere la tua funzione C++ Cov() disponibile per il tuo script Python? In questo caso, in pratica, si desidera utilizzare la funzione PyArg_ * per estrarre i dati dagli argomenti della funzione Python in una variabile C++ (non un PyObject come in precedenza), quindi utilizzare la funzione PyBuild * per passare il risultato a Python. Se fornisci il codice Python che mostra un caso d'uso di esempio, possiamo postare una risposta. – Schollii

+8

Hai detto che non puoi usare boost. Ma SWIG è uno strumento che ho usato molto mentre genera codice C++ che fa tutte le chiamate PyArg e PyBuild ecc per te, con propagazione delle eccezioni ecc. Tutto quello che devi fare per usare SWIG è installarlo sul tuo computer, creare un .i file che include la .h della tua classe MatrixXd e la funzione Cov, eseguilo, costruisci la libreria generata da SWIG e avvia Python: puoi quindi chiamare Cov da Python senza alcuna API C da usare! – Schollii

risposta

6

Se si interfacciano moduli numerici scritti in lingue diverse, è buona norma mantenere i dati scambiati il ​​più piatti possibile.

La rappresentazione piana di un vero e proprio Matrix libeigen è array ac di tipo reale (float o doppio)

Ecco un C++ ¹ campionare


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

Ecco 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]) 

da utilizzare come

python2.7 setup_eigen_python.py install --user 

ed ecco un po 'di test driver


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, ma di gran lunga non solo, perché avere per ottenere lungo senza boost, avrebbe preferito utilizzare le funzionalità dello standard C++ 2011 lik e auto e std::unique_ptr ma non sapevo se il QO avesse un supporto sufficiente per questo.

Problemi correlati