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.
È 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
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
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