C array to python array

Hello,

Maybe it is an easy question but I didn,t find a way to access a C pointer through a python numerical array.

For example given a function :
double * giveArray(int n);
returning a pointer to an array of size n.
In PyROOT. is it possible to “cast” its result into an array (an numpy.array actually) in order to easily perform operation on it ?

Hi,

the result returned from PyROOT is an ordinary python buffer object (the only modification is the stride, by default buffer objects are of type char*); AFAIK, numpy can handle those. The only problem that I can see is that the size of the double* array per se is unknown, so “casting” by the user is required to set the size.

I don’t have a numpy installation handy, but I have anecdotal evidence that the reverse works (passing a numpy array through a double* by means of the buffer interface that PyROOT, too, accepts). Can you just give it a try?

Cheers,
Wim

Hello wim,

Thanks for your answer.

Indeed, passing a numpy.array to a C function such as TH1D::FillN(int, double* double*) works. I’m actually using this in my scripts.

But I could not reverse the procedure. The numpy.array constructor doesn’t take size as argument : doing something like

c_pointer_object = giveArray(10)
a = numpy.array(c_pointer_object)

crashes python (the contrary would have surprised me). I was wandering if there are known workaround …

P.A.

Hi,

without a size argument, the buffer size is by default set to the moral equivalent of INT_MAX, because there can be no further information derived from a blank “double *” return argument. Size of INT_MAX allows the user to access into the array as far as needed, regardless the actual size, which is now the user’s responsibility. And if numpy doesn’t allow the developer to add this information, a crash seems likely behavior.

Are fixed size arrays an option? When returned as part of struct, their size is known from the class definition and hence properly handled.

Worst comes to worst, you can first copy the double* buffer into a python array from module array of type ‘d’, and there fix the size in the built-up by using a tuned iterator. Something like (haven’t tested it):[code]import array
def mybuf__iter_( self ):
n = GetSizeFromSomeWhere()
i = 0
while i < n:
yield self[i]
i += 1

mybuf.class.iter = mybuf__iter_
a = array.array( ‘d’, mybuf )
del mybuf.class.iter[/code]
For the future, I’ll add a member function to the buffer object to fix its size. If it’s really urgent, ACLiC can probably be used to compile that in from a script, but it’ll be fugly. :slight_smile:

Cheers,
Wim

Hi,

I revive this thread in case some people are interested with this topic.
I just discovered an easy way of doing c pointer -> array conversion in python.
Assume we have :

Then on python side :

p=f(10) a = numpy.ndarray( (10,),dtype= numpy.float32, buffer=p)

‘a’ will use the pointer created on the C++ side (i.e. modification on the c++ side will affect a in python).

I find this very useful since numpy array are so easy to work with.

What I still need now is to be able to do the same with std::vector … Any idea ?

P.A.

Hello,

I found a solution to the above problem.
I’m afraid experts will find it awful, but it seems to work.

One needs to compile a helper function (maybe it already exists somewhere ?)

#include <vector>

template<class T>
T* vectorTopointer(std::vector<T> &v){
  return &v[0];
}

// explicit instantiation
template float* vectorTopointer(std::vector<float> &v);
template int* vectorTopointer(std::vector<int> &v);

Then compile/load this snippet (via ROOT.gSytem.CompileMacro() for ex.)
It works as expected :

[code]>>> v = ROOT.vector(float)(5)

import numpy
a = numpy.ndarray( (v.size( ), ) , dtype= numpy.float32, buffer=ROOT.vectorTopointer(v) )
v[0]=1.234
a[0]
1.234[/code]

Warning : I guess if the stl vector is resized (via resize(), or a push_back() ) the numpy array might get completely wrong !