how to pass an array from c++ to python function and retrieve python returned array to c++ - c++

I'm writting a c++ program to call a python function and retrieve the return array.but i always get an error as below:
only length-1 arrays can be converted to Python scalars
and my c++ code:
int main(int argc, char *argv[])
{
int i;
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
if (argc < 3)
{
printf("Usage: exe_name python_source function_name\n");
return 1;
}
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString(argv[1]);
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, argv[2]);
if (PyCallable_Check(pFunc))
{
// Prepare the argument list for the call
if( argc > 3 )
{
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; i++)
{
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue)
{
PyErr_Print();
return 1;
}
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
if (pArgs != NULL)
{
Py_DECREF(pArgs);
}
} else
{
pValue = PyObject_CallObject(pFunc, NULL);
}
if (pValue != NULL)
{
cout <<pValue;
printf("Return of call : %ld\n", PyInt_AsLong(pValue));
PyErr_Print();
Py_DECREF(pValue);
}
else
{
PyErr_Print();
}
} else
{
PyErr_Print();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
system("PAUSE");
return 0;
}
Python function:
import numpy as np
_ZERO_THRESHOLD = 1e-9 # Everything below this is zero
def data():
print "process starting..."
N = 5
obs = np.matrix([np.random.normal(size=5) for _ in xrange(N)])
V = pca_svd(obs)
print "V:"
print V[0:5]
pca = IPCA(obs.shape[1], 3)
for i in xrange(obs.shape[0]):
x = obs[i,:].transpose()
print " "
print "new input:"
print x
pca.update(x)
U = pca.components
A = pca.variances
B = U.T*x
print B
return B
I know there is something wrong with this statement
PyInt_AsLong(pValue)
Can anyone tell me how to fix that in order to retrieve the matrix from python to c++
Thank you so much.

You are using PyInt_AsLong(pValue) to convert the Python object pValue to a C long scalar. If pValue is a Numpy array, this means that you are trying to convert the array to a number, which is only possible for length-1 arrays:
only length-1 arrays can be converted to Python scalars
Instead of using PyInt_AsLong, use the PyArray_* functions provided by Numpy's C API to access the data; in particular, see section Array API.

You want to use NumPy C API, probably to get a data pointer with
#include <numpy/arrayobject.h>
...
p = (uint8_t*)PyArray_DATA(pValue);
after making really sure that you actually got an array of the right dimensions. See my hello.hpp for some example code.

Related

Pass an array or argptr as parameters to a old varargs (...) function? C++

I have a old varargs(...) function that uses va_list, va_start, va_arg, va_end
cell executeForwards(int id, ...)
{
if (!g_forwards.isIdValid(id))
return -1;
cell params[FORWARD_MAX_PARAMS];
int paramsNum = g_forwards.getParamsNum(id);
va_list argptr;
va_start(argptr, id);
ForwardParam param_type;
for (int i = 0; i < paramsNum && i < FORWARD_MAX_PARAMS; ++i)
{
param_type = g_forwards.getParamType(id, i);
if (param_type == FP_FLOAT)
{
REAL tmp = (REAL)va_arg(argptr, double); // floats get converted to doubles
params[i] = amx_ftoc(tmp);
}
else if(param_type == FP_FLOAT_BYREF)
{
REAL *tmp = reinterpret_cast<REAL *>(va_arg(argptr, double*));
params[i] = reinterpret_cast<cell>(tmp);
}
else if(param_type == FP_CELL_BYREF)
{
cell *tmp = reinterpret_cast<cell *>(va_arg(argptr, cell*));
params[i] = reinterpret_cast<cell>(tmp);
}
else
params[i] = (cell)va_arg(argptr, cell);
}
va_end(argptr);
return g_forwards.executeForwards(id, params);
}
For some reason I need to push the parameters dynamically to this function, for example by using an array or something, Is that possible in C++?
example code:
va_list argptr;
va_push(argptr, 100);
va_push(argptr, 2.22f);
va_push(argptr, 300);
executeForwards(0, argptr);
Notice: I cannot modify the content of this function (executeForwards)

Iterate over results in neo4j_client for C++

I am looking for examples on usage for neo4j_client in C++. In the test suite I see the neo4j_result_t, but no example of iterating or calling fields by name. Is that possible?
Results are returned as a neo4j_result_stream_t, which represents a stream of result rows. The number of the columns in the result is available via neo4j_nfields, and their names via neo4j_fieldname, both of which take the neo4j_result_stream_t pointer as a parameter.
To iterate over the result rows, use neo4j_fetch_next which returns a neo4j_result_t. And to extract values for each column from the row (the fields), pass the pointer to neo4j_result_field (along with the index of the column).
An example would be something like this:
neo4j_result_stream_t *results =
neo4j_run(session, "MATCH (n) RETURN n.name, n.age", neo4j_null);
if (results == NULL)
{
neo4j_perror(stderr, errno, "Failed to run statement");
return EXIT_FAILURE;
}
int ncolumns = neo4j_nfields(results);
if (ncolumns < 0)
{
neo4j_perror(stderr, errno, "Failed to retrieve results");
return EXIT_FAILURE;
}
neo4j_result_t *result;
while ((result = neo4j_fetch_next(results)) != NULL)
{
unsigned int i;
for (i = 0; i < ncolumns; ++i)
{
if (i > 0)
{
printf(", ");
}
neo4j_value_t value = neo4j_result_field(result, i);
neo4j_fprint(value, stdout);
}
printf("\n");
}

Passing information between SWIG in and freearg typemaps

I have a typemap targetting Python which accepts both an already wrapped pointer object or additionally allows passing a Python sequence. In the case of a wrapped pointer, I do not want to delete the memory as SWIG owns it. However, when processing a sequence I'm allocating a temporary object that needs to be deleted. So I added a flag to my 'in' typemap to mark whether I allocated the pointer target or not. How can I access this flag in the corresponding 'freearg' typemap?
The typemaps look like this:
%typemap(in) name* (void* argp = 0, int res = 0, bool needsDelete = false) {
res = SWIG_ConvertPtr($input, &argp, $descriptor, $disown | 0);
if (SWIG_IsOK(res)) {
$1 = ($ltype)(argp); // already a wrapped pointer, accept
} else {
if (!PySequence_Check($input)) {
SWIG_exception(SWIG_ArgError(res), "Expecting a sequence.");
} else if (PyObject_Length($input) != size) {
SWIG_exception(SWIG_ArgError(res), "Expecting a sequence of length " #size);
} else {
needsDelete = true;
$1 = new name;
for (int i = 0; i < size; ++i) {
PyObject* o = PySequence_GetItem($input, i);
(*$1)[i] = swig::as<type>(o);
Py_DECREF(o);
}
}
}
}
%typemap(freearg) name* {
if ($1 /* && needsDelete */) delete $1;
}
This leads to code being generated that looks like:
{
res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_MyName_t, 0 | 0);
if (SWIG_IsOK(res2)) {
arg2 = (MyName *)(argp2); // already a wrapper pointer, accept
} else {
if (!PySequence_Check(obj1)) {
SWIG_exception(SWIG_ArgError(res2), "Expecting a sequence.");
} else if (PyObject_Length(obj1) != 3) {
SWIG_exception(SWIG_ArgError(res2), "Expecting a sequence of length ""3");
} else {
needsDelete2 = true;
arg2 = new MyName;
for (int i = 0; i < 3; ++i) {
PyObject* o = PySequence_GetItem(obj1, i);
(*arg2)[i] = swig::as<double>(o);
Py_DECREF(o);
}
}
}
}
if (arg1) (arg1)->someMember = *arg2;
resultobj = SWIG_Py_Void();
{
if (arg2 /* && needsDelete */) delete arg2;
}
According to 11.15 Passing data between typemaps from the SWIG manual:
You just need to use the variable as needsDelete$argnum in the freearg typemap.

Extending python3, how does the garbage collection work

I'm making my own PriorityQueue in C as a python module. I read the basics of python ownership and reference system, so I thought I'd do the following:
In push(): Accept an priority(int) and an object to be saved. Increment the reference count on the object to be saved, since we will be keeping that.
In pop(): Delete the object from my priorityqueue, but don't decrement the reference counter, since that might destroy the object. Instead I transfer my reference ownership to the python function calling my function.
This seemed to work at first hand. But when actually using it in an application I get the following error:
Fatal Python error: GC object already tracked
What does this mean? The stacktrace is not useful at all, it's all inside python files I don't recognize(sre_parse and apport_python_hook).
Just for clarity, these are my C push and pop functions:
(self->heap[index]->key is the priority of the element at that index
self->heap[index]->value is the object)
PyObject* pop(CDSHeap *self) {
//If there aare no elements
if (self->heap[0].value == 0 || self->end == 0) {
Py_RETURN_NONE;
}
//If there is only one element
if (self->end == 1) {
PyObject* result = self->heap[0].value;
self->heap[0].key = 0;
self->end = 0;
return result;
}
//Two or more elements:
//First save the result:
PyObject* result = self->heap[0].value;
//Get the last element, and place it at the top
while (self->heap[self->end].value == 0) self->end--;
self->heap[0].value = self->heap[self->end].value;
self->heap[0].key = self->heap[self->end].key;
self->heap[self->end].value = 0;
//Reheapify the heap
int ptr = 0;
while (self->end >= ptr) {
if (self->heap[ptr*2+1].value != 0 && self->heap[ptr*2+1].key < self->heap[ptr].key
&& (self->heap[ptr*2+2].value == 0 || self->heap[ptr*2+1].key <= self->heap[ptr*2+2].key)) {
swapElement(self->heap, ptr, ptr*2+1);
ptr = ptr*2+1;
}else
if (self->heap[ptr*2+2].value != 0 && self->heap[ptr*2+2].value < self->heap[ptr].value) {
swapElement(self->heap, ptr, ptr*2+2);
ptr = ptr*2+2;
} else {
break;
}
}
return result;
}
PyObject* push(CDSHeap *self, PyObject* args) {
int k;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO",&k, &obj)){
return NULL;
}
Py_INCREF(obj);
//Add the element to the end of the heap
self->heap[self->end].key = k;
self->heap[self->end].value = obj;
//Increment the size and reheapify
int ptr = self->end++;
while (ptr > 0) {
int parent = (ptr-1)/2;
if (self->heap[ptr].key < self->heap[parent].key) {
swapElement(self->heap, ptr, parent);
ptr = parent;
} else {
Py_RETURN_NONE;
}
}
Py_RETURN_NONE;
}

How can I query the data of a complex return type using PyObject_CallObject?

I have a small python programm that computes a 2d positon
def getPosition(lerpParameter):
A = getClothoidConstant()
...
The python script can be found in my project folder here.
The function getPosition is included in the file clothoid.py. The function returns a value of type Vector2. How can I access the data of the returned Vector2d in my C++ program?
The C++ programm looks like this:
/// Get function
PyObject *pFunc = PyObject_GetAttrString(pModule, pid.functionName);
// pFunc is a new reference
if (pFunc && PyCallable_Check(pFunc))
{
PyObject *pArgs = PyTuple_New(pid.getArgumentCount());
PyObject *pValue = nullptr;
// setup function parameters
for (int i = 0; i < pid.getArgumentCount(); ++i)
{
if (pid.arguments[i].type == eType::Int)
{
pValue = PyLong_FromLong(atoi(pid.arguments[i].name.c_str()));
}
else
{
pValue = PyFloat_FromDouble(atof(pid.arguments[i].name.c_str()));
}
if (!pValue)
{
Py_DECREF(pArgs);
Py_DECREF(pModule);
std::cout << "Cannot convert argument" << std::endl;
throw std::runtime_error("Cannot convert argument");
}
// pValue reference stolen here:
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != nullptr)
{
switch (pid.returnType)
{
...
case eType::Double:
//std::cout << "Result of call: " << PyFloat_AsDouble(pValue) << std::endl;
doubleValue_ = PyFloat_AsDouble(pValue);
break;
case eType::Vector2d:
{
// How can I acccess the data here?
}
break;
default:
break;
}
Py_DECREF(pValue);
}
If the return type is a double or int it is easy to get the corresponding value. But I have no idea how to access the data of the Vector2.
If you want to get the 'x' attribute, and you know it's a float:
PyObject *temp = PyObject_GetAttrString(pValue, "x");
if (temp == NULL) {
// error handling
}
double x = PyFloat_AsDouble(temp);
// clean up reference when done with temp
Py_DECREF(temp);