(function of function) - TF1: funcotion composition (f1 o f2 ) (x)

I have two function TF1 (f1 and f2) and I would like to create a new TF1 function (ftot) in order to use it in my fit.

Ftot = f1( f2(x) )
(I can’t modify neither f1 nor f2.)

How can I do this?

Did you try

new TF1("f3","f2(f1(x)");

?

Yes, it doesn’t work …

How did it fail? Did you correct the (unfortunately obvious type I had (missing the 1 at the end of TF1)? Did you replace f1 and f2 with the “name” (1st argument of the constructor) of the two functions? See also https://root.cern.ch/doc/master/classTF1.html for more details.

   TF1 *ftot = new TF1("ftot","f(fsh(x)))");
----------------------------
The error is:

input_line_51:1:70: error: called object type 'TF1 *' is not a function or function pointer
Double_t TFormula____id5336273493103678123(Double_t *x){ return f(fsh(x[0]))) ; }
                                                                  ~~~^
Error in <TFormula::Eval>: Can't find TFormula____id5336273493103678123 function prototype with arguments Double_t*
Error in <TFormula::ProcessFormula>: Could not find f function with 1 argument(s)
Error in <TFormula::ProcessFormula>: Could not find fsh function with 1 argument(s)
Error in <TFormula::ProcessFormula>: Formula "f(fsh(x)))" is invalid !

Try with

  TFormula *ftot = new TFormula("ftot","f(fsh(x)))");

TFormula *ftot = new TFormula(“ftot”,“f(fsh(x)))”);

doesn’t work

Here is a minimal not working example to clear up some confusion. It has always puzzled me as well, why this doesn’t work:

root [0] auto f1 = new TF1("f1", "2*x");
root [1] auto f2 = new TF1("f2", "x*x");
root [2] auto f = new TF1("f", "f1(f2(x))");
input_line_23:1:71: error: called object type 'TF1 *' is not a function or function pointer
Double_t TFormula____id12629671998992482178(Double_t *x){ return f1(f2(x[0])) ; }
                                                                    ~~^
Error in <TFormula::Eval>: Can't find TFormula____id12629671998992482178 function prototype with arguments Double_t*
Error in <TFormula::ProcessFormula>: Could not find f1 function with 1 argument(s)
Error in <TFormula::ProcessFormula>: Could not find f2 function with 1 argument(s)
Error in <TFormula::ProcessFormula>: Formula "f1(f2(x))" is invalid !

It is also not restricted to nesting, a simple addition already fails:

root [7] auto f4 = new TF1("f4", "f1(x) + f2(x)");
input_line_28:1:68: error: called object type 'TF1 *' is not a function or function pointer
Double_t TFormula____id10490377465922475681(Double_t *x){ return f1(x[0])+f2(x[0]) ; }
                                                                 ~~^
input_line_28:1:77: error: called object type 'TF1 *' is not a function or function pointer
Double_t TFormula____id10490377465922475681(Double_t *x){ return f1(x[0])+f2(x[0]) ; }
                                                                          ~~^
Error in <TFormula::Eval>: Can't find TFormula____id10490377465922475681 function prototype with arguments Double_t*
Error in <TFormula::ProcessFormula>: Could not find f1 function with 1 argument(s)
Error in <TFormula::ProcessFormula>: Could not find f2 function with 1 argument(s)
Error in <TFormula::ProcessFormula>: Formula "f1(x)+f2(x)" is invalid !

In other words, why are TF1 objects not callable? I would have expected to be able to do e.g. f1(3.5). What does work is (*f1)(3.5), because we are using pointers.

So, a solution is not to use pointers:

root [15] auto g1 = TF1("g1", "2*x")
(TF1 &) Name: g1 Title: 2*x
root [16] auto g2 = TF1("g1", "x*x")
(TF1 &) Name: g1 Title: x*x
root [17] auto g = TF1("g", "g1(g2(x))")
(TF1 &) Name: g Title: g1(g2(x))

The real solution would be to get TF1 * to be recognized as a function pointer, though.

Hi,

The formula of TF1 understands C++ syntax, so if you have previously defined a pointer to TF1 as f1 you then need to use (*f1)(x).

However the formula understands also other TF1 names, by replacing the formula name with its expression. This works partially for compositions. For example this works:

auto g_1 = new TF1("g1", "x*x");
auto g_2 = new TF1("g2", "2*g1")
auto g_3 = new TF1("g3","g1+g2")

but as you find out “g2(g1)” does not work.
In principle we should be able to implement this case in TFormula

Lorenzo

Double_t funTheoSchifted(Double_t *x, Double_t *par){
Double_t *fshPar;
Double_t *fPar;

fshPar = par;
fPar = &par[2];

Double_t y = fsh->EvalPar(x,fshPar);

Double_t sr = f->EvalPar(&y,fPar);
return sr;
}

[…]

TF1 *ftot = new TF1(“ftot”,funTheoSchifted,100,600,6);

in this way it works!

Yes, it would be a really nice new feature. Could you add it in your todo list for a next ROOT release?

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