Hello. This is my first forum post, so please forgive any transgressions.
I noticed some PyROOT behaviour recently and I don’t know if it’s a bug or if this is the way it’s supposed to be, so I’ll just describe what I’m doing and hope you can help me with this…
I’ve been working on a sort of Python interface to TMinuit for performing simple one-dimensional function fits to data points. To take full advantage of Python’s flexibility I have defined a fit function in Python which always takes the independent variable (x) as its first argument and the parameters as keyword arguments:
def expo(x, amplitude=.8, xcoefficient=.5): return amplitude * exp(xcoefficient * x)
I’ve implemented a function (calculate_chi2) to calculate the chi^2 for a given parameter set and defined a FCN for TMinuit using the usual syntax (function_to_minimize), which I passed to TMinuit using SetFCN.
# calculate the chi^2 for the current parameters def calculate_chi2(parameters): result = 0.0 for i in range(number_of_points): x = xdata[i] # This doesn't work, presumably because the unpacking operator `*' # doesn't behave well when used with buffers... (?): fit_function_value_at_x = expo(x, *parameters) y = ydata[i] result += ((y-fit_function_value_at_x)*(y-fit_function_value_at_x)) return result
# this is passed to TMinuit.SetFCN def function_to_minimize(number_of_parameters, derivatives, f, parameters, internal_flag): f = calculate_chi2(parameters)
# refer TMinuit to the aforementioned FCN gMinuit = TMinuit(number_of_parameters) gMinuit.SetFCN(function_to_minimize)
The result was that everything failed with a MemoryError. Debugging on the Python side says the culprit is the line "fit_function_value_at_x = expo(x, parameters)" in calculate_chi2. Also, I expected the parameter vector to be passed as a Python list, or in any case as an iterable, so the unpacking operator () will work on it.
I don’t really understand the mechanics of C++ communicating with Python, but is there any way the pythonization of TMinuit could be improved upon/expanded, so the unpacking operator could be used in the above code without causing a MemoryError?
I’ve found a temporary workaround by putting the parameters in a Python iterable (e.g. a list) and unpacking that when passing to the fit function. What I thought this would do is actually bring C++ data to the Python side, so that Python (and the * operator) can work with it, but I’m afraid this translation doesn’t scale well with large inputs (making fits with a lot of plot points slower than necessary).
# temporary workaround -> put the parameters in a list, which # can be unpacked by `*'... (slow?) parameter_list =  for j in range(number_of_parameters): parameter_list.append(parameters[j]) fit_function_value_at_x = expo(x, *parameter_list)