ROOT::Math::Functor in PyROOT (Multivariate minimization)


I want to minimize the following function:

def myFcn(x,p1,p2):
    #for the first missing particle
    n3 = T3vector()

    p3 = TLorentzVector() 
    p3.SetPtEtaPhiE( n3.Pt() , n3.Eta() , x[4], x[0] )

    #for the scnd missing particle
    n4 = T3vector()

    p4 = TLorentzVector() 
    p4.SetPtEtaPhiE( n4.Pt() , n4.Eta() , x[5], x[1] )

    return (p1+p2+p3+p4).M2()

Where p1,p2,p3 and p4 are Lorenz vectors. I am trying to minimize it using minuit, there are other four constraints but I am not considering them yet for simplicity. To do this I been following this example-> ROOT: tutorials/fit/NumericalMinimization.C Source File . There is a line in the example which is:

ROOT::Math::Functor f(&RosenBrock,2);

I tried to write it in pyroot as:

f = root.Math.Functor(root.AddressOf(myFcn),6)


f = root.Math.Functor (myFcn,6)

but neither worked. So i wonder, how can i write it in PyROOT? And there is any other minimization examples in python or c++? i just found this one until now.

Best Regards,

I think @etejedor can help you with this, once back from vacation

1 Like


This works for me with master:

>>> import ROOT
>>> def f(x, p1, p2): return .1
>>> a = ROOT.Math.Functor(f, 6)
>>> a
<cppyy.gbl.ROOT.Math.Functor object at 0x68b0e90>

As for the minimization examples I’ll ask @moneta to say something.

1 Like


The code above is correct, but it will not work when used for Minimization. The function to be passed to the minimiser needs to take only one parameter that is a list of values corresponding to the parameters to be found by the minimiser.
I attached as example the NumericalMinimization script translated in Python



1 Like

Hi @moneta ,

If the minimizer takes only one parameter, how can I minimize a multivariate function with root or other Roo tools? I need to minimize the function that I wrote above, but subject to other 4 constraints.

And I don’t know why, but I can’t open the link you sent. When I open it, it actually opens as an empty .jpeg →


The function to pass to the minimizer must be a function requiring only one argument, but this can be a list or an array of several variables. These variables are the minimization parameters. In your case it is not clear to me what are these variables between x,p1,p3,p3,p4.
Adding the constraints is another story, we do not support an interface for including them directly in the minimiser, you need to implement yourself as was already answered to you in
Minimization subject to constrains with Tminuit, is it possible? [PyROOT] - #4 by couet.

Here is the link to the example of doing the minimization in Python:



1 Like


So about the variables between x,p1,p3,p3,p4.

The function that I am trying to minimize is the Mandelstam S variable for a system of 4 particles (two visible and two neutrinos) . Actually, I am trying to minimize it with respect to the neutrino variables (p,theta,phi),and I already have all he information about the visible particles. This leaves 6 variables at the total. And writing S explicitly in terms of p, theta and phi for all the variables is kinda of messy, so i tried to work directly with the four vectors.

“In your case it is not clear to me what are these variables between x,p1,p3,p3,p4.”. So these variables you said above are the 3d arrays n3 and n4? If it is, I created them so I could just use them .Pt and .Eta components of them directly into a .SetPtEtaPhiE().

There is some problem trying to minimize the function in this way? Or is it ok?

Yes you can define your functions to minimise with respect to the (p,theta,phi) of the two neutrinos. Do something like:

def myFcn(x):
   pt1 = x[0]
   eta1 = x[1]
   phi1 = x[2]
   pt2 = x[3]
   eta2 = x[4]
   phi2 = x[5]
   # 4 vector for neutrino 1 and 2
   n1 = ROOT.Math.PtEtaPhiMVector(pt1,eta1,phi1,0)
   n2 = ROOT.Math.PtEtaPhiMVector(pt2,eta2,phi2,0)
1 Like

Okay, thank you!

Just one more question, I know you said that "The function to be passed to the minimiser needs to take only one parameter " but there is a way to read the p1 and p2 lorenz vectors from the main function? Or I would have to try to read them from the .root file directly inside the function that will be minimized?

Hi @etejedor ,

I tried to follow what you did and I got this:

>>> import ROOT
>>> def f(x, p1, p2): return .1
>>> a = ROOT.Math.Functor(f, 6)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Template method resolution failed:
  none of the 2 overloaded methods succeeded. Full details:
  Functor::Functor(const ROOT::Math::Functor& rhs) =>
    TypeError: takes at most 1 arguments (2 given)
  Functor::Functor() =>
    TypeError: takes at most 0 arguments (2 given)
  Failed to instantiate "Functor(function,int)"

I don’t know what you meant by “This works for me with master:”, sorry but I don’t know what ‘master’ is. I just used the terminal to try the code line I wrote above.


Yes, let me clarify, master is the current development branch of ROOT. With what ROOT version did you get that error?

I just tried 6.24 and I also see it, but it seems fixed in 6.26 which will be released soon.

Until then, if you want to work with master, one easy way is to do from lxplus:

[etejedor@lxplus766 ~]$ source /cvmfs/ 
[etejedor@lxplus766 ~]$ python3
Python 3.9.5 (default, Jun 16 2021, 18:19:24) 
[GCC 9.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ROOT
>>> def f(x, p1, p2): return .1
>>> a = ROOT.Math.Functor(f, 6)
>>> a
<cppyy.gbl.ROOT.Math.Functor object at 0x83a0490>

Alternatively if you use SWAN, you can also pick the “development bleeding edge” stack when starting your session, and that will have the same effect.


The other inputs to the function to be minimised, need to be either taken from the ROOT file inside the functions or defined as global variables that will be visible inside the function.
In C++ you can define a functor class and use the other inputs as member data of the class.
I am not sure if you can use a class to define your function in PyROOT



I’m also having facing this issue, and unfortunately I’m restricted to the root version of our analysis framework. Are there any work arounds to get this to work in 6.24?


Would it be an option to define f as a function in C++, and then pass it as an argument of functor from Python? That might work.