Dear Pythoneers,
I have been reading really good answers on this forum so I thought I'll give it a try and see whether someone can help me.
What I want to do:
"I want to embed Python in C++ and use Python's capabilities in order to create a expression evaluator"
In more detail:
"I will have a custom expression entered by the user containing various variables. The values for these variables will be stored in matrices. What I need to do in Python is to use the Py API from C++ to evaluate the result for every set of values for the expression."
What did I do:
After much searching I managed to create a test program for the above problem. Specifically I wrote a simple program that:
->Creates two variables x and y with random values
->Passes those values to two Python variables
->Passes a string containing the expression to Python and evaluates the result
->This result is later converted to a C type and so I have my result
The problem:
The whole thing is slow. After comparing with a Qt implementation of the same problem Qt turns out to be 2times faster than Python.
----Here is the code I used :------
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
using namespace std;
#include <Python.h>
#include <graminit.h>
int main(int argc, char** argv)
{
const int N = atoi(argv[1]);
srand(time(0));
//Create a new namespace dictionary and set the typical built-in values or variables
Py_Initialize();
//Creating new namespace dictionary
PyObject *pDictionary = PyDict_New();
PyDict_SetItemString( pDictionary, "__builtins__", PyEval_GetBuiltins() );
PyRun_String( "import math", file_input, pDictionary, pDictionary );
//------------------------------------
double xValue,yValue;
string expression="result=math.sqrt(x**2)*math.sin(x)*math.cos(y**2)+math.log(y)*math.sin(x+y)";
for (int i=0;i<N;i++) {
xValue=((double) rand()/(double) RAND_MAX);yValue=((double) rand()/(double) RAND_MAX);
PyDict_SetItemString( pDictionary, "x", PyFloat_FromDouble(xValue) );
PyDict_SetItemString( pDictionary, "y", PyFloat_FromDouble(yValue) );
PyRun_String( expression.c_str(), file_input, pDictionary, pDictionary );
PyObject *pResult = PyDict_GetItemString( pDictionary, "result" );
double nResult;
PyArg_Parse( pResult, "d", &nResult );
}
Py_DECREF( pDictionary );
Py_Finalize();
return 0;
}
First of all let me note that this is the first time I used PyAPI and I might well be doing it wrong.
After the disappointment by the performance I thought of another way:
"What if I somehow convert the entire matrix to a numpy array and then evaluate the expression for all values through a vectorized numpy code...."
This is what I tried to do:
PyRun_SimpleString("from numpy import *");
PyRun_SimpleString("N=1000000");
PyRun_SimpleString("result=zeros((N),dtype=float32)");
PyRun_SimpleString("x=random.random((N))");
PyRun_SimpleString("y=random.random((N))");
PyRun_SimpleString("result[0:N]=sqrt(x[0:N]**2)*sin(x[0:N])*cos(y[0:N]**2)+log(y[0:N])*sin(x[0:N]+y[0:N])");
needless to say this code took tens of times less than Python and Qt.
So if there any suggestions on how to convert a C array to numpy and then pass the whole thing to Python (and of course the opposite) I would really appreciate it..
Moreover if anyone can help optimize the above code please do..
Thank you very much for your help