pyROOT TMultiGraph Segmentation Fault

TGraph accept only flot or double arrays: ROOT: TGraph Class Reference

What is this constructor then, TGraph::TGraph(Int_t n, const Int_t *x, const Int_t *y)?

oops yes …you are right … I never use it … sorry for that. So I do not know why with python it does not work. I am not an expert of the python interface,

No worries, I am far from an expert myself and have just recently started using it regularly.

@amadio Any suggestions on why TMultiGraph::GetListOfGraphs is leading to a segmentation fault or why one cannot create a TGraph from a numpy array of integers?

@ksmith No, sorry. I will try to use your script to reproduce the problem and debug what is happening. I will report back here when I find the answer. Cheers,

this should read:

energies = np.linspace(-3, 1, num=5, dtype="int32")
data1 = np.array([10, 20, 304, 50, 60], dtype="int32")

(otherwise the y-axis data is taken to be floats, hence the garbage data 4.94065645841e-323)

Thanks for the idea, what is wrong with the default int64 type? Is the issue here that one array is floats and the other is ints?

$ python
Python 2.7.14 (default, Sep 22 2017, 00:06:07) 
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> energies = np.linspace(-3, 1, num=5)
>>> data1 = np.array([10, 20, 304, 50, 60])
>>> print energies.dtype, data1.dtype
float64 int64

yep.

and in that configuration, the double* overload is selected, whereas if you use int32/int32, the correct int* overload is chosen.

overloading is complicated :slight_smile: (it’s already complicated in C++ so when you add python on top…)

having said that, it seems there is yet another issue when using float32/float32:

>>> make("float32","float32")
ene=[-3. -2. -1.  0.  1.]
dat=[  10.   20.  304.   50.   60.]
0 -1069547520.0 1092616192.0
1 -1073741824.0 1101004800.0
2 -1082130432.0 1134034944.0
3 0.0 1112014848.0
4 1065353216.0 1114636288.0

Interesting issue. Why always 32? Is there something wrong with the python default 64 (at least default for me)?

my guess (not having seen exactly how the method dispatch was done in that particular case) is that in the "float32/float32" case, the dispatch selects the int* overload based on the size of the elements (4).
and I suspect the int* overload is selected (in lieu of the float* on) because it’s the first that satisfies the “element-size” criteria.

the numbers that are printed with float32/float32 eerily look like floating point values whose byte content have been interpreted as integers that have been later on converted to floats.

Indeed. The code looks for the ‘typecode’ variable (is there on the old array interface), and when that fails, it does a size match. Since that code was written, the numpy buffer interface and the memory views of p3 have come along. I’ve said many times that that should be fixed, but there has never been enough interest to warrant the work.

(For my own nefarious purposes, I’m reworking the buffer interface in my cppyy fork … it’s not that hard … )

@ksmith So, I guess this problem has been solved, right? Could you please mark @sbinet’s comment as solution? Thanks!

That’s not a solution.
I just explained why in some setup you get garbled data.
python shouldn’t let you get (silently!) garbled data.

in C++, when you don’t give the correct types to a function/method, the first line of defense (the compiler) will tell you, loudly.
in python calling C++, the method dispatcher should tell you. right now, it doesn’t.

1 Like

also, AFAIK, the original segfault still happens when the snippet of code is executed inside a function.
that’s another bug :slight_smile:

I agree with @sbinet although he has proposed a possible avoidance of one issue, I would not call it solved. (He has clarified the cause nicely though it seems.) In addition, the original issue hasn’t been resolved although @Graipher’s suggestion to not use a method would be another work around.

Dear @ksmith,

Apologies for the delay. I discussed the matter with other members of the team and created a JIRA issue (ROOT-9040) to address this problem.

For now, I recommend just setting the proper types for the vectors you pass as pointers to ROOT in Python, and add input() to get a pause for user input before exiting. I believe the cause of the crash could be an issue at tear down rather than being related to the problem that vector types are mismatched.

Cheers,
—Guilherme

Thanks for the investigation. I selected to watch the bug. I will definitely try to use “proper” types although this seems to go against the python ideology. As for adding input() this is not always a reasonable solution as some scripts were designed to be run automatically with no user interaction. At the moment we are avoiding the TMultiGraph::GetListOfGraphs method as that seems to be involved.

I ran into the issue of “proper” types again and had to reteach myself what was learned above. I wanted to clarify the situation for myself and others who might run into this. At the moment the dtype of the two numpy arrays passed to TGraph must match. In addition, only certain dtype values produce reasonable output:

Type Constructor Chosen Output
int32 int* Good
int64 double* Bad
float32 int* Bad
float64 double* Good

* The constructor chosen may not be correct, but is an educated guess based on above discussions.

Therefore the default type for integer arrays on 64-bit machine (int64) will not produce reasonable output.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.