Understand enumeration of TF1 parameters

Hi, I had some code using TF1 which stopped working properly after moving root-5 -> root-6. I’ve found in doc that new TFormula behind TF1 has changed. Fine for me, however I found weird, inconsistent behavior of parameter enumeration. Maybe you can shine some light on it why it works like this.
Outputs below comes from TF1::print("V"); call.

I have two functions, on is a weighted sum of two gaussians. In the very fits version it was just plain sum, so it had 6 parameters: N1, mean1, sigma1, N2, mean2, sigma2. Later on it was turned into weighted sum with common mean, so params become: N, mean, sigma1, dummy, r, sigma2. r replaced the old N2, dummy is in place for the old mean2 to keep backward compatibility. When printing, I get:

Formula based function:     f_h_SignalInvMass_sig 
 f_h_SignalInvMass_sig : s2gs Ndim= 1, Npar= 5, Number= 0 
 Formula expression: 
        ([p0]*([p4]/([p2]*TMath::Sqrt(2.0*TMath::Pi()))*TMath::Exp(-0.5*pow(((x-[p1])/[p2]),2))+(1.0-[p4])/([p5]*TMath::Sqrt(2.0*TMath::Pi()))*TMath::Exp(-0.5*pow(((x-[p1])/[p5]),2)))) 
List of  Variables: 
Var   0                    x =    0.000000 
List of  Parameters: 
Par   0                   p0 =    0.000000 
Par   1                   p1 =    0.000000 
Par   2                   p2 =    0.000000 
Par   3                   p4 =    0.000000 
Par   4                   p5 =    0.000000 
Expression passed to Cling:
        Double_t TFormula____id2933220127093106735(Double_t *x,Double_t *p){ return (p[0]*(p[3]/(p[2]*TMath::Sqrt(2.0*TMath::Pi()))*TMath::Exp(-0.5*TMath::Power(((x[0]-p[1])/p[2]),2))+(1.0-p[3])/(p[4]*TMath::Sqrt(2.0*TMath::Pi()))*TMath::Exp(-0.5*TMath::Power(((x[0]-p[1])/p[4]),2)))) ; }

p3 is missing as it is not in the formula, that is fine, the param numbers goes 0…4. I the root version it was 1-1 enumeration, so my function had 6 parameters (tested with ROOT::v5::TFormula):

 Par  0                    p0 = 0
 Par  1                    p1 = 0
 Par  2                    p2 = 0
 Par  3                    p3 = 0
 Par  4                    p4 = 0
 Par  5                    p5 = 0

This brought me some troubles but can handle it.

But now I have another function, which is background and is supposed to be concatenated to signal function above. Thus it params start with index 6. But when I print it:

Formula based function:     f_h_SignalInvMass_bkg 
 f_h_SignalInvMass_bkg : pol5(6)+aexpo Ndim= 1, Npar= 15, Number= 0 
 Formula expression: 
        ([p6]+[p7]*x+[p8]*pow(x,2)+[p9]*pow(x,3)+[p10]*pow(x,4)+[p11]*pow(x,5))+([p12]*exp([p13]*(x-[p14]))) 
List of  Variables: 
Var   0                    x =    0.000000 
List of  Parameters: 
Par   0                   p0 =    0.000000 
Par   1                   p1 =    0.000000 
Par   2                   p2 =    0.000000 
Par   3                   p3 =    0.000000 
Par   4                   p4 =    0.000000 
Par   5                   p5 =    0.000000 
Par   6                   p6 =    0.000000 
Par   7                   p7 =    0.000000 
Par   8                   p8 =    0.000000 
Par   9                   p9 =    0.000000 
Par  10                  p10 =    0.000000 
Par  11                  p11 =    0.000000 
Par  12                  p12 =    0.000000 
Par  13                  p13 =    0.000000 
Par  14                  p14 =    0.000000 
Expression passed to Cling:
        Double_t TFormula____id1908495908384388024(Double_t *x,Double_t *p){ return (p[6]+p[7]*x[0]+p[8]*TMath::Power(x[0],2)+p[9]*TMath::Power(x[0],3)+p[10]*TMath::Power(x[0],4)+p[11]*TMath::Power(x[0],5))+(p[12]*TMath::Exp(p[13]*(x[0]-p[14]))) ; }

I see the inconsistency that p0p5 were not given in the formula but any way they appear on the list and are enumerated. Thus GetNPar() returns me 14 parameters instead of 9.
The TFormula was initiated with “pol5(6)+aexpo” where aexpo is another formula with “[0] * exp([1]*(x-[2]))”.

Can you explain this? I would expect the second function is correct, but the first one is broken. If I defined parameters as [5] in the formula, I want to access it with GetParameter(5), not GetParameter(4).


ROOT Version: 6.20.04
Platform: Linux
Compiler: GCC-9.3.0


You MUST NOT use non-existent parameters.
Try e.g.: "pol5(0)+aexpo(6)" or: "pol5(3)+aexpo(0)"

But it does not answer question about the inconsistency. Why the first formula omit the missing parameters, and the second do not? And if this is a problem, maybe TFormula should display a warning about incorrect format?

You get “inconsistencies” which you yourself create. Do NOT blame ROOT.
Try in ROOT 5 and ROOT 6:
TF1 *f = new TF1("f", "pol0(99)", 0., 1.); f->Print("V");

They are the same, but what about:

TF1 *f = new TF1("f", "pol0(99)", 0., 1.); f->Print("V");
TF1 *f2 = new TF2("f2", "f", 0, 1); f2->Print("V");

They aren’t the same?

Isn’t it obvious that ROOT 6 (ROOT 5 will not do it), when creating “f2”, tries to deal with the “inconsistency” that you created when defining “f”? It “renumerates” parameters which appear in the formula, leaving their names unchanged (so, in “f2”, you get 1 parameter with the name “p99”).

For me it isn’t. If you deal with inconsistency then you deal with it already in f or you do not do it at all. otherwise it break the logic, as in this example. And this dealing happens without any message, warning or so. User is not aware of this action. Then it could react - e.g. fix formula.

The underlying reason is that ROOT 5 formula always uses the original expression "pol0(99)" (you explicitly ask for at least 100 parameters) while ROOT 6 formula decomposes / simplifies it into another expression "[p99]" (there is just 1 parameter named “p99”).

So, you need to fix your source code e.g. like I show in my first post here.

I can fix the code, but the fact that f and f2 and working different ways I consider a bug.

Hi,
probably @moneta can comment on whether this can be considered a bug or not. You could also open a bug report at https://sft.its.cern.ch/jira/projects/ROOT , although it won’t be high-priority I am afraid.

Cheers,
Enrico

So on top of this I can report another problem I noticed.

In my old ROOT-5 version, my function of sum of two gauses was defined with name s2gaus which worked nice. In any formula I could use e.g. s2gaus+pol5(6). However in ROOT-6 I realized that the build in functions were evaluated first, thus the gaus part of s2gaus was evaluated leaving orphaned s2 making problems. See this example:

root [0] new TF1("s2gaus", "[0] * ([4] / ( [2] * TMath::Sqrt(2.0 * TMath::Pi()) ) * TMath::Exp(-0.5*((x-[1])/[2])**2) + (1.0 - [4]) / ( [5] * TMath::Sqrt(2.0 * TMath::Pi()) ) * TMath::Exp(-0.5*((x-[1])/[5])**2)) + [3]*0", -1, 1);
root [1] TF1 * f = new TF1("f2", "s2gaus + pol5(6)", -1, 1);
input_line_13:2:78: error: use of undeclared identifier 's2'
Double_t TFormula____id9918300281635781362(Double_t *x,Double_t *p){ return {s2[0]}*TMath::Exp(-0.5*((x[0]-p[1])/p[2])*((x[0]-p[1])/p[2]))+(p[6]+p[7]*x[0]+p[8]*TMath::Power(x[0],2)+p[9]*TMath::Power(x[0],3)+p[10]*TMath::Power(x[...
                                                                             ^
input_line_14:2:78: error: use of undeclared identifier 's2'
Double_t TFormula____id9918300281635781362(Double_t *x,Double_t *p){ return {s2[0]}*TMath::Exp(-0.5*((x[0]-p[1])/p[2])*((x[0]-p[1])/p[2]))+(p[6]+p[7]*x[0]+p[8]*TMath::Power(x[0],2)+p[9]*TMath::Power(x[0],3)+p[10]*TMath::Power(x[...
                                                                             ^
Error in <prepareMethod>: Can't compile function TFormula____id9918300281635781362 prototype with arguments Double_t*,Double_t*
Error in <TFormula::InputFormulaIntoCling>: Error compiling formula expression in Cling
Error in <TFormula::ProcessFormula>: "s2[0]" has not been matched in the formula expression
Error in <TFormula::ProcessFormula>: Formula "s2[0]*exp(-0.5*((x-[p1])/[p2])*((x-[p1])/[p2]))+([p6]+[p7]*x+[p8]*pow(x,2)+[p9]*pow(x,3)+[p10]*pow(x,4)+[p11]*pow(x,5))" is invalid !

the same time in ROOT-5

root [0] new TF1("s2gaus", "[0] * ([4] / ( [2] * TMath::Sqrt(2.0 * TMath::Pi()) ) * TMath::Exp(-0.5*((x-[1])/[2])**2) + (1.0 - [4]) / ( [5] * TMath::Sqrt(2.0 * TMath::Pi()) ) * TMath::Exp(-0.5*((x-[1])/[5])**2)) + [3]*0", -1, 1);        
root [1] TF1 * f = new TF1("f2", "s2gaus + pol5(6)", -1, 1);                                                                                                                                                                                 
root [2] f->Print()
f2 : s2gaus+pol5(6) Ndim= 1, Npar= 12, Noper= 49                                                                                                                                                                          
fExpr[0] = [0]  action = 140 action param = 0
fExpr[1] = [4]  action = 140 action param = 4
fExpr[2] = [2]  action = 140 action param = 2
fExpr[3] = 2.0  action = 141 action param = 0
fExpr[4] = Double_t TMath::Pi()  action = 145 action param = 0
fExpr[5] = *  action = 3 action param = 0
fExpr[6] = Double_t TMath::Sqrt(Double_t x)  action = 145 action param = 1001
fExpr[7] = *  action = 3 action param = 0
fExpr[8] = /  action = 4 action param = 0
fExpr[9] = 0.5  action = 141 action param = 1
fExpr[10] = x  action = 144 action param = 0
fExpr[11] = [1]  action = 140 action param = 1
fExpr[12] = -  action = 2 action param = 0
fExpr[13] = [2]  action = 140 action param = 2
fExpr[14] = /  action = 4 action param = 0
fExpr[15] = sq  action = 21 action param = 0
fExpr[16] = *  action = 3 action param = 0
fExpr[17] = -  action = 44 action param = 0
fExpr[18] = Double_t TMath::Exp(Double_t x)  action = 145 action param = 2001
fExpr[19] = *  action = 3 action param = 0
fExpr[20] = 1.0  action = 141 action param = 2
fExpr[21] = [4]  action = 140 action param = 4
fExpr[22] = -  action = 2 action param = 0
fExpr[23] = [5]  action = 140 action param = 5
fExpr[24] = 2.0  action = 141 action param = 0
fExpr[25] = Double_t TMath::Pi()  action = 145 action param = 3000
fExpr[26] = *  action = 3 action param = 0
fExpr[27] = Double_t TMath::Sqrt(Double_t x)  action = 145 action param = 4001
fExpr[28] = *  action = 3 action param = 0
fExpr[29] = /  action = 4 action param = 0
fExpr[30] = 0.5  action = 141 action param = 1
fExpr[31] = x  action = 144 action param = 0
fExpr[32] = [1]  action = 140 action param = 1
fExpr[33] = -  action = 2 action param = 0
fExpr[34] = [5]  action = 140 action param = 5
fExpr[35] = /  action = 4 action param = 0
fExpr[36] = sq  action = 21 action param = 0
fExpr[37] = *  action = 3 action param = 0
fExpr[38] = -  action = 44 action param = 0
fExpr[39] = Double_t TMath::Exp(Double_t x)  action = 145 action param = 5001
fExpr[40] = *  action = 3 action param = 0
fExpr[41] = +  action = 1 action param = 0
fExpr[42] = *  action = 3 action param = 0
fExpr[43] = [3]  action = 140 action param = 3
fExpr[44] = 0  action = 141 action param = 3
fExpr[45] = *  action = 3 action param = 0
fExpr[46] = +  action = 1 action param = 0
fExpr[47] = pol5(6)  action = 130 action param = 507
fExpr[48] = +  action = 1 action param = 0
Optimized expression
fExpr[0] = [0]           action = 146 action param = 0
fExpr[1] = [4]           action = 146 action param = 4
fExpr[2] = [2]           action = 146 action param = 2
fExpr[3] = 2.0,Double_t TMath::Pi(),*            action = 148 action param = 0
fExpr[4] = Double_t TMath::Sqrt(Double_t x)              action = 161 action param = 0
fExpr[5] = *             action = 3 action param = 0
fExpr[6] = /             action = 4 action param = 0
fExpr[7] = 0.5           action = 146 action param = 1
fExpr[8] = x,[1],-               action = 148 action param = 0
fExpr[9] = [2]           action = 146 action param = 2
fExpr[10] = /            action = 4 action param = 0
fExpr[11] = sq           action = 161 action param = 0
fExpr[12] = *            action = 3 action param = 0
fExpr[13] = -            action = 44 action param = 0
fExpr[14] = Double_t TMath::Exp(Double_t x)              action = 161 action param = 0
fExpr[15] = *            action = 3 action param = 0
fExpr[16] = 1.0,[4],-            action = 148 action param = 0
fExpr[17] = [5]                  action = 146 action param = 5
fExpr[18] = 2.0,Double_t TMath::Pi(),*           action = 148 action param = 0
fExpr[19] = Double_t TMath::Sqrt(Double_t x)             action = 161 action param = 0
fExpr[20] = *            action = 3 action param = 0
fExpr[21] = /            action = 4 action param = 0
fExpr[22] = 0.5                  action = 146 action param = 1
fExpr[23] = x,[1],-              action = 148 action param = 0
fExpr[24] = [5]                  action = 146 action param = 5
fExpr[25] = /            action = 4 action param = 0
fExpr[26] = sq           action = 161 action param = 0
fExpr[27] = *            action = 3 action param = 0
fExpr[28] = -            action = 44 action param = 0
fExpr[29] = Double_t TMath::Exp(Double_t x)              action = 161 action param = 0
fExpr[30] = *            action = 3 action param = 0
fExpr[31] = +            action = 1 action param = 0
fExpr[32] = *            action = 3 action param = 0
fExpr[33] = [3],0,*              action = 148 action param = 0
fExpr[34] = +            action = 1 action param = 0
fExpr[35] = pol5(6)              action = 130 action param = 507
fExpr[36] = +            action = 1 action param = 0
Par  0                    p0 = 0
Par  1                    p1 = 0
Par  2                    p2 = 0
Par  3                    p3 = 0
Par  4                    p4 = 0
Par  5                    p5 = 0
Par  6                    p6 = 0
Par  7                    p7 = 0
Par  8                    p8 = 0
Par  9                    p9 = 0
Par 10                   p10 = 0
Par 11                   p11 = 0
root [3]

@moneta That’s a clear bug … ROOT 6 formula tries to be clever and expands “s2gaus” into “s2 * gaus” (this will probably happen in all cases when an existing function name is used as the trailing part of a new function name, at least for standard ROOT functions).

Hi,

Yes this last thing reported is a bug and I opened a JIRA ticket:

https://sft.its.cern.ch/jira/browse/ROOT-10815

For the other problems, there is no much we can do. I remind you can define clearly the functions passing also the parameter names, for example:

TF1 f("f","gaus([a1],[m],[s1])+gaus([a2],[m],[s2])");
f.Print("v"); // to see also parameter order

Lorenzo

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