Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TF1.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Rene Brun 18/08/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "Riostream.h"
13 #include "TROOT.h"
14 #include "TMath.h"
15 #include "TF1.h"
16 #include "TH1.h"
17 #include "TGraph.h"
18 #include "TVirtualPad.h"
19 #include "TStyle.h"
20 #include "TRandom.h"
21 #include "TInterpreter.h"
22 #include "TPluginManager.h"
23 #include "TBrowser.h"
24 #include "TColor.h"
25 #include "TClass.h"
26 #include "TMethodCall.h"
27 #include "TF1Helper.h"
28 #include "TF1NormSum.h"
29 #include "TF1Convolution.h"
30 #include "TVirtualMutex.h"
31 #include "Math/WrappedFunction.h"
32 #include "Math/WrappedTF1.h"
33 #include "Math/BrentRootFinder.h"
34 #include "Math/BrentMinimizer1D.h"
35 #include "Math/BrentMethods.h"
36 #include "Math/Integrator.h"
38 #include "Math/IntegratorOptions.h"
39 #include "Math/GaussIntegrator.h"
43 #include "Math/Functor.h"
44 #include "Math/Minimizer.h"
45 #include "Math/MinimizerOptions.h"
46 #include "Math/Factory.h"
47 #include "Math/ChebyshevPol.h"
48 #include "Fit/FitResult.h"
49 // for I/O backward compatibility
50 #include "v5/TF1Data.h"
51 
52 #include "AnalyticalIntegrals.h"
53 
54 std::atomic<Bool_t> TF1::fgAbsValue(kFALSE);
55 Bool_t TF1::fgRejectPoint = kFALSE;
56 std::atomic<Bool_t> TF1::fgAddToGlobList(kTRUE);
57 static Double_t gErrorTF1 = 0;
58 
59 using TF1Updater_t = void (*)(Int_t nobjects, TObject **from, TObject **to);
60 bool R__SetClonesArrayTF1Updater(TF1Updater_t func);
61 
62 
63 namespace {
64 struct TF1v5Convert : public TF1 {
65 public:
66  void Convert(ROOT::v5::TF1Data &from)
67  {
68  // convert old TF1 to new one
69  fNpar = from.GetNpar();
70  fNdim = from.GetNdim();
71  if (from.fType == 0) {
72  // formula functions
73  // if ndim is not 1 set xmin max to zero to avoid error in ctor
74  double xmin = from.fXmin;
75  double xmax = from.fXmax;
76  if (fNdim > 1) {
77  xmin = 0;
78  xmax = 0;
79  }
80  TF1 fnew(from.GetName(), from.GetExpFormula(), xmin, xmax);
81  if (fNdim > 1) {
82  fnew.SetRange(from.fXmin, from.fXmax);
83  }
84  fnew.Copy(*this);
85  // need to set parameter values
86  if (from.GetParameters())
87  fFormula->SetParameters(from.GetParameters());
88  } else {
89  // case of a function pointers
90  fParams = new TF1Parameters(fNpar);
91  fName = from.GetName();
92  fTitle = from.GetTitle();
93  // need to set parameter values
94  if (from.GetParameters())
95  fParams->SetParameters(from.GetParameters());
96  }
97  // copy the other data members
98  fNpx = from.fNpx;
99  fType = (EFType)from.fType;
100  fNpfits = from.fNpfits;
101  fNDF = from.fNDF;
102  fChisquare = from.fChisquare;
103  fMaximum = from.fMaximum;
104  fMinimum = from.fMinimum;
105  fXmin = from.fXmin;
106  fXmax = from.fXmax;
107 
108  if (from.fParErrors)
109  fParErrors = std::vector<Double_t>(from.fParErrors, from.fParErrors + fNpar);
110  if (from.fParMin)
111  fParMin = std::vector<Double_t>(from.fParMin, from.fParMin + fNpar);
112  if (from.fParMax)
113  fParMax = std::vector<Double_t>(from.fParMax, from.fParMax + fNpar);
114  if (from.fNsave > 0) {
115  assert(from.fSave);
116  fSave = std::vector<Double_t>(from.fSave, from.fSave + from.fNsave);
117  }
118  // set the bits
119  for (int ibit = 0; ibit < 24; ++ibit)
120  if (from.TestBit(BIT(ibit)))
121  SetBit(BIT(ibit));
122 
123  // copy the graph attributes
124  auto &fromLine = static_cast<TAttLine &>(from);
125  fromLine.Copy(*this);
126  auto &fromFill = static_cast<TAttFill &>(from);
127  fromFill.Copy(*this);
128  auto &fromMarker = static_cast<TAttMarker &>(from);
129  fromMarker.Copy(*this);
130  }
131 };
132 } // unnamed namespace
133 
134 static void R__v5TF1Updater(Int_t nobjects, TObject **from, TObject **to)
135 {
136  auto **fromv5 = (ROOT::v5::TF1Data **)from;
137  auto **target = (TF1v5Convert **)to;
138 
139  for (int i = 0; i < nobjects; ++i) {
140  if (fromv5[i] && target[i])
141  target[i]->Convert(*fromv5[i]);
142  }
143 }
144 
145 int R__RegisterTF1UpdaterTrigger = R__SetClonesArrayTF1Updater(R__v5TF1Updater);
146 
147 ClassImp(TF1);
148 
149 // class wrapping evaluation of TF1(x) - y0
150 class GFunc {
151  const TF1 *fFunction;
152  const double fY0;
153 public:
154  GFunc(const TF1 *function , double y): fFunction(function), fY0(y) {}
155  double operator()(double x) const
156  {
157  return fFunction->Eval(x) - fY0;
158  }
159 };
160 
161 // class wrapping evaluation of -TF1(x)
162 class GInverseFunc {
163  const TF1 *fFunction;
164 public:
165  GInverseFunc(const TF1 *function): fFunction(function) {}
166 
167  double operator()(double x) const
168  {
169  return - fFunction->Eval(x);
170  }
171 };
172 // class wrapping evaluation of -TF1(x) for multi-dimension
173 class GInverseFuncNdim {
174  TF1 *fFunction;
175 public:
176  GInverseFuncNdim(TF1 *function): fFunction(function) {}
177 
178  double operator()(const double *x) const
179  {
180  return - fFunction->EvalPar(x, (Double_t *)0);
181  }
182 };
183 
184 // class wrapping function evaluation directly in 1D interface (used for integration)
185 // and implementing the methods for the momentum calculations
186 
187 class TF1_EvalWrapper : public ROOT::Math::IGenFunction {
188 public:
189  TF1_EvalWrapper(TF1 *f, const Double_t *par, bool useAbsVal, Double_t n = 1, Double_t x0 = 0) :
190  fFunc(f),
191  fPar(((par) ? par : f->GetParameters())),
192  fAbsVal(useAbsVal),
193  fN(n),
194  fX0(x0)
195  {
196  fFunc->InitArgs(fX, fPar);
197  if (par) fFunc->SetParameters(par);
198  }
199 
200  ROOT::Math::IGenFunction *Clone() const
201  {
202  // use default copy constructor
203  TF1_EvalWrapper *f = new TF1_EvalWrapper(*this);
204  f->fFunc->InitArgs(f->fX, f->fPar);
205  return f;
206  }
207  // evaluate |f(x)|
208  Double_t DoEval(Double_t x) const
209  {
210  // use evaluation with stored parameters (i.e. pass zero)
211  fX[0] = x;
212  Double_t fval = fFunc->EvalPar(fX, 0);
213  if (fAbsVal && fval < 0) return -fval;
214  return fval;
215  }
216  // evaluate x * |f(x)|
217  Double_t EvalFirstMom(Double_t x)
218  {
219  fX[0] = x;
220  return fX[0] * TMath::Abs(fFunc->EvalPar(fX, 0));
221  }
222  // evaluate (x - x0) ^n * f(x)
223  Double_t EvalNMom(Double_t x) const
224  {
225  fX[0] = x;
226  return TMath::Power(fX[0] - fX0, fN) * TMath::Abs(fFunc->EvalPar(fX, 0));
227  }
228 
229  TF1 *fFunc;
230  mutable Double_t fX[1];
231  const double *fPar;
232  Bool_t fAbsVal;
233  Double_t fN;
234  Double_t fX0;
235 };
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 /** \class TF1
239  \ingroup Hist
240  \brief 1-Dim function class
241 
242 
243 ## TF1: 1-Dim function class
244 
245 A TF1 object is a 1-Dim function defined between a lower and upper limit.
246 The function may be a simple function based on a TFormula expression or a precompiled user function.
247 The function may have associated parameters.
248 TF1 graphics function is via the TH1 and TGraph drawing functions.
249 
250 The following types of functions can be created:
251 
252 1. [Expression using variable x and no parameters]([#F1)
253 2. [Expression using variable x with parameters](#F2)
254 3. [Lambda Expression with variable x and parameters](#F3)
255 4. [A general C function with parameters](#F4)
256 5. [A general C++ function object (functor) with parameters](#F5)
257 6. [A member function with parameters of a general C++ class](#F6)
258 
259 
260 
261 ### <a name="F1"></a> 1 - Expression using variable x and no parameters
262 
263 #### Case 1: inline expression using standard C++ functions/operators
264 
265 Begin_Macro(source)
266 {
267  TF1 *fa1 = new TF1("fa1","sin(x)/x",0,10);
268  fa1->Draw();
269 }
270 End_Macro
271 
272 #### Case 2: inline expression using a ROOT function (e.g. from TMath) without parameters
273 
274 
275 Begin_Macro(source)
276 {
277  TF1 *fa2 = new TF1("fa2","TMath::DiLog(x)",0,10);
278  fa2->Draw();
279 }
280 End_Macro
281 
282 #### Case 3: inline expression using a user defined CLING function by name
283 
284 ~~~~{.cpp}
285 Double_t myFunc(double x) { return x+sin(x); }
286 ....
287 TF1 *fa3 = new TF1("fa3","myFunc(x)",-3,5);
288 fa3->Draw();
289 ~~~~
290 
291 ### <a name="F2"></a> 2 - Expression using variable x with parameters
292 
293 #### Case 1: inline expression using standard C++ functions/operators
294 
295 * Example a:
296 
297 
298 ~~~~{.cpp}
299 TF1 *fa = new TF1("fa","[0]*x*sin([1]*x)",-3,3);
300 ~~~~
301 
302 This creates a function of variable x with 2 parameters. The parameters must be initialized via:
303 
304 ~~~~{.cpp}
305  fa->SetParameter(0,value_first_parameter);
306  fa->SetParameter(1,value_second_parameter);
307 ~~~~
308 
309 
310 Parameters may be given a name:
311 
312 ~~~~{.cpp}
313  fa->SetParName(0,"Constant");
314 ~~~~
315 
316 * Example b:
317 
318 ~~~~{.cpp}
319  TF1 *fb = new TF1("fb","gaus(0)*expo(3)",0,10);
320 ~~~~
321 
322 
323 ``gaus(0)`` is a substitute for ``[0]*exp(-0.5*((x-[1])/[2])**2)`` and ``(0)`` means start numbering parameters at ``0``. ``expo(3)`` is a substitute for ``exp([3]+[4]*x)``.
324 
325 #### Case 2: inline expression using TMath functions with parameters
326 
327 ~~~~{.cpp}
328  TF1 *fb2 = new TF1("fa3","TMath::Landau(x,[0],[1],0)",-5,10);
329  fb2->SetParameters(0.2,1.3);
330  fb2->Draw();
331 ~~~~
332 
333 
334 
335 Begin_Macro
336 {
337  TCanvas *c = new TCanvas("c","c",0,0,500,300);
338  TF1 *fb2 = new TF1("fa3","TMath::Landau(x,[0],[1],0)",-5,10);
339  fb2->SetParameters(0.2,1.3); fb2->Draw();
340  return c;
341 }
342 End_Macro
343 
344 ###<a name="F3"></a> 3 - A lambda expression with variables and parameters
345 
346 \since **6.00/00:**
347 TF1 supports using lambda expressions in the formula. This allows, by using a full C++ syntax the full power of lambda
348 functions and still maintain the capability of storing the function in a file which cannot be done with
349 function pointer or lambda written not as expression, but as code (see items below).
350 
351 Example on how using lambda to define a sum of two functions.
352 Note that is necessary to provide the number of parameters
353 
354 ~~~~{.cpp}
355 TF1 f1("f1","sin(x)",0,10);
356 TF1 f2("f2","cos(x)",0,10);
357 TF1 fsum("f1","[&](double *x, double *p){ return p[0]*f1(x) + p[1]*f2(x); }",0,10,2);
358 ~~~~
359 
360 ###<a name="F4"></a> 4 - A general C function with parameters
361 
362 Consider the macro myfunc.C below:
363 
364 ~~~~{.cpp}
365  // Macro myfunc.C
366  Double_t myfunction(Double_t *x, Double_t *par)
367  {
368  Float_t xx =x[0];
369  Double_t f = TMath::Abs(par[0]*sin(par[1]*xx)/xx);
370  return f;
371  }
372  void myfunc()
373  {
374  TF1 *f1 = new TF1("myfunc",myfunction,0,10,2);
375  f1->SetParameters(2,1);
376  f1->SetParNames("constant","coefficient");
377  f1->Draw();
378  }
379  void myfit()
380  {
381  TH1F *h1=new TH1F("h1","test",100,0,10);
382  h1->FillRandom("myfunc",20000);
383  TF1 *f1 = (TF1 *)gROOT->GetFunction("myfunc");
384  f1->SetParameters(800,1);
385  h1->Fit("myfunc");
386  }
387 ~~~~
388 
389 
390 
391 In an interactive session you can do:
392 
393 ~~~~
394  Root > .L myfunc.C
395  Root > myfunc();
396  Root > myfit();
397 ~~~~
398 
399 
400 
401 TF1 objects can reference other TF1 objects of type A or B defined above. This excludes CLing or compiled functions. However, there is a restriction. A function cannot reference a basic function if the basic function is a polynomial polN.
402 
403 Example:
404 
405 ~~~~{.cpp}
406 {
407  TF1 *fcos = new TF1 ("fcos", "[0]*cos(x)", 0., 10.);
408  fcos->SetParNames( "cos");
409  fcos->SetParameter( 0, 1.1);
410 
411  TF1 *fsin = new TF1 ("fsin", "[0]*sin(x)", 0., 10.);
412  fsin->SetParNames( "sin");
413  fsin->SetParameter( 0, 2.1);
414 
415  TF1 *fsincos = new TF1 ("fsc", "fcos+fsin");
416 
417  TF1 *fs2 = new TF1 ("fs2", "fsc+fsc");
418 }
419 ~~~~
420 
421 
422 ### <a name="F5"></a> 5 - A general C++ function object (functor) with parameters
423 
424 A TF1 can be created from any C++ class implementing the operator()(double *x, double *p). The advantage of the function object is that he can have a state and reference therefore what-ever other object. In this way the user can customize his function.
425 
426 Example:
427 
428 
429 ~~~~{.cpp}
430 class MyFunctionObject {
431  public:
432  // use constructor to customize your function object
433 
434  double operator() (double *x, double *p) {
435  // function implementation using class data members
436  }
437 };
438 {
439  ....
440  MyFunctionObject fobj;
441  TF1 * f = new TF1("f",fobj,0,1,npar); // create TF1 class.
442  .....
443 }
444 ~~~~
445 
446 #### Using a lambda function as a general C++ functor object
447 
448 From C++11 we can use both std::function or even better lambda functions to create the TF1.
449 As above the lambda must have the right signature but can capture whatever we want. For example we can make
450 a TF1 from the TGraph::Eval function as shown below where we use as function parameter the graph normalization.
451 
452 ~~~~{.cpp}
453 TGraph * g = new TGraph(npointx, xvec, yvec);
454 TF1 * f = new TF1("f",[&](double*x, double *p){ return p[0]*g->Eval(x[0]); }, xmin, xmax, 1);
455 ~~~~
456 
457 
458 ### <a name="F6"></a> 6 - A member function with parameters of a general C++ class
459 
460 A TF1 can be created in this case from any member function of a class which has the signature of (double * , double *) and returning a double.
461 
462 Example:
463 
464 ~~~~{.cpp}
465 class MyFunction {
466  public:
467  ...
468  double Evaluate() (double *x, double *p) {
469  // function implementation
470  }
471 };
472 {
473  ....
474  MyFunction * fptr = new MyFunction(....); // create the user function class
475  TF1 * f = new TF1("f",fptr,&MyFunction::Evaluate,0,1,npar,"MyFunction","Evaluate"); // create TF1 class.
476 
477  .....
478 }
479 ~~~~
480 
481 See also the tutorial __math/exampleFunctor.C__ for a running example.
482 */
483 ////////////////////////////////////////////////////////////////////////////
484 
485 TF1 *TF1::fgCurrent = 0;
486 
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 /// TF1 default constructor.
490 
491 TF1::TF1():
492  TNamed(), TAttLine(), TAttFill(), TAttMarker(),
493  fXmin(0), fXmax(0), fNpar(0), fNdim(0), fType(EFType::kFormula)
494 {
495  SetFillStyle(0);
496 }
497 
498 
499 ////////////////////////////////////////////////////////////////////////////////
500 /// F1 constructor using a formula definition
501 ///
502 /// See TFormula constructor for explanation of the formula syntax.
503 ///
504 /// See tutorials: fillrandom, first, fit1, formula1, multifit
505 /// for real examples.
506 ///
507 /// Creates a function of type A or B between xmin and xmax
508 ///
509 /// if formula has the form "fffffff;xxxx;yyyy", it is assumed that
510 /// the formula string is "fffffff" and "xxxx" and "yyyy" are the
511 /// titles for the X and Y axis respectively.
512 
513 TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, EAddToList addToGlobList, bool vectorize) :
514  TNamed(name, formula), TAttLine(), TAttFill(), TAttMarker(), fType(EFType::kFormula)
515 {
516  if (xmin < xmax) {
517  fXmin = xmin;
518  fXmax = xmax;
519  } else {
520  fXmin = xmax; //when called from TF2,TF3
521  fXmax = xmin;
522  }
523  // Create rep formula (no need to add to gROOT list since we will add the TF1 object)
524 
525  // First check if we are making a convolution
526  if (TString(formula, 5) == "CONV(" && formula[strlen(formula) - 1] == ')') {
527  // Look for single ',' delimiter
528  int delimPosition = -1;
529  int parenCount = 0;
530  for (unsigned int i = 5; i < strlen(formula) - 1; i++) {
531  if (formula[i] == '(')
532  parenCount++;
533  else if (formula[i] == ')')
534  parenCount--;
535  else if (formula[i] == ',' && parenCount == 0) {
536  if (delimPosition == -1)
537  delimPosition = i;
538  else
539  Error("TF1", "CONV takes 2 arguments. Too many arguments found in : %s", formula);
540  }
541  }
542  if (delimPosition == -1)
543  Error("TF1", "CONV takes 2 arguments. Only one argument found in : %s", formula);
544 
545  // Having found the delimiter, define the first and second formulas
546  TString formula1 = TString(TString(formula)(5, delimPosition - 5));
547  TString formula2 = TString(TString(formula)(delimPosition + 1, strlen(formula) - 1 - (delimPosition + 1)));
548  // remove spaces from these formulas
549  formula1.ReplaceAll(' ', "");
550  formula2.ReplaceAll(' ', "");
551 
552  TF1 *function1 = (TF1 *)(gROOT->GetListOfFunctions()->FindObject(formula1));
553  if (function1 == nullptr)
554  function1 = new TF1((const char *)formula1, (const char *)formula1, xmin, xmax);
555  TF1 *function2 = (TF1 *)(gROOT->GetListOfFunctions()->FindObject(formula2));
556  if (function2 == nullptr)
557  function2 = new TF1((const char *)formula2, (const char *)formula2, xmin, xmax);
558 
559  // std::cout << "functions have been defined" << std::endl;
560 
561  TF1Convolution *conv = new TF1Convolution(function1, function2);
562 
563  // (note: currently ignoring `useFFT` option)
564  fNpar = conv->GetNpar();
565  fNdim = 1; // (note: may want to extend this in the future?)
566 
567  fType = EFType::kCompositionFcn;
568  fComposition = std::unique_ptr<TF1AbsComposition>(conv);
569 
570  fParams = new TF1Parameters(fNpar); // default to zeros (TF1Convolution has no GetParameters())
571  // set parameter names
572  for (int i = 0; i < fNpar; i++)
573  this->SetParName(i, conv->GetParName(i));
574  // set parameters to default values
575  int f1Npar = function1->GetNpar();
576  int f2Npar = function2->GetNpar();
577  // first, copy parameters from function1
578  for (int i = 0; i < f1Npar; i++)
579  this->SetParameter(i, function1->GetParameter(i));
580  // then, check if the "Constant" parameters were combined
581  // (this code assumes function2 has at most one parameter named "Constant")
582  if (conv->GetNpar() == f1Npar + f2Npar - 1) {
583  int cst1 = function1->GetParNumber("Constant");
584  int cst2 = function2->GetParNumber("Constant");
585  this->SetParameter(cst1, function1->GetParameter(cst1) * function2->GetParameter(cst2));
586  // and copy parameters from function2
587  for (int i = 0; i < f2Npar; i++)
588  if (i < cst2)
589  this->SetParameter(f1Npar + i, function2->GetParameter(i));
590  else if (i > cst2)
591  this->SetParameter(f1Npar + i - 1, function2->GetParameter(i));
592  } else {
593  // or if no constant, simply copy parameters from function2
594  for (int i = 0; i < f2Npar; i++)
595  this->SetParameter(i + f1Npar, function2->GetParameter(i));
596  }
597 
598  // Then check if we need NSUM syntax:
599  } else if (TString(formula, 5) == "NSUM(" && formula[strlen(formula) - 1] == ')') {
600  // using comma as delimiter
601  char delimiter = ',';
602  // first, remove "NSUM(" and ")" and spaces
603  TString formDense = TString(formula)(5,strlen(formula)-5-1);
604  formDense.ReplaceAll(' ', "");
605 
606  // make sure standard functions are defined (e.g. gaus, expo)
607  InitStandardFunctions();
608 
609  // Go char-by-char to split terms and define the relevant functions
610  int parenCount = 0;
611  int termStart = 0;
612  TObjArray *newFuncs = new TObjArray();
613  newFuncs->SetOwner(kTRUE);
614  TObjArray *coeffNames = new TObjArray();
615  coeffNames->SetOwner(kTRUE);
616  TString fullFormula("");
617  for (int i = 0; i < formDense.Length(); ++i) {
618  if (formDense[i] == '(')
619  parenCount++;
620  else if (formDense[i] == ')')
621  parenCount--;
622  else if (formDense[i] == delimiter && parenCount == 0) {
623  // term goes from termStart to i
624  DefineNSUMTerm(newFuncs, coeffNames, fullFormula, formDense, termStart, i, xmin, xmax);
625  termStart = i + 1;
626  }
627  }
628  DefineNSUMTerm(newFuncs, coeffNames, fullFormula, formDense, termStart, formDense.Length(), xmin, xmax);
629 
630  TF1NormSum *normSum = new TF1NormSum(fullFormula, xmin, xmax);
631 
632  if (xmin == 0 && xmax == 1.) Info("TF1","Created TF1NormSum object using the default [0,1] range");
633 
634  fNpar = normSum->GetNpar();
635  fNdim = 1; // (note: may want to extend functionality in the future)
636 
637  fType = EFType::kCompositionFcn;
638  fComposition = std::unique_ptr<TF1AbsComposition>(normSum);
639 
640  fParams = new TF1Parameters(fNpar);
641  fParams->SetParameters(&(normSum->GetParameters())[0]); // inherit default parameters from normSum
642 
643  // Parameter names
644  for (int i = 0; i < fNpar; i++) {
645  if (coeffNames->At(i) != nullptr) {
646  TString coeffName = ((TObjString *)coeffNames->At(i))->GetString();
647  this->SetParName(i, (const char *)coeffName);
648  } else {
649  this->SetParName(i, normSum->GetParName(i));
650  }
651  }
652 
653  } else { // regular TFormula
654  fFormula = new TFormula(name, formula, false, vectorize);
655  fNpar = fFormula->GetNpar();
656  // TFormula can have dimension zero, but since this is a TF1 minimal dim is 1
657  fNdim = fFormula->GetNdim() == 0 ? 1 : fFormula->GetNdim();
658  }
659  if (fNpar) {
660  fParErrors.resize(fNpar);
661  fParMin.resize(fNpar);
662  fParMax.resize(fNpar);
663  }
664  // do we want really to have this un-documented feature where we accept cases where dim > 1
665  // by setting xmin >= xmax ??
666  if (fNdim > 1 && xmin < xmax) {
667  Error("TF1", "function: %s/%s has dimension %d instead of 1", name, formula, fNdim);
668  MakeZombie();
669  }
670 
671  DoInitialize(addToGlobList);
672 }
673 TF1::EAddToList GetGlobalListOption(Option_t * opt) {
674  if (opt == nullptr) return TF1::EAddToList::kDefault;
675  TString option(opt);
676  option.ToUpper();
677  if (option.Contains("NL")) return TF1::EAddToList::kNo;
678  if (option.Contains("GL")) return TF1::EAddToList::kAdd;
679  return TF1::EAddToList::kDefault;
680 }
681 bool GetVectorizedOption(Option_t * opt) {
682  if (opt == nullptr) return false;
683  TString option(opt);
684  option.ToUpper();
685  if (option.Contains("VEC")) return true;
686  return false;
687 }
688 TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, Option_t * opt) :
689 ////////////////////////////////////////////////////////////////////////////////
690 /// Same constructor as above (for TFormula based function) but passing an option strings
691 /// available options
692 /// VEC - vectorize the formula expressions (not possible for lambda based expressions)
693 /// NL - function is not stores in the global list of functions
694 /// GL - function will be always stored in the global list of functions ,
695 /// independently of the global setting of TF1::DefaultAddToGlobalList
696 ///////////////////////////////////////////////////////////////////////////////////
697  TF1(name, formula, xmin, xmax, GetGlobalListOption(opt), GetVectorizedOption(opt) )
698 {}
699 ////////////////////////////////////////////////////////////////////////////////
700 /// F1 constructor using name of an interpreted function.
701 ///
702 /// Creates a function of type C between xmin and xmax.
703 /// name is the name of an interpreted C++ function.
704 /// The function is defined with npar parameters
705 /// fcn must be a function of type:
706 ///
707 /// Double_t fcn(Double_t *x, Double_t *params)
708 ///
709 /// This constructor is called for functions of type C by the C++ interpreter.
710 ///
711 /// WARNING! A function created with this constructor cannot be Cloned.
712 
713 TF1::TF1(const char *name, Double_t xmin, Double_t xmax, Int_t npar, Int_t ndim, EAddToList addToGlobList) :
714  TF1(EFType::kInterpreted, name, xmin, xmax, npar, ndim, addToGlobList, new TF1Parameters(npar))
715 {
716  if (fName.Data()[0] == '*') { // case TF1 name starts with a *
717  Info("TF1", "TF1 has a name starting with a \'*\' - it is for saved TF1 objects in a .C file");
718  return; //case happens via SavePrimitive
719  } else if (fName.IsNull()) {
720  Error("TF1", "requires a proper function name!");
721  return;
722  }
723 
724  fMethodCall = new TMethodCall();
725  fMethodCall->InitWithPrototype(fName, "Double_t*,Double_t*");
726 
727  if (! fMethodCall->IsValid()) {
728  Error("TF1", "No function found with the signature %s(Double_t*,Double_t*)", name);
729  return;
730  }
731 }
732 
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Constructor using a pointer to a real function.
736 ///
737 /// \param npar is the number of free parameters used by the function
738 ///
739 /// This constructor creates a function of type C when invoked
740 /// with the normal C++ compiler.
741 ///
742 /// see test program test/stress.cxx (function stress1) for an example.
743 /// note the interface with an intermediate pointer.
744 ///
745 /// WARNING! A function created with this constructor cannot be Cloned.
746 
747 TF1::TF1(const char *name, Double_t (*fcn)(Double_t *, Double_t *), Double_t xmin, Double_t xmax, Int_t npar, Int_t ndim, EAddToList addToGlobList) :
748  TF1(EFType::kPtrScalarFreeFcn, name, xmin, xmax, npar, ndim, addToGlobList, new TF1Parameters(npar), new TF1FunctorPointerImpl<double>(ROOT::Math::ParamFunctor(fcn)))
749 {}
750 
751 ////////////////////////////////////////////////////////////////////////////////
752 /// Constructor using a pointer to real function.
753 ///
754 /// \param npar is the number of free parameters used by the function
755 ///
756 /// This constructor creates a function of type C when invoked
757 /// with the normal C++ compiler.
758 ///
759 /// see test program test/stress.cxx (function stress1) for an example.
760 /// note the interface with an intermediate pointer.
761 ///
762 /// WARNING! A function created with this constructor cannot be Cloned.
763 
764 TF1::TF1(const char *name, Double_t (*fcn)(const Double_t *, const Double_t *), Double_t xmin, Double_t xmax, Int_t npar, Int_t ndim, EAddToList addToGlobList) :
765  TF1(EFType::kPtrScalarFreeFcn, name, xmin, xmax, npar, ndim, addToGlobList, new TF1Parameters(npar), new TF1FunctorPointerImpl<double>(ROOT::Math::ParamFunctor(fcn)))
766 {}
767 
768 ////////////////////////////////////////////////////////////////////////////////
769 /// Constructor using the Functor class.
770 ///
771 /// \param xmin and
772 /// \param xmax define the plotting range of the function
773 /// \param npar is the number of free parameters used by the function
774 ///
775 /// This constructor can be used only in compiled code
776 ///
777 /// WARNING! A function created with this constructor cannot be Cloned.
778 
779 TF1::TF1(const char *name, ROOT::Math::ParamFunctor f, Double_t xmin, Double_t xmax, Int_t npar, Int_t ndim, EAddToList addToGlobList) :
780  TF1(EFType::kPtrScalarFreeFcn, name, xmin, xmax, npar, ndim, addToGlobList, new TF1Parameters(npar), new TF1FunctorPointerImpl<double>(ROOT::Math::ParamFunctor(f)))
781 {}
782 
783 ////////////////////////////////////////////////////////////////////////////////
784 /// Common initialization of the TF1. Add to the global list and
785 /// set the default style
786 
787 void TF1::DoInitialize(EAddToList addToGlobalList)
788 {
789  // add to global list of functions if default adding is on OR if bit is set
790  bool doAdd = ((addToGlobalList == EAddToList::kDefault && fgAddToGlobList)
791  || addToGlobalList == EAddToList::kAdd);
792  if (doAdd && gROOT) {
793  SetBit(kNotGlobal, kFALSE);
794  R__LOCKGUARD(gROOTMutex);
795  // Store formula in linked list of formula in ROOT
796  TF1 *f1old = (TF1 *)gROOT->GetListOfFunctions()->FindObject(fName);
797  if (f1old) {
798  gROOT->GetListOfFunctions()->Remove(f1old);
799  // We removed f1old from the list, it is not longer global.
800  // (See TF1::AddToGlobalList which requires this flag to be correct).
801  f1old->SetBit(kNotGlobal, kTRUE);
802  }
803  gROOT->GetListOfFunctions()->Add(this);
804  } else
805  SetBit(kNotGlobal, kTRUE);
806 
807  if (gStyle) {
808  SetLineColor(gStyle->GetFuncColor());
809  SetLineWidth(gStyle->GetFuncWidth());
810  SetLineStyle(gStyle->GetFuncStyle());
811  }
812  SetFillStyle(0);
813 }
814 
815 ////////////////////////////////////////////////////////////////////////////////
816 /// Static method to add/avoid to add automatically functions to the global list (gROOT->GetListOfFunctions() )
817 /// After having called this static method, all the functions created afterwards will follow the
818 /// desired behaviour.
819 ///
820 /// By default the functions are added automatically
821 /// It returns the previous status (true if the functions are added automatically)
822 
823 Bool_t TF1::DefaultAddToGlobalList(Bool_t on)
824 {
825  return fgAddToGlobList.exchange(on);
826 }
827 
828 ////////////////////////////////////////////////////////////////////////////////
829 /// Add to global list of functions (gROOT->GetListOfFunctions() )
830 /// return previous status (true if the function was already in the list false if not)
831 
832 Bool_t TF1::AddToGlobalList(Bool_t on)
833 {
834  if (!gROOT) return false;
835 
836  bool prevStatus = !TestBit(kNotGlobal);
837  if (on) {
838  if (prevStatus) {
839  R__LOCKGUARD(gROOTMutex);
840  assert(gROOT->GetListOfFunctions()->FindObject(this) != nullptr);
841  return on; // do nothing
842  }
843  // do I need to delete previous one with the same name ???
844  //TF1 * old = dynamic_cast<TF1*>( gROOT->GetListOfFunctions()->FindObject(GetName()) );
845  //if (old) { gROOT->GetListOfFunctions()->Remove(old); old->SetBit(kNotGlobal, kTRUE); }
846  R__LOCKGUARD(gROOTMutex);
847  gROOT->GetListOfFunctions()->Add(this);
848  SetBit(kNotGlobal, kFALSE);
849  } else if (prevStatus) {
850  // if previous status was on and now is off we need to remove the function
851  SetBit(kNotGlobal, kTRUE);
852  R__LOCKGUARD(gROOTMutex);
853  TF1 *old = dynamic_cast<TF1 *>(gROOT->GetListOfFunctions()->FindObject(GetName()));
854  if (!old) {
855  Warning("AddToGlobalList", "Function is supposed to be in the global list but it is not present");
856  return kFALSE;
857  }
858  gROOT->GetListOfFunctions()->Remove(this);
859  }
860  return prevStatus;
861 }
862 
863 ////////////////////////////////////////////////////////////////////////////////
864 /// Helper functions for NSUM parsing
865 
866 // Defines the formula that a given term uses, if not already defined,
867 // and appends "sanitized" formula to `fullFormula` string
868 void TF1::DefineNSUMTerm(TObjArray *newFuncs, TObjArray *coeffNames, TString &fullFormula, TString &formula,
869  int termStart, int termEnd, Double_t xmin, Double_t xmax)
870 {
871  TString originalTerm = formula(termStart, termEnd-termStart);
872  int coeffLength = TermCoeffLength(originalTerm);
873  if (coeffLength != -1)
874  termStart += coeffLength + 1;
875 
876  // `originalFunc` is the real formula and `cleanedFunc` is the
877  // sanitized version that will not confuse the TF1NormSum
878  // constructor
879  TString originalFunc = formula(termStart, termEnd-termStart);
880  TString cleanedFunc = TString(formula(termStart, termEnd-termStart))
881  .ReplaceAll('+', "<plus>")
882  .ReplaceAll('*',"<times>");
883 
884  // define function (if necessary)
885  if (!gROOT->GetListOfFunctions()->FindObject(cleanedFunc))
886  newFuncs->Add(new TF1(cleanedFunc, originalFunc, xmin, xmax));
887 
888  // append sanitized term to `fullFormula`
889  if (fullFormula.Length() != 0)
890  fullFormula.Append('+');
891 
892  // include numerical coefficient
893  if (coeffLength != -1 && originalTerm[0] != '[')
894  fullFormula.Append(originalTerm(0, coeffLength+1));
895 
896  // add coefficient name
897  if (coeffLength != -1 && originalTerm[0] == '[')
898  coeffNames->Add(new TObjString(TString(originalTerm(1,coeffLength-2))));
899  else
900  coeffNames->Add(nullptr);
901 
902  fullFormula.Append(cleanedFunc);
903 }
904 
905 
906 // Returns length of coeff at beginning of a given term, not counting the '*'
907 // Returns -1 if no coeff found
908 // Coeff can be either a number or parameter name
909 int TF1::TermCoeffLength(TString &term) {
910  int firstAsterisk = term.First('*');
911  if (firstAsterisk == -1) // no asterisk found
912  return -1;
913 
914  if (TString(term(0,firstAsterisk)).IsFloat())
915  return firstAsterisk;
916 
917  if (term[0] == '[' && term[firstAsterisk-1] == ']'
918  && TString(term(1,firstAsterisk-2)).IsAlnum())
919  return firstAsterisk;
920 
921  return -1;
922 }
923 
924 ////////////////////////////////////////////////////////////////////////////////
925 /// Operator =
926 
927 TF1 &TF1::operator=(const TF1 &rhs)
928 {
929  if (this != &rhs) {
930  rhs.Copy(*this);
931  }
932  return *this;
933 }
934 
935 
936 ////////////////////////////////////////////////////////////////////////////////
937 /// TF1 default destructor.
938 
939 TF1::~TF1()
940 {
941  if (fHistogram) delete fHistogram;
942  if (fMethodCall) delete fMethodCall;
943 
944  // this was before in TFormula destructor
945  {
946  R__LOCKGUARD(gROOTMutex);
947  if (gROOT) gROOT->GetListOfFunctions()->Remove(this);
948  }
949 
950  if (fParent) fParent->RecursiveRemove(this);
951 
952  if (fFormula) delete fFormula;
953  if (fParams) delete fParams;
954  if (fFunctor) delete fFunctor;
955 }
956 
957 
958 ////////////////////////////////////////////////////////////////////////////////
959 
960 TF1::TF1(const TF1 &f1) :
961  TNamed(f1), TAttLine(f1), TAttFill(f1), TAttMarker(f1),
962  fXmin(0), fXmax(0), fNpar(0), fNdim(0), fType(EFType::kFormula)
963 {
964  ((TF1 &)f1).Copy(*this);
965 }
966 
967 
968 ////////////////////////////////////////////////////////////////////////////////
969 /// Static function: set the fgAbsValue flag.
970 /// By default TF1::Integral uses the original function value to compute the integral
971 /// However, TF1::Moment, CentralMoment require to compute the integral
972 /// using the absolute value of the function.
973 
974 void TF1::AbsValue(Bool_t flag)
975 {
976  fgAbsValue = flag;
977 }
978 
979 
980 ////////////////////////////////////////////////////////////////////////////////
981 /// Browse.
982 
983 void TF1::Browse(TBrowser *b)
984 {
985  Draw(b ? b->GetDrawOption() : "");
986  gPad->Update();
987 }
988 
989 
990 ////////////////////////////////////////////////////////////////////////////////
991 /// Copy this F1 to a new F1.
992 /// Note that the cached integral with its related arrays are not copied
993 /// (they are also set as transient data members)
994 
995 void TF1::Copy(TObject &obj) const
996 {
997  delete((TF1 &)obj).fHistogram;
998  delete((TF1 &)obj).fMethodCall;
999 
1000  TNamed::Copy((TF1 &)obj);
1001  TAttLine::Copy((TF1 &)obj);
1002  TAttFill::Copy((TF1 &)obj);
1003  TAttMarker::Copy((TF1 &)obj);
1004  ((TF1 &)obj).fXmin = fXmin;
1005  ((TF1 &)obj).fXmax = fXmax;
1006  ((TF1 &)obj).fNpx = fNpx;
1007  ((TF1 &)obj).fNpar = fNpar;
1008  ((TF1 &)obj).fNdim = fNdim;
1009  ((TF1 &)obj).fType = fType;
1010  ((TF1 &)obj).fChisquare = fChisquare;
1011  ((TF1 &)obj).fNpfits = fNpfits;
1012  ((TF1 &)obj).fNDF = fNDF;
1013  ((TF1 &)obj).fMinimum = fMinimum;
1014  ((TF1 &)obj).fMaximum = fMaximum;
1015 
1016  ((TF1 &)obj).fParErrors = fParErrors;
1017  ((TF1 &)obj).fParMin = fParMin;
1018  ((TF1 &)obj).fParMax = fParMax;
1019  ((TF1 &)obj).fParent = fParent;
1020  ((TF1 &)obj).fSave = fSave;
1021  ((TF1 &)obj).fHistogram = 0;
1022  ((TF1 &)obj).fMethodCall = 0;
1023  ((TF1 &)obj).fNormalized = fNormalized;
1024  ((TF1 &)obj).fNormIntegral = fNormIntegral;
1025  ((TF1 &)obj).fFormula = 0;
1026 
1027  if (fFormula) assert(fFormula->GetNpar() == fNpar);
1028 
1029  if (fMethodCall) {
1030  // use copy-constructor of TMethodCall
1031  if (((TF1 &)obj).fMethodCall) delete((TF1 &)obj).fMethodCall;
1032  TMethodCall *m = new TMethodCall(*fMethodCall);
1033 // m->InitWithPrototype(fMethodCall->GetMethodName(),fMethodCall->GetProto());
1034  ((TF1 &)obj).fMethodCall = m;
1035  }
1036  if (fFormula) {
1037  TFormula *formulaToCopy = ((TF1 &)obj).fFormula;
1038  if (formulaToCopy) delete formulaToCopy;
1039  formulaToCopy = new TFormula();
1040  fFormula->Copy(*formulaToCopy);
1041  ((TF1 &)obj).fFormula = formulaToCopy;
1042  }
1043  if (fParams) {
1044  TF1Parameters *paramsToCopy = ((TF1 &)obj).fParams;
1045  if (paramsToCopy) *paramsToCopy = *fParams;
1046  else ((TF1 &)obj).fParams = new TF1Parameters(*fParams);
1047  }
1048  if (fFunctor) {
1049  // use clone of TF1FunctorPointer
1050  if (((TF1 &)obj).fFunctor) delete((TF1 &)obj).fFunctor;
1051  ((TF1 &)obj).fFunctor = fFunctor->Clone();
1052  }
1053 
1054  if (fComposition) {
1055  TF1AbsComposition *comp = (TF1AbsComposition *)fComposition->IsA()->New();
1056  fComposition->Copy(*comp);
1057  ((TF1 &)obj).fComposition = std::unique_ptr<TF1AbsComposition>(comp);
1058  }
1059 }
1060 
1061 
1062 ////////////////////////////////////////////////////////////////////////////////
1063 /// Returns the first derivative of the function at point x,
1064 /// computed by Richardson's extrapolation method (use 2 derivative estimates
1065 /// to compute a third, more accurate estimation)
1066 /// first, derivatives with steps h and h/2 are computed by central difference formulas
1067 /// \f[
1068 /// D(h) = \frac{f(x+h) - f(x-h)}{2h}
1069 /// \f]
1070 /// the final estimate
1071 /// \f[
1072 /// D = \frac{4D(h/2) - D(h)}{3}
1073 /// \f]
1074 /// "Numerical Methods for Scientists and Engineers", H.M.Antia, 2nd edition"
1075 ///
1076 /// if the argument params is null, the current function parameters are used,
1077 /// otherwise the parameters in params are used.
1078 ///
1079 /// the argument eps may be specified to control the step size (precision).
1080 /// the step size is taken as eps*(xmax-xmin).
1081 /// the default value (0.001) should be good enough for the vast majority
1082 /// of functions. Give a smaller value if your function has many changes
1083 /// of the second derivative in the function range.
1084 ///
1085 /// Getting the error via TF1::DerivativeError:
1086 /// (total error = roundoff error + interpolation error)
1087 /// the estimate of the roundoff error is taken as follows:
1088 /// \f[
1089 /// err = k\sqrt{f(x)^{2} + x^{2}deriv^{2}}\sqrt{\sum ai^{2}},
1090 /// \f]
1091 /// where k is the double precision, ai are coefficients used in
1092 /// central difference formulas
1093 /// interpolation error is decreased by making the step size h smaller.
1094 ///
1095 /// \author Anna Kreshuk
1096 
1097 Double_t TF1::Derivative(Double_t x, Double_t *params, Double_t eps) const
1098 {
1099  if (GetNdim() > 1) {
1100  Warning("Derivative", "Function dimension is larger than one");
1101  }
1102 
1103  ROOT::Math::RichardsonDerivator rd;
1104  double xmin, xmax;
1105  GetRange(xmin, xmax);
1106  // this is not optimal (should be used the average x instead of the range)
1107  double h = eps * std::abs(xmax - xmin);
1108  if (h <= 0) h = 0.001;
1109  double der = 0;
1110  if (params) {
1111  ROOT::Math::WrappedTF1 wtf(*(const_cast<TF1 *>(this)));
1112  wtf.SetParameters(params);
1113  der = rd.Derivative1(wtf, x, h);
1114  } else {
1115  // no need to set parameters used a non-parametric wrapper to avoid allocating
1116  // an array with parameter values
1117  ROOT::Math::WrappedFunction<const TF1 & > wf(*this);
1118  der = rd.Derivative1(wf, x, h);
1119  }
1120 
1121  gErrorTF1 = rd.Error();
1122  return der;
1123 
1124 }
1125 
1126 
1127 ////////////////////////////////////////////////////////////////////////////////
1128 /// Returns the second derivative of the function at point x,
1129 /// computed by Richardson's extrapolation method (use 2 derivative estimates
1130 /// to compute a third, more accurate estimation)
1131 /// first, derivatives with steps h and h/2 are computed by central difference formulas
1132 /// \f[
1133 /// D(h) = \frac{f(x+h) - 2f(x) + f(x-h)}{h^{2}}
1134 /// \f]
1135 /// the final estimate
1136 /// \f[
1137 /// D = \frac{4D(h/2) - D(h)}{3}
1138 /// \f]
1139 /// "Numerical Methods for Scientists and Engineers", H.M.Antia, 2nd edition"
1140 ///
1141 /// if the argument params is null, the current function parameters are used,
1142 /// otherwise the parameters in params are used.
1143 ///
1144 /// the argument eps may be specified to control the step size (precision).
1145 /// the step size is taken as eps*(xmax-xmin).
1146 /// the default value (0.001) should be good enough for the vast majority
1147 /// of functions. Give a smaller value if your function has many changes
1148 /// of the second derivative in the function range.
1149 ///
1150 /// Getting the error via TF1::DerivativeError:
1151 /// (total error = roundoff error + interpolation error)
1152 /// the estimate of the roundoff error is taken as follows:
1153 /// \f[
1154 /// err = k\sqrt{f(x)^{2} + x^{2}deriv^{2}}\sqrt{\sum ai^{2}},
1155 /// \f]
1156 /// where k is the double precision, ai are coefficients used in
1157 /// central difference formulas
1158 /// interpolation error is decreased by making the step size h smaller.
1159 ///
1160 /// \author Anna Kreshuk
1161 
1162 Double_t TF1::Derivative2(Double_t x, Double_t *params, Double_t eps) const
1163 {
1164  if (GetNdim() > 1) {
1165  Warning("Derivative2", "Function dimension is larger than one");
1166  }
1167 
1168  ROOT::Math::RichardsonDerivator rd;
1169  double xmin, xmax;
1170  GetRange(xmin, xmax);
1171  // this is not optimal (should be used the average x instead of the range)
1172  double h = eps * std::abs(xmax - xmin);
1173  if (h <= 0) h = 0.001;
1174  double der = 0;
1175  if (params) {
1176  ROOT::Math::WrappedTF1 wtf(*(const_cast<TF1 *>(this)));
1177  wtf.SetParameters(params);
1178  der = rd.Derivative2(wtf, x, h);
1179  } else {
1180  // no need to set parameters used a non-parametric wrapper to avoid allocating
1181  // an array with parameter values
1182  ROOT::Math::WrappedFunction<const TF1 & > wf(*this);
1183  der = rd.Derivative2(wf, x, h);
1184  }
1185 
1186  gErrorTF1 = rd.Error();
1187 
1188  return der;
1189 }
1190 
1191 
1192 ////////////////////////////////////////////////////////////////////////////////
1193 /// Returns the third derivative of the function at point x,
1194 /// computed by Richardson's extrapolation method (use 2 derivative estimates
1195 /// to compute a third, more accurate estimation)
1196 /// first, derivatives with steps h and h/2 are computed by central difference formulas
1197 /// \f[
1198 /// D(h) = \frac{f(x+2h) - 2f(x+h) + 2f(x-h) - f(x-2h)}{2h^{3}}
1199 /// \f]
1200 /// the final estimate
1201 /// \f[
1202 /// D = \frac{4D(h/2) - D(h)}{3}
1203 /// \f]
1204 /// "Numerical Methods for Scientists and Engineers", H.M.Antia, 2nd edition"
1205 ///
1206 /// if the argument params is null, the current function parameters are used,
1207 /// otherwise the parameters in params are used.
1208 ///
1209 /// the argument eps may be specified to control the step size (precision).
1210 /// the step size is taken as eps*(xmax-xmin).
1211 /// the default value (0.001) should be good enough for the vast majority
1212 /// of functions. Give a smaller value if your function has many changes
1213 /// of the second derivative in the function range.
1214 ///
1215 /// Getting the error via TF1::DerivativeError:
1216 /// (total error = roundoff error + interpolation error)
1217 /// the estimate of the roundoff error is taken as follows:
1218 /// \f[
1219 /// err = k\sqrt{f(x)^{2} + x^{2}deriv^{2}}\sqrt{\sum ai^{2}},
1220 /// \f]
1221 /// where k is the double precision, ai are coefficients used in
1222 /// central difference formulas
1223 /// interpolation error is decreased by making the step size h smaller.
1224 ///
1225 /// \author Anna Kreshuk
1226 
1227 Double_t TF1::Derivative3(Double_t x, Double_t *params, Double_t eps) const
1228 {
1229  if (GetNdim() > 1) {
1230  Warning("Derivative3", "Function dimension is larger than one");
1231  }
1232 
1233  ROOT::Math::RichardsonDerivator rd;
1234  double xmin, xmax;
1235  GetRange(xmin, xmax);
1236  // this is not optimal (should be used the average x instead of the range)
1237  double h = eps * std::abs(xmax - xmin);
1238  if (h <= 0) h = 0.001;
1239  double der = 0;
1240  if (params) {
1241  ROOT::Math::WrappedTF1 wtf(*(const_cast<TF1 *>(this)));
1242  wtf.SetParameters(params);
1243  der = rd.Derivative3(wtf, x, h);
1244  } else {
1245  // no need to set parameters used a non-parametric wrapper to avoid allocating
1246  // an array with parameter values
1247  ROOT::Math::WrappedFunction<const TF1 & > wf(*this);
1248  der = rd.Derivative3(wf, x, h);
1249  }
1250 
1251  gErrorTF1 = rd.Error();
1252  return der;
1253 
1254 }
1255 
1256 
1257 ////////////////////////////////////////////////////////////////////////////////
1258 /// Static function returning the error of the last call to the of Derivative's
1259 /// functions
1260 
1261 Double_t TF1::DerivativeError()
1262 {
1263  return gErrorTF1;
1264 }
1265 
1266 
1267 ////////////////////////////////////////////////////////////////////////////////
1268 /// Compute distance from point px,py to a function.
1269 ///
1270 /// Compute the closest distance of approach from point px,py to this
1271 /// function. The distance is computed in pixels units.
1272 ///
1273 /// Note that px is called with a negative value when the TF1 is in
1274 /// TGraph or TH1 list of functions. In this case there is no point
1275 /// looking at the histogram axis.
1276 
1277 Int_t TF1::DistancetoPrimitive(Int_t px, Int_t py)
1278 {
1279  if (!fHistogram) return 9999;
1280  Int_t distance = 9999;
1281  if (px >= 0) {
1282  distance = fHistogram->DistancetoPrimitive(px, py);
1283  if (distance <= 1) return distance;
1284  } else {
1285  px = -px;
1286  }
1287 
1288  Double_t xx[1];
1289  Double_t x = gPad->AbsPixeltoX(px);
1290  xx[0] = gPad->PadtoX(x);
1291  if (xx[0] < fXmin || xx[0] > fXmax) return distance;
1292  Double_t fval = Eval(xx[0]);
1293  Double_t y = gPad->YtoPad(fval);
1294  Int_t pybin = gPad->YtoAbsPixel(y);
1295  return TMath::Abs(py - pybin);
1296 }
1297 
1298 
1299 ////////////////////////////////////////////////////////////////////////////////
1300 /// Draw this function with its current attributes.
1301 ///
1302 /// Possible option values are:
1303 ///
1304 /// option | description
1305 /// -------|----------------------------------------
1306 /// "SAME" | superimpose on top of existing picture
1307 /// "L" | connect all computed points with a straight line
1308 /// "C" | connect all computed points with a smooth curve
1309 /// "FC" | draw a fill area below a smooth curve
1310 ///
1311 /// Note that the default value is "L". Therefore to draw on top
1312 /// of an existing picture, specify option "LSAME"
1313 ///
1314 /// NB. You must use DrawCopy if you want to draw several times the same
1315 /// function in the current canvas.
1316 
1317 void TF1::Draw(Option_t *option)
1318 {
1319  TString opt = option;
1320  opt.ToLower();
1321  if (gPad && !opt.Contains("same")) gPad->Clear();
1322 
1323  AppendPad(option);
1324 
1325  gPad->IncrementPaletteColor(1, opt);
1326 }
1327 
1328 
1329 ////////////////////////////////////////////////////////////////////////////////
1330 /// Draw a copy of this function with its current attributes.
1331 ///
1332 /// This function MUST be used instead of Draw when you want to draw
1333 /// the same function with different parameters settings in the same canvas.
1334 ///
1335 /// Possible option values are:
1336 ///
1337 /// option | description
1338 /// -------|----------------------------------------
1339 /// "SAME" | superimpose on top of existing picture
1340 /// "L" | connect all computed points with a straight line
1341 /// "C" | connect all computed points with a smooth curve
1342 /// "FC" | draw a fill area below a smooth curve
1343 ///
1344 /// Note that the default value is "L". Therefore to draw on top
1345 /// of an existing picture, specify option "LSAME"
1346 
1347 TF1 *TF1::DrawCopy(Option_t *option) const
1348 {
1349  TF1 *newf1 = (TF1 *)this->IsA()->New();
1350  Copy(*newf1);
1351  newf1->AppendPad(option);
1352  newf1->SetBit(kCanDelete);
1353  return newf1;
1354 }
1355 
1356 
1357 ////////////////////////////////////////////////////////////////////////////////
1358 /// Draw derivative of this function
1359 ///
1360 /// An intermediate TGraph object is built and drawn with option.
1361 /// The function returns a pointer to the TGraph object. Do:
1362 ///
1363 /// TGraph *g = (TGraph*)myfunc.DrawDerivative(option);
1364 ///
1365 /// The resulting graph will be drawn into the current pad.
1366 /// If this function is used via the context menu, it recommended
1367 /// to create a new canvas/pad before invoking this function.
1368 
1369 TObject *TF1::DrawDerivative(Option_t *option)
1370 {
1371  TVirtualPad *pad = gROOT->GetSelectedPad();
1372  TVirtualPad *padsav = gPad;
1373  if (pad) pad->cd();
1374 
1375  TGraph *gr = new TGraph(this, "d");
1376  gr->Draw(option);
1377  if (padsav) padsav->cd();
1378  return gr;
1379 }
1380 
1381 
1382 ////////////////////////////////////////////////////////////////////////////////
1383 /// Draw integral of this function
1384 ///
1385 /// An intermediate TGraph object is built and drawn with option.
1386 /// The function returns a pointer to the TGraph object. Do:
1387 ///
1388 /// TGraph *g = (TGraph*)myfunc.DrawIntegral(option);
1389 ///
1390 /// The resulting graph will be drawn into the current pad.
1391 /// If this function is used via the context menu, it recommended
1392 /// to create a new canvas/pad before invoking this function.
1393 
1394 TObject *TF1::DrawIntegral(Option_t *option)
1395 {
1396  TVirtualPad *pad = gROOT->GetSelectedPad();
1397  TVirtualPad *padsav = gPad;
1398  if (pad) pad->cd();
1399 
1400  TGraph *gr = new TGraph(this, "i");
1401  gr->Draw(option);
1402  if (padsav) padsav->cd();
1403  return gr;
1404 }
1405 
1406 
1407 ////////////////////////////////////////////////////////////////////////////////
1408 /// Draw function between xmin and xmax.
1409 
1410 void TF1::DrawF1(Double_t xmin, Double_t xmax, Option_t *option)
1411 {
1412 // //if(Compile(formula)) return ;
1413  SetRange(xmin, xmax);
1414 
1415  Draw(option);
1416 }
1417 
1418 
1419 ////////////////////////////////////////////////////////////////////////////////
1420 /// Evaluate this function.
1421 ///
1422 /// Computes the value of this function (general case for a 3-d function)
1423 /// at point x,y,z.
1424 /// For a 1-d function give y=0 and z=0
1425 /// The current value of variables x,y,z is passed through x, y and z.
1426 /// The parameters used will be the ones in the array params if params is given
1427 /// otherwise parameters will be taken from the stored data members fParams
1428 
1429 Double_t TF1::Eval(Double_t x, Double_t y, Double_t z, Double_t t) const
1430 {
1431  if (fType == EFType::kFormula) return fFormula->Eval(x, y, z, t);
1432 
1433  Double_t xx[4] = {x, y, z, t};
1434  Double_t *pp = (Double_t *)fParams->GetParameters();
1435  // if (fType == EFType::kInterpreted)((TF1 *)this)->InitArgs(xx, pp);
1436  return ((TF1 *)this)->EvalPar(xx, pp);
1437 }
1438 
1439 
1440 ////////////////////////////////////////////////////////////////////////////////
1441 /// Evaluate function with given coordinates and parameters.
1442 ///
1443 /// Compute the value of this function at point defined by array x
1444 /// and current values of parameters in array params.
1445 /// If argument params is omitted or equal 0, the internal values
1446 /// of parameters (array fParams) will be used instead.
1447 /// For a 1-D function only x[0] must be given.
1448 /// In case of a multi-dimensional function, the arrays x must be
1449 /// filled with the corresponding number of dimensions.
1450 ///
1451 /// WARNING. In case of an interpreted function (fType=2), it is the
1452 /// user's responsibility to initialize the parameters via InitArgs
1453 /// before calling this function.
1454 /// InitArgs should be called at least once to specify the addresses
1455 /// of the arguments x and params.
1456 /// InitArgs should be called every time these addresses change.
1457 
1458 Double_t TF1::EvalPar(const Double_t *x, const Double_t *params)
1459 {
1460  //fgCurrent = this;
1461 
1462  if (fType == EFType::kFormula) {
1463  assert(fFormula);
1464 
1465  if (fNormalized && fNormIntegral != 0)
1466  return fFormula->EvalPar(x, params) / fNormIntegral;
1467  else
1468  return fFormula->EvalPar(x, params);
1469  }
1470  Double_t result = 0;
1471  if (fType == EFType::kPtrScalarFreeFcn || fType == EFType::kTemplScalar) {
1472  if (fFunctor) {
1473  assert(fParams);
1474  if (params) result = ((TF1FunctorPointerImpl<Double_t> *)fFunctor)->fImpl((Double_t *)x, (Double_t *)params);
1475  else result = ((TF1FunctorPointerImpl<Double_t> *)fFunctor)->fImpl((Double_t *)x, (Double_t *)fParams->GetParameters());
1476 
1477  } else result = GetSave(x);
1478 
1479  if (fNormalized && fNormIntegral != 0)
1480  result = result / fNormIntegral;
1481 
1482  return result;
1483  }
1484  if (fType == EFType::kInterpreted) {
1485  if (fMethodCall) fMethodCall->Execute(result);
1486  else result = GetSave(x);
1487 
1488  if (fNormalized && fNormIntegral != 0)
1489  result = result / fNormIntegral;
1490 
1491  return result;
1492  }
1493 
1494 #ifdef R__HAS_VECCORE
1495  if (fType == EFType::kTemplVec) {
1496  if (fFunctor) {
1497  if (params) result = EvalParVec(x, params);
1498  else result = EvalParVec(x, (Double_t *) fParams->GetParameters());
1499  }
1500  else {
1501  result = GetSave(x);
1502  }
1503 
1504  if (fNormalized && fNormIntegral != 0)
1505  result = result / fNormIntegral;
1506 
1507  return result;
1508  }
1509 #endif
1510 
1511  if (fType == EFType::kCompositionFcn) {
1512  if (!fComposition)
1513  Error("EvalPar", "Composition function not found");
1514 
1515  result = (*fComposition)(x, params);
1516  }
1517 
1518  return result;
1519 }
1520 
1521 ////////////////////////////////////////////////////////////////////////////////
1522 /// Execute action corresponding to one event.
1523 ///
1524 /// This member function is called when a F1 is clicked with the locator
1525 
1526 void TF1::ExecuteEvent(Int_t event, Int_t px, Int_t py)
1527 {
1528  if (!gPad) return;
1529 
1530  if (fHistogram) fHistogram->ExecuteEvent(event, px, py);
1531 
1532  if (!gPad->GetView()) {
1533  if (event == kMouseMotion) gPad->SetCursor(kHand);
1534  }
1535 }
1536 
1537 
1538 ////////////////////////////////////////////////////////////////////////////////
1539 /// Fix the value of a parameter
1540 /// The specified value will be used in a fit operation
1541 
1542 void TF1::FixParameter(Int_t ipar, Double_t value)
1543 {
1544  if (ipar < 0 || ipar > GetNpar() - 1) return;
1545  SetParameter(ipar, value);
1546  if (value != 0) SetParLimits(ipar, value, value);
1547  else SetParLimits(ipar, 1, 1);
1548 }
1549 
1550 
1551 ////////////////////////////////////////////////////////////////////////////////
1552 /// Static function returning the current function being processed
1553 
1554 TF1 *TF1::GetCurrent()
1555 {
1556  ::Warning("TF1::GetCurrent", "This function is obsolete and is working only for the current painted functions");
1557  return fgCurrent;
1558 }
1559 
1560 
1561 ////////////////////////////////////////////////////////////////////////////////
1562 /// Return a pointer to the histogram used to visualise the function
1563 
1564 TH1 *TF1::GetHistogram() const
1565 {
1566  if (fHistogram) return fHistogram;
1567 
1568  // histogram has not been yet created - create it
1569  // should not we make this function not const ??
1570  const_cast<TF1 *>(this)->fHistogram = const_cast<TF1 *>(this)->CreateHistogram();
1571  if (!fHistogram) Error("GetHistogram", "Error creating histogram for function %s of type %s", GetName(), IsA()->GetName());
1572  return fHistogram;
1573 }
1574 
1575 
1576 ////////////////////////////////////////////////////////////////////////////////
1577 /// Returns the maximum value of the function
1578 ///
1579 /// Method:
1580 /// First, the grid search is used to bracket the maximum
1581 /// with the step size = (xmax-xmin)/fNpx.
1582 /// This way, the step size can be controlled via the SetNpx() function.
1583 /// If the function is unimodal or if its extrema are far apart, setting
1584 /// the fNpx to a small value speeds the algorithm up many times.
1585 /// Then, Brent's method is applied on the bracketed interval
1586 /// epsilon (default = 1.E-10) controls the relative accuracy (if |x| > 1 )
1587 /// and absolute (if |x| < 1) and maxiter (default = 100) controls the maximum number
1588 /// of iteration of the Brent algorithm
1589 /// If the flag logx is set the grid search is done in log step size
1590 /// This is done automatically if the log scale is set in the current Pad
1591 ///
1592 /// NOTE: see also TF1::GetMaximumX and TF1::GetX
1593 
1594 Double_t TF1::GetMaximum(Double_t xmin, Double_t xmax, Double_t epsilon, Int_t maxiter, Bool_t logx) const
1595 {
1596  if (xmin >= xmax) {
1597  xmin = fXmin;
1598  xmax = fXmax;
1599  }
1600 
1601  if (!logx && gPad != 0) logx = gPad->GetLogx();
1602 
1603  ROOT::Math::BrentMinimizer1D bm;
1604  GInverseFunc g(this);
1605  ROOT::Math::WrappedFunction<GInverseFunc> wf1(g);
1606  bm.SetFunction(wf1, xmin, xmax);
1607  bm.SetNpx(fNpx);
1608  bm.SetLogScan(logx);
1609  bm.Minimize(maxiter, epsilon, epsilon);
1610  Double_t x;
1611  x = - bm.FValMinimum();
1612 
1613  return x;
1614 }
1615 
1616 
1617 ////////////////////////////////////////////////////////////////////////////////
1618 /// Returns the X value corresponding to the maximum value of the function
1619 ///
1620 /// Method:
1621 /// First, the grid search is used to bracket the maximum
1622 /// with the step size = (xmax-xmin)/fNpx.
1623 /// This way, the step size can be controlled via the SetNpx() function.
1624 /// If the function is unimodal or if its extrema are far apart, setting
1625 /// the fNpx to a small value speeds the algorithm up many times.
1626 /// Then, Brent's method is applied on the bracketed interval
1627 /// epsilon (default = 1.E-10) controls the relative accuracy (if |x| > 1 )
1628 /// and absolute (if |x| < 1) and maxiter (default = 100) controls the maximum number
1629 /// of iteration of the Brent algorithm
1630 /// If the flag logx is set the grid search is done in log step size
1631 /// This is done automatically if the log scale is set in the current Pad
1632 ///
1633 /// NOTE: see also TF1::GetX
1634 
1635 Double_t TF1::GetMaximumX(Double_t xmin, Double_t xmax, Double_t epsilon, Int_t maxiter, Bool_t logx) const
1636 {
1637  if (xmin >= xmax) {
1638  xmin = fXmin;
1639  xmax = fXmax;
1640  }
1641 
1642  if (!logx && gPad != 0) logx = gPad->GetLogx();
1643 
1644  ROOT::Math::BrentMinimizer1D bm;
1645  GInverseFunc g(this);
1646  ROOT::Math::WrappedFunction<GInverseFunc> wf1(g);
1647  bm.SetFunction(wf1, xmin, xmax);
1648  bm.SetNpx(fNpx);
1649  bm.SetLogScan(logx);
1650  bm.Minimize(maxiter, epsilon, epsilon);
1651  Double_t x;
1652  x = bm.XMinimum();
1653 
1654  return x;
1655 }
1656 
1657 
1658 ////////////////////////////////////////////////////////////////////////////////
1659 /// Returns the minimum value of the function on the (xmin, xmax) interval
1660 ///
1661 /// Method:
1662 /// First, the grid search is used to bracket the maximum
1663 /// with the step size = (xmax-xmin)/fNpx. This way, the step size
1664 /// can be controlled via the SetNpx() function. If the function is
1665 /// unimodal or if its extrema are far apart, setting the fNpx to
1666 /// a small value speeds the algorithm up many times.
1667 /// Then, Brent's method is applied on the bracketed interval
1668 /// epsilon (default = 1.E-10) controls the relative accuracy (if |x| > 1 )
1669 /// and absolute (if |x| < 1) and maxiter (default = 100) controls the maximum number
1670 /// of iteration of the Brent algorithm
1671 /// If the flag logx is set the grid search is done in log step size
1672 /// This is done automatically if the log scale is set in the current Pad
1673 ///
1674 /// NOTE: see also TF1::GetMaximumX and TF1::GetX
1675 
1676 Double_t TF1::GetMinimum(Double_t xmin, Double_t xmax, Double_t epsilon, Int_t maxiter, Bool_t logx) const
1677 {
1678  if (xmin >= xmax) {
1679  xmin = fXmin;
1680  xmax = fXmax;
1681  }
1682 
1683  if (!logx && gPad != 0) logx = gPad->GetLogx();
1684 
1685  ROOT::Math::BrentMinimizer1D bm;
1686  ROOT::Math::WrappedFunction<const TF1 &> wf1(*this);
1687  bm.SetFunction(wf1, xmin, xmax);
1688  bm.SetNpx(fNpx);
1689  bm.SetLogScan(logx);
1690  bm.Minimize(maxiter, epsilon, epsilon);
1691  Double_t x;
1692  x = bm.FValMinimum();
1693 
1694  return x;
1695 }
1696 
1697 ////////////////////////////////////////////////////////////////////////////////
1698 /// Find the minimum of a function of whatever dimension.
1699 /// While GetMinimum works only for 1D function , GetMinimumNDim works for all dimensions
1700 /// since it uses the minimizer interface
1701 /// vector x at beginning will contained the initial point, on exit will contain the result
1702 
1703 Double_t TF1::GetMinMaxNDim(Double_t *x , bool findmax, Double_t epsilon, Int_t maxiter) const
1704 {
1705  R__ASSERT(x != 0);
1706 
1707  int ndim = GetNdim();
1708  if (ndim == 0) {
1709  Error("GetMinimumNDim", "Function of dimension 0 - return Eval(x)");
1710  return (const_cast<TF1 &>(*this))(x);
1711  }
1712 
1713  // create minimizer class
1714  const char *minimName = ROOT::Math::MinimizerOptions::DefaultMinimizerType().c_str();
1715  const char *minimAlgo = ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo().c_str();
1716  ROOT::Math::Minimizer *min = ROOT::Math::Factory::CreateMinimizer(minimName, minimAlgo);
1717 
1718  if (min == 0) {
1719  Error("GetMinimumNDim", "Error creating minimizer %s", minimName);
1720  return 0;
1721  }
1722 
1723  // minimizer will be set using default values
1724  if (epsilon > 0) min->SetTolerance(epsilon);
1725  if (maxiter > 0) min->SetMaxFunctionCalls(maxiter);
1726 
1727  // create wrapper class from TF1 (cannot use Functor, t.b.i.)
1728  ROOT::Math::WrappedMultiFunction<TF1 &> objFunc(const_cast<TF1 &>(*this), ndim);
1729  // create -f(x) when searching for the maximum
1730  GInverseFuncNdim invFunc(const_cast<TF1 *>(this));
1731  ROOT::Math::WrappedMultiFunction<GInverseFuncNdim &> objFuncInv(invFunc, ndim);
1732  if (!findmax)
1733  min->SetFunction(objFunc);
1734  else
1735  min->SetFunction(objFuncInv);
1736 
1737  std::vector<double> rmin(ndim);
1738  std::vector<double> rmax(ndim);
1739  GetRange(&rmin[0], &rmax[0]);
1740  for (int i = 0; i < ndim; ++i) {
1741  const char *xname = 0;
1742  double stepSize = 0.1;
1743  // use range for step size or give some value depending on x if range is not defined
1744  if (rmax[i] > rmin[i])
1745  stepSize = (rmax[i] - rmin[i]) / 100;
1746  else if (std::abs(x[i]) > 1.)
1747  stepSize = 0.1 * x[i];
1748 
1749  // set variable names
1750  if (ndim <= 3) {
1751  if (i == 0) {
1752  xname = "x";
1753  } else if (i == 1) {
1754  xname = "y";
1755  } else {
1756  xname = "z";
1757  }
1758  } else {
1759  xname = TString::Format("x_%d", i);
1760  // arbitrary step sie (should be computed from range)
1761  }
1762 
1763  if (rmin[i] < rmax[i]) {
1764  //Info("GetMinMax","setting limits on %s - [ %f , %f ]",xname,rmin[i],rmax[i]);
1765  min->SetLimitedVariable(i, xname, x[i], stepSize, rmin[i], rmax[i]);
1766  } else {
1767  min->SetVariable(i, xname, x[i], stepSize);
1768  }
1769  }
1770 
1771  bool ret = min->Minimize();
1772  if (!ret) {
1773  Error("GetMinimumNDim", "Error minimizing function %s", GetName());
1774  }
1775  if (min->X()) std::copy(min->X(), min->X() + ndim, x);
1776  double fmin = min->MinValue();
1777  delete min;
1778  // need to revert sign in case looking for maximum
1779  return (findmax) ? -fmin : fmin;
1780 
1781 }
1782 
1783 
1784 ////////////////////////////////////////////////////////////////////////////////
1785 /// Returns the X value corresponding to the minimum value of the function
1786 /// on the (xmin, xmax) interval
1787 ///
1788 /// Method:
1789 /// First, the grid search is used to bracket the maximum
1790 /// with the step size = (xmax-xmin)/fNpx. This way, the step size
1791 /// can be controlled via the SetNpx() function. If the function is
1792 /// unimodal or if its extrema are far apart, setting the fNpx to
1793 /// a small value speeds the algorithm up many times.
1794 /// Then, Brent's method is applied on the bracketed interval
1795 /// epsilon (default = 1.E-10) controls the relative accuracy (if |x| > 1 )
1796 /// and absolute (if |x| < 1) and maxiter (default = 100) controls the maximum number
1797 /// of iteration of the Brent algorithm
1798 /// If the flag logx is set the grid search is done in log step size
1799 /// This is done automatically if the log scale is set in the current Pad
1800 ///
1801 /// NOTE: see also TF1::GetX
1802 
1803 Double_t TF1::GetMinimumX(Double_t xmin, Double_t xmax, Double_t epsilon, Int_t maxiter, Bool_t logx) const
1804 {
1805  if (xmin >= xmax) {
1806  xmin = fXmin;
1807  xmax = fXmax;
1808  }
1809 
1810  ROOT::Math::BrentMinimizer1D bm;
1811  ROOT::Math::WrappedFunction<const TF1 &> wf1(*this);
1812  bm.SetFunction(wf1, xmin, xmax);
1813  bm.SetNpx(fNpx);
1814  bm.SetLogScan(logx);
1815  bm.Minimize(maxiter, epsilon, epsilon);
1816  Double_t x;
1817  x = bm.XMinimum();
1818 
1819  return x;
1820 }
1821 
1822 
1823 ////////////////////////////////////////////////////////////////////////////////
1824 /// Returns the X value corresponding to the function value fy for (xmin<x<xmax).
1825 /// in other words it can find the roots of the function when fy=0 and successive calls
1826 /// by changing the next call to [xmin+eps,xmax] where xmin is the previous root.
1827 ///
1828 /// Method:
1829 /// First, the grid search is used to bracket the maximum
1830 /// with the step size = (xmax-xmin)/fNpx. This way, the step size
1831 /// can be controlled via the SetNpx() function. If the function is
1832 /// unimodal or if its extrema are far apart, setting the fNpx to
1833 /// a small value speeds the algorithm up many times.
1834 /// Then, Brent's method is applied on the bracketed interval
1835 /// epsilon (default = 1.E-10) controls the relative accuracy (if |x| > 1 )
1836 /// and absolute (if |x| < 1) and maxiter (default = 100) controls the maximum number
1837 /// of iteration of the Brent algorithm
1838 /// If the flag logx is set the grid search is done in log step size
1839 /// This is done automatically if the log scale is set in the current Pad
1840 ///
1841 /// NOTE: see also TF1::GetMaximumX, TF1::GetMinimumX
1842 
1843 Double_t TF1::GetX(Double_t fy, Double_t xmin, Double_t xmax, Double_t epsilon, Int_t maxiter, Bool_t logx) const
1844 {
1845  if (xmin >= xmax) {
1846  xmin = fXmin;
1847  xmax = fXmax;
1848  }
1849 
1850  if (!logx && gPad != 0) logx = gPad->GetLogx();
1851 
1852  GFunc g(this, fy);
1853  ROOT::Math::WrappedFunction<GFunc> wf1(g);
1854  ROOT::Math::BrentRootFinder brf;
1855  brf.SetFunction(wf1, xmin, xmax);
1856  brf.SetNpx(fNpx);
1857  brf.SetLogScan(logx);
1858  bool ret = brf.Solve(maxiter, epsilon, epsilon);
1859  if (!ret) Error("GetX","[%f,%f] is not a valid interval",xmin,xmax);
1860  return (ret) ? brf.Root() : TMath::QuietNaN();
1861 }
1862 
1863 ////////////////////////////////////////////////////////////////////////////////
1864 /// Return the number of degrees of freedom in the fit
1865 /// the fNDF parameter has been previously computed during a fit.
1866 /// The number of degrees of freedom corresponds to the number of points
1867 /// used in the fit minus the number of free parameters.
1868 
1869 Int_t TF1::GetNDF() const
1870 {
1871  Int_t npar = GetNpar();
1872  if (fNDF == 0 && (fNpfits > npar)) return fNpfits - npar;
1873  return fNDF;
1874 }
1875 
1876 
1877 ////////////////////////////////////////////////////////////////////////////////
1878 /// Return the number of free parameters
1879 
1880 Int_t TF1::GetNumberFreeParameters() const
1881 {
1882  Int_t ntot = GetNpar();
1883  Int_t nfree = ntot;
1884  Double_t al, bl;
1885  for (Int_t i = 0; i < ntot; i++) {
1886  ((TF1 *)this)->GetParLimits(i, al, bl);
1887  if (al * bl != 0 && al >= bl) nfree--;
1888  }
1889  return nfree;
1890 }
1891 
1892 
1893 ////////////////////////////////////////////////////////////////////////////////
1894 /// Redefines TObject::GetObjectInfo.
1895 /// Displays the function info (x, function value)
1896 /// corresponding to cursor position px,py
1897 
1898 char *TF1::GetObjectInfo(Int_t px, Int_t /* py */) const
1899 {
1900  static char info[64];
1901  Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
1902  snprintf(info, 64, "(x=%g, f=%g)", x, ((TF1 *)this)->Eval(x));
1903  return info;
1904 }
1905 
1906 
1907 ////////////////////////////////////////////////////////////////////////////////
1908 /// Return value of parameter number ipar
1909 
1910 Double_t TF1::GetParError(Int_t ipar) const
1911 {
1912  if (ipar < 0 || ipar > GetNpar() - 1) return 0;
1913  return fParErrors[ipar];
1914 }
1915 
1916 
1917 ////////////////////////////////////////////////////////////////////////////////
1918 /// Return limits for parameter ipar.
1919 
1920 void TF1::GetParLimits(Int_t ipar, Double_t &parmin, Double_t &parmax) const
1921 {
1922  parmin = 0;
1923  parmax = 0;
1924  int n = fParMin.size();
1925  assert(n == int(fParMax.size()) && n <= fNpar);
1926  if (ipar < 0 || ipar > n - 1) return;
1927  parmin = fParMin[ipar];
1928  parmax = fParMax[ipar];
1929 }
1930 
1931 
1932 ////////////////////////////////////////////////////////////////////////////////
1933 /// Return the fit probability
1934 
1935 Double_t TF1::GetProb() const
1936 {
1937  if (fNDF <= 0) return 0;
1938  return TMath::Prob(fChisquare, fNDF);
1939 }
1940 
1941 
1942 ////////////////////////////////////////////////////////////////////////////////
1943 /// Compute Quantiles for density distribution of this function
1944 ///
1945 /// Quantile x_q of a probability distribution Function F is defined as
1946 /// \f[
1947 /// F(x_{q}) = \int_{xmin}^{x_{q}} f dx = q with 0 <= q <= 1.
1948 /// \f]
1949 /// For instance the median \f$ x_{\frac{1}{2}} \f$ of a distribution is defined as that value
1950 /// of the random variable for which the distribution function equals 0.5:
1951 /// \f[
1952 /// F(x_{\frac{1}{2}}) = \prod(x < x_{\frac{1}{2}}) = \frac{1}{2}
1953 /// \f]
1954 ///
1955 /// \param[in] this TF1 function
1956 /// \param[in] nprobSum maximum size of array q and size of array probSum
1957 /// \param[in] probSum array of positions where quantiles will be computed.
1958 /// It is assumed to contain at least nprobSum values.
1959 /// \param[out] return value nq (<=nprobSum) with the number of quantiles computed
1960 /// \param[out] array q filled with nq quantiles
1961 ///
1962 /// Getting quantiles from two histograms and storing results in a TGraph,
1963 /// a so-called QQ-plot
1964 ///
1965 /// TGraph *gr = new TGraph(nprob);
1966 /// f1->GetQuantiles(nprob,gr->GetX());
1967 /// f2->GetQuantiles(nprob,gr->GetY());
1968 /// gr->Draw("alp");
1969 ///
1970 /// \author Eddy Offermann
1971 
1972 
1973 Int_t TF1::GetQuantiles(Int_t nprobSum, Double_t *q, const Double_t *probSum)
1974 {
1975  // LM: change to use fNpx
1976  // should we change code to use a root finder ?
1977  // It should be more precise and more efficient
1978  const Int_t npx = TMath::Max(fNpx, 2 * nprobSum);
1979  const Double_t xMin = GetXmin();
1980  const Double_t xMax = GetXmax();
1981  const Double_t dx = (xMax - xMin) / npx;
1982 
1983  TArrayD integral(npx + 1);
1984  TArrayD alpha(npx);
1985  TArrayD beta(npx);
1986  TArrayD gamma(npx);
1987 
1988  integral[0] = 0;
1989  Int_t intNegative = 0;
1990  Int_t i;
1991  for (i = 0; i < npx; i++) {
1992  Double_t integ = Integral(Double_t(xMin + i * dx), Double_t(xMin + i * dx + dx), 0.0);
1993  if (integ < 0) {
1994  intNegative++;
1995  integ = -integ;
1996  }
1997  integral[i + 1] = integral[i] + integ;
1998  }
1999 
2000  if (intNegative > 0)
2001  Warning("GetQuantiles", "function:%s has %d negative values: abs assumed",
2002  GetName(), intNegative);
2003  if (integral[npx] == 0) {
2004  Error("GetQuantiles", "Integral of function is zero");
2005  return 0;
2006  }
2007 
2008  const Double_t total = integral[npx];
2009  for (i = 1; i <= npx; i++) integral[i] /= total;
2010  //the integral r for each bin is approximated by a parabola
2011  // x = alpha + beta*r +gamma*r**2
2012  // compute the coefficients alpha, beta, gamma for each bin
2013  for (i = 0; i < npx; i++) {
2014  const Double_t x0 = xMin + dx * i;
2015  const Double_t r2 = integral[i + 1] - integral[i];
2016  const Double_t r1 = Integral(x0, x0 + 0.5 * dx, 0.0) / total;
2017  gamma[i] = (2 * r2 - 4 * r1) / (dx * dx);
2018  beta[i] = r2 / dx - gamma[i] * dx;
2019  alpha[i] = x0;
2020  gamma[i] *= 2;
2021  }
2022 
2023  // Be careful because of finite precision in the integral; Use the fact that the integral
2024  // is monotone increasing
2025  for (i = 0; i < nprobSum; i++) {
2026  const Double_t r = probSum[i];
2027  Int_t bin = TMath::Max(TMath::BinarySearch(npx + 1, integral.GetArray(), r), (Long64_t)0);
2028  // in case the prob is 1
2029  if (bin == npx) {
2030  q[i] = xMax;
2031  continue;
2032  }
2033  // LM use a tolerance 1.E-12 (integral precision)
2034  while (bin < npx - 1 && TMath::AreEqualRel(integral[bin + 1], r, 1E-12)) {
2035  if (TMath::AreEqualRel(integral[bin + 2], r, 1E-12)) bin++;
2036  else break;
2037  }
2038 
2039  const Double_t rr = r - integral[bin];
2040  if (rr != 0.0) {
2041  Double_t xx = 0.0;
2042  const Double_t fac = -2.*gamma[bin] * rr / beta[bin] / beta[bin];
2043  if (fac != 0 && fac <= 1)
2044  xx = (-beta[bin] + TMath::Sqrt(beta[bin] * beta[bin] + 2 * gamma[bin] * rr)) / gamma[bin];
2045  else if (beta[bin] != 0.)
2046  xx = rr / beta[bin];
2047  q[i] = alpha[bin] + xx;
2048  } else {
2049  q[i] = alpha[bin];
2050  if (integral[bin + 1] == r) q[i] += dx;
2051  }
2052  }
2053 
2054  return nprobSum;
2055 }
2056 
2057 
2058 ////////////////////////////////////////////////////////////////////////////////
2059 /// Return a random number following this function shape
2060 ///
2061 /// The distribution contained in the function fname (TF1) is integrated
2062 /// over the channel contents.
2063 /// It is normalized to 1.
2064 /// For each bin the integral is approximated by a parabola.
2065 /// The parabola coefficients are stored as non persistent data members
2066 /// Getting one random number implies:
2067 /// - Generating a random number between 0 and 1 (say r1)
2068 /// - Look in which bin in the normalized integral r1 corresponds to
2069 /// - Evaluate the parabolic curve in the selected bin to find the corresponding X value.
2070 ///
2071 /// If the ratio fXmax/fXmin > fNpx the integral is tabulated in log scale in x
2072 /// The parabolic approximation is very good as soon as the number of bins is greater than 50.
2073 
2074 Double_t TF1::GetRandom()
2075 {
2076  // Check if integral array must be build
2077  if (fIntegral.size() == 0) {
2078  fIntegral.resize(fNpx + 1);
2079  fAlpha.resize(fNpx + 1);
2080  fBeta.resize(fNpx);
2081  fGamma.resize(fNpx);
2082  fIntegral[0] = 0;
2083  fAlpha[fNpx] = 0;
2084  Double_t integ;
2085  Int_t intNegative = 0;
2086  Int_t i;
2087  Bool_t logbin = kFALSE;
2088  Double_t dx;
2089  Double_t xmin = fXmin;
2090  Double_t xmax = fXmax;
2091  if (xmin > 0 && xmax / xmin > fNpx) {
2092  logbin = kTRUE;
2093  fAlpha[fNpx] = 1;
2094  xmin = TMath::Log10(fXmin);
2095  xmax = TMath::Log10(fXmax);
2096  }
2097  dx = (xmax - xmin) / fNpx;
2098 
2099  Double_t *xx = new Double_t[fNpx + 1];
2100  for (i = 0; i < fNpx; i++) {
2101  xx[i] = xmin + i * dx;
2102  }
2103  xx[fNpx] = xmax;
2104  for (i = 0; i < fNpx; i++) {
2105  if (logbin) {
2106  integ = Integral(TMath::Power(10, xx[i]), TMath::Power(10, xx[i + 1]), 0.0);
2107  } else {
2108  integ = Integral(xx[i], xx[i + 1], 0.0);
2109  }
2110  if (integ < 0) {
2111  intNegative++;
2112  integ = -integ;
2113  }
2114  fIntegral[i + 1] = fIntegral[i] + integ;
2115  }
2116  if (intNegative > 0) {
2117  Warning("GetRandom", "function:%s has %d negative values: abs assumed", GetName(), intNegative);
2118  }
2119  if (fIntegral[fNpx] == 0) {
2120  delete [] xx;
2121  Error("GetRandom", "Integral of function is zero");
2122  return 0;
2123  }
2124  Double_t total = fIntegral[fNpx];
2125  for (i = 1; i <= fNpx; i++) { // normalize integral to 1
2126  fIntegral[i] /= total;
2127  }
2128  //the integral r for each bin is approximated by a parabola
2129  // x = alpha + beta*r +gamma*r**2
2130  // compute the coefficients alpha, beta, gamma for each bin
2131  Double_t x0, r1, r2, r3;
2132  for (i = 0; i < fNpx; i++) {
2133  x0 = xx[i];
2134  r2 = fIntegral[i + 1] - fIntegral[i];
2135  if (logbin) r1 = Integral(TMath::Power(10, x0), TMath::Power(10, x0 + 0.5 * dx), 0.0) / total;
2136  else r1 = Integral(x0, x0 + 0.5 * dx, 0.0) / total;
2137  r3 = 2 * r2 - 4 * r1;
2138  if (TMath::Abs(r3) > 1e-8) fGamma[i] = r3 / (dx * dx);
2139  else fGamma[i] = 0;
2140  fBeta[i] = r2 / dx - fGamma[i] * dx;
2141  fAlpha[i] = x0;
2142  fGamma[i] *= 2;
2143  }
2144  delete [] xx;
2145  }
2146 
2147  // return random number
2148  Double_t r = gRandom->Rndm();
2149  Int_t bin = TMath::BinarySearch(fNpx, fIntegral.data(), r);
2150  Double_t rr = r - fIntegral[bin];
2151 
2152  Double_t yy;
2153  if (fGamma[bin] != 0)
2154  yy = (-fBeta[bin] + TMath::Sqrt(fBeta[bin] * fBeta[bin] + 2 * fGamma[bin] * rr)) / fGamma[bin];
2155  else
2156  yy = rr / fBeta[bin];
2157  Double_t x = fAlpha[bin] + yy;
2158  if (fAlpha[fNpx] > 0) return TMath::Power(10, x);
2159  return x;
2160 }
2161 
2162 
2163 ////////////////////////////////////////////////////////////////////////////////
2164 /// Return a random number following this function shape in [xmin,xmax]
2165 ///
2166 /// The distribution contained in the function fname (TF1) is integrated
2167 /// over the channel contents.
2168 /// It is normalized to 1.
2169 /// For each bin the integral is approximated by a parabola.
2170 /// The parabola coefficients are stored as non persistent data members
2171 /// Getting one random number implies:
2172 /// - Generating a random number between 0 and 1 (say r1)
2173 /// - Look in which bin in the normalized integral r1 corresponds to
2174 /// - Evaluate the parabolic curve in the selected bin to find
2175 /// the corresponding X value.
2176 ///
2177 /// The parabolic approximation is very good as soon as the number
2178 /// of bins is greater than 50.
2179 ///
2180 /// IMPORTANT NOTE
2181 ///
2182 /// The integral of the function is computed at fNpx points. If the function
2183 /// has sharp peaks, you should increase the number of points (SetNpx)
2184 /// such that the peak is correctly tabulated at several points.
2185 
2186 Double_t TF1::GetRandom(Double_t xmin, Double_t xmax)
2187 {
2188  // Check if integral array must be build
2189  if (fIntegral.size() == 0) {
2190  fIntegral.resize(fNpx + 1);
2191  fAlpha.resize(fNpx+1);
2192  fBeta.resize(fNpx);
2193  fGamma.resize(fNpx);
2194 
2195  Double_t dx = (fXmax - fXmin) / fNpx;
2196  Double_t integ;
2197  Int_t intNegative = 0;
2198  Int_t i;
2199  for (i = 0; i < fNpx; i++) {
2200  integ = Integral(Double_t(fXmin + i * dx), Double_t(fXmin + i * dx + dx), 0.0);
2201  if (integ < 0) {
2202  intNegative++;
2203  integ = -integ;
2204  }
2205  fIntegral[i + 1] = fIntegral[i] + integ;
2206  }
2207  if (intNegative > 0) {
2208  Warning("GetRandom", "function:%s has %d negative values: abs assumed", GetName(), intNegative);
2209  }
2210  if (fIntegral[fNpx] == 0) {
2211  Error("GetRandom", "Integral of function is zero");
2212  return 0;
2213  }
2214  Double_t total = fIntegral[fNpx];
2215  for (i = 1; i <= fNpx; i++) { // normalize integral to 1
2216  fIntegral[i] /= total;
2217  }
2218  //the integral r for each bin is approximated by a parabola
2219  // x = alpha + beta*r +gamma*r**2
2220  // compute the coefficients alpha, beta, gamma for each bin
2221  Double_t x0, r1, r2, r3;
2222  for (i = 0; i < fNpx; i++) {
2223  x0 = fXmin + i * dx;
2224  r2 = fIntegral[i + 1] - fIntegral[i];
2225  r1 = Integral(x0, x0 + 0.5 * dx, 0.0) / total;
2226  r3 = 2 * r2 - 4 * r1;
2227  if (TMath::Abs(r3) > 1e-8) fGamma[i] = r3 / (dx * dx);
2228  else fGamma[i] = 0;
2229  fBeta[i] = r2 / dx - fGamma[i] * dx;
2230  fAlpha[i] = x0;
2231  fGamma[i] *= 2;
2232  }
2233  }
2234 
2235  // return random number
2236  Double_t dx = (fXmax - fXmin) / fNpx;
2237  Int_t nbinmin = (Int_t)((xmin - fXmin) / dx);
2238  Int_t nbinmax = (Int_t)((xmax - fXmin) / dx) + 2;
2239  if (nbinmax > fNpx) nbinmax = fNpx;
2240 
2241  Double_t pmin = fIntegral[nbinmin];
2242  Double_t pmax = fIntegral[nbinmax];
2243 
2244  Double_t r, x, xx, rr;
2245  do {
2246  r = gRandom->Uniform(pmin, pmax);
2247 
2248  Int_t bin = TMath::BinarySearch(fNpx, fIntegral.data(), r);
2249  rr = r - fIntegral[bin];
2250 
2251  if (fGamma[bin] != 0)
2252  xx = (-fBeta[bin] + TMath::Sqrt(fBeta[bin] * fBeta[bin] + 2 * fGamma[bin] * rr)) / fGamma[bin];
2253  else
2254  xx = rr / fBeta[bin];
2255  x = fAlpha[bin] + xx;
2256  } while (x < xmin || x > xmax);
2257  return x;
2258 }
2259 
2260 ////////////////////////////////////////////////////////////////////////////////
2261 /// Return range of a generic N-D function.
2262 
2263 void TF1::GetRange(Double_t *rmin, Double_t *rmax) const
2264 {
2265  int ndim = GetNdim();
2266 
2267  double xmin = 0, ymin = 0, zmin = 0, xmax = 0, ymax = 0, zmax = 0;
2268  GetRange(xmin, ymin, zmin, xmax, ymax, zmax);
2269  for (int i = 0; i < ndim; ++i) {
2270  if (i == 0) {
2271  rmin[0] = xmin;
2272  rmax[0] = xmax;
2273  } else if (i == 1) {
2274  rmin[1] = ymin;
2275  rmax[1] = ymax;
2276  } else if (i == 2) {
2277  rmin[2] = zmin;
2278  rmax[2] = zmax;
2279  } else {
2280  rmin[i] = 0;
2281  rmax[i] = 0;
2282  }
2283  }
2284 }
2285 
2286 
2287 ////////////////////////////////////////////////////////////////////////////////
2288 /// Return range of a 1-D function.
2289 
2290 void TF1::GetRange(Double_t &xmin, Double_t &xmax) const
2291 {
2292  xmin = fXmin;
2293  xmax = fXmax;
2294 }
2295 
2296 
2297 ////////////////////////////////////////////////////////////////////////////////
2298 /// Return range of a 2-D function.
2299 
2300 void TF1::GetRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const
2301 {
2302  xmin = fXmin;
2303  xmax = fXmax;
2304  ymin = 0;
2305  ymax = 0;
2306 }
2307 
2308 
2309 ////////////////////////////////////////////////////////////////////////////////
2310 /// Return range of function.
2311 
2312 void TF1::GetRange(Double_t &xmin, Double_t &ymin, Double_t &zmin, Double_t &xmax, Double_t &ymax, Double_t &zmax) const
2313 {
2314  xmin = fXmin;
2315  xmax = fXmax;
2316  ymin = 0;
2317  ymax = 0;
2318  zmin = 0;
2319  zmax = 0;
2320 }
2321 
2322 
2323 ////////////////////////////////////////////////////////////////////////////////
2324 /// Get value corresponding to X in array of fSave values
2325 
2326 Double_t TF1::GetSave(const Double_t *xx)
2327 {
2328  if (fSave.size() == 0) return 0;
2329  //if (fSave == 0) return 0;
2330  int fNsave = fSave.size();
2331  Double_t x = Double_t(xx[0]);
2332  Double_t y, dx, xmin, xmax, xlow, xup, ylow, yup;
2333  if (fParent && fParent->InheritsFrom(TH1::Class())) {
2334  //if parent is a histogram the function had been saved at the center of the bins
2335  //we make a linear interpolation between the saved values
2336  xmin = fSave[fNsave - 3];
2337  xmax = fSave[fNsave - 2];
2338  if (fSave[fNsave - 1] == xmax) {
2339  TH1 *h = (TH1 *)fParent;
2340  TAxis *xaxis = h->GetXaxis();
2341  Int_t bin1 = xaxis->FindBin(xmin);
2342  Int_t binup = xaxis->FindBin(xmax);
2343  Int_t bin = xaxis->FindBin(x);
2344  if (bin < binup) {
2345  xlow = xaxis->GetBinCenter(bin);
2346  xup = xaxis->GetBinCenter(bin + 1);
2347  ylow = fSave[bin - bin1];
2348  yup = fSave[bin - bin1 + 1];
2349  } else {
2350  xlow = xaxis->GetBinCenter(bin - 1);
2351  xup = xaxis->GetBinCenter(bin);
2352  ylow = fSave[bin - bin1 - 1];
2353  yup = fSave[bin - bin1];
2354  }
2355  dx = xup - xlow;
2356  y = ((xup * ylow - xlow * yup) + x * (yup - ylow)) / dx;
2357  return y;
2358  }
2359  }
2360  Int_t np = fNsave - 3;
2361  xmin = Double_t(fSave[np + 1]);
2362  xmax = Double_t(fSave[np + 2]);
2363  dx = (xmax - xmin) / np;
2364  if (x < xmin || x > xmax) return 0;
2365  // return a Nan in case of x=nan, otherwise will crash later
2366  if (TMath::IsNaN(x)) return x;
2367  if (dx <= 0) return 0;
2368 
2369  Int_t bin = Int_t((x - xmin) / dx);
2370  xlow = xmin + bin * dx;
2371  xup = xlow + dx;
2372  ylow = fSave[bin];
2373  yup = fSave[bin + 1];
2374  y = ((xup * ylow - xlow * yup) + x * (yup - ylow)) / dx;
2375  return y;
2376 }
2377 
2378 
2379 ////////////////////////////////////////////////////////////////////////////////
2380 /// Get x axis of the function.
2381 
2382 TAxis *TF1::GetXaxis() const
2383 {
2384  TH1 *h = GetHistogram();
2385  if (!h) return 0;
2386  return h->GetXaxis();
2387 }
2388 
2389 
2390 ////////////////////////////////////////////////////////////////////////////////
2391 /// Get y axis of the function.
2392 
2393 TAxis *TF1::GetYaxis() const
2394 {
2395  TH1 *h = GetHistogram();
2396  if (!h) return 0;
2397  return h->GetYaxis();
2398 }
2399 
2400 
2401 ////////////////////////////////////////////////////////////////////////////////
2402 /// Get z axis of the function. (In case this object is a TF2 or TF3)
2403 
2404 TAxis *TF1::GetZaxis() const
2405 {
2406  TH1 *h = GetHistogram();
2407  if (!h) return 0;
2408  return h->GetZaxis();
2409 }
2410 
2411 
2412 
2413 ////////////////////////////////////////////////////////////////////////////////
2414 /// Compute the gradient (derivative) wrt a parameter ipar
2415 ///
2416 /// \param ipar index of parameter for which the derivative is computed
2417 /// \param x point, where the derivative is computed
2418 /// \param eps - if the errors of parameters have been computed, the step used in
2419 /// numerical differentiation is eps*parameter_error.
2420 ///
2421 /// if the errors have not been computed, step=eps is used
2422 /// default value of eps = 0.01
2423 /// Method is the same as in Derivative() function
2424 ///
2425 /// If a parameter is fixed, the gradient on this parameter = 0
2426 
2427 Double_t TF1::GradientPar(Int_t ipar, const Double_t *x, Double_t eps)
2428 {
2429  return GradientParTempl<Double_t>(ipar, x, eps);
2430 }
2431 
2432 ////////////////////////////////////////////////////////////////////////////////
2433 /// Compute the gradient wrt parameters
2434 ///
2435 /// \param x point, were the gradient is computed
2436 /// \param grad used to return the computed gradient, assumed to be of at least fNpar size
2437 /// \param eps if the errors of parameters have been computed, the step used in
2438 /// numerical differentiation is eps*parameter_error.
2439 ///
2440 /// if the errors have not been computed, step=eps is used
2441 /// default value of eps = 0.01
2442 /// Method is the same as in Derivative() function
2443 ///
2444 /// If a parameter is fixed, the gradient on this parameter = 0
2445 
2446 void TF1::GradientPar(const Double_t *x, Double_t *grad, Double_t eps)
2447 {
2448  GradientParTempl<Double_t>(x, grad, eps);
2449 }
2450 
2451 ////////////////////////////////////////////////////////////////////////////////
2452 /// Initialize parameters addresses.
2453 
2454 void TF1::InitArgs(const Double_t *x, const Double_t *params)
2455 {
2456  if (fMethodCall) {
2457  Long_t args[2];
2458  args[0] = (Long_t)x;
2459  if (params) args[1] = (Long_t)params;
2460  else args[1] = (Long_t)GetParameters();
2461  fMethodCall->SetParamPtrs(args);
2462  }
2463 }
2464 
2465 
2466 ////////////////////////////////////////////////////////////////////////////////
2467 /// Create the basic function objects
2468 
2469 void TF1::InitStandardFunctions()
2470 {
2471  TF1 *f1;
2472  R__LOCKGUARD(gROOTMutex);
2473  if (!gROOT->GetListOfFunctions()->FindObject("gaus")) {
2474  f1 = new TF1("gaus", "gaus", -1, 1);
2475  f1->SetParameters(1, 0, 1);
2476  f1 = new TF1("gausn", "gausn", -1, 1);
2477  f1->SetParameters(1, 0, 1);
2478  f1 = new TF1("landau", "landau", -1, 1);
2479  f1->SetParameters(1, 0, 1);
2480  f1 = new TF1("landaun", "landaun", -1, 1);
2481  f1->SetParameters(1, 0, 1);
2482  f1 = new TF1("expo", "expo", -1, 1);
2483  f1->SetParameters(1, 1);
2484  for (Int_t i = 0; i < 10; i++) {
2485  f1 = new TF1(Form("pol%d", i), Form("pol%d", i), -1, 1);
2486  f1->SetParameters(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
2487  // create also chebyshev polynomial
2488  // (note polynomial object will not be deleted)
2489  // note that these functions cannot be stored
2490  ROOT::Math::ChebyshevPol *pol = new ROOT::Math::ChebyshevPol(i);
2491  Double_t min = -1;
2492  Double_t max = 1;
2493  f1 = new TF1(TString::Format("chebyshev%d", i), pol, min, max, i + 1, 1);
2494  f1->SetParameters(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
2495  }
2496 
2497  }
2498 }
2499 ////////////////////////////////////////////////////////////////////////////////
2500 /// IntegralOneDim or analytical integral
2501 
2502 Double_t TF1::Integral(Double_t a, Double_t b, Double_t epsrel)
2503 {
2504  Double_t error = 0;
2505  if (GetNumber() > 0) {
2506  Double_t result = 0.;
2507  if (gDebug) {
2508  Info("computing analytical integral for function %s with number %d", GetName(), GetNumber());
2509  }
2510  result = AnalyticalIntegral(this, a, b);
2511  // if it is a formula that havent been implemented in analytical integral a NaN is return
2512  if (!TMath::IsNaN(result)) return result;
2513  if (gDebug)
2514  Warning("analytical integral not available for %s - with number %d compute numerical integral", GetName(), GetNumber());
2515  }
2516  return IntegralOneDim(a, b, epsrel, epsrel, error);
2517 }
2518 
2519 ////////////////////////////////////////////////////////////////////////////////
2520 /// Return Integral of function between a and b using the given parameter values and
2521 /// relative and absolute tolerance.
2522 ///
2523 /// The default integrator defined in ROOT::Math::IntegratorOneDimOptions::DefaultIntegrator() is used
2524 /// If ROOT contains the MathMore library the default integrator is set to be
2525 /// the adaptive ROOT::Math::GSLIntegrator (based on QUADPACK) or otherwise the
2526 /// ROOT::Math::GaussIntegrator is used
2527 /// See the reference documentation of these classes for more information about the
2528 /// integration algorithms
2529 /// To change integration algorithm just do :
2530 /// ROOT::Math::IntegratorOneDimOptions::SetDefaultIntegrator(IntegratorName);
2531 /// Valid integrator names are:
2532 /// - Gauss : for ROOT::Math::GaussIntegrator
2533 /// - GaussLegendre : for ROOT::Math::GaussLegendreIntegrator
2534 /// - Adaptive : for ROOT::Math::GSLIntegrator adaptive method (QAG)
2535 /// - AdaptiveSingular : for ROOT::Math::GSLIntegrator adaptive singular method (QAGS)
2536 /// - NonAdaptive : for ROOT::Math::GSLIntegrator non adaptive (QNG)
2537 ///
2538 /// In order to use the GSL integrators one needs to have the MathMore library installed
2539 ///
2540 /// Note 1:
2541 ///
2542 /// Values of the function f(x) at the interval end-points A and B are not
2543 /// required. The subprogram may therefore be used when these values are
2544 /// undefined.
2545 ///
2546 /// Note 2:
2547 ///
2548 /// Instead of TF1::Integral, you may want to use the combination of
2549 /// TF1::CalcGaussLegendreSamplingPoints and TF1::IntegralFast.
2550 /// See an example with the following script:
2551 ///
2552 /// ~~~ {.cpp}
2553 /// void gint() {
2554 /// TF1 *g = new TF1("g","gaus",-5,5);
2555 /// g->SetParameters(1,0,1);
2556 /// //default gaus integration method uses 6 points
2557 /// //not suitable to integrate on a large domain
2558 /// double r1 = g->Integral(0,5);
2559 /// double r2 = g->Integral(0,1000);
2560 ///
2561 /// //try with user directives computing more points
2562 /// Int_t np = 1000;
2563 /// double *x=new double[np];
2564 /// double *w=new double[np];
2565 /// g->CalcGaussLegendreSamplingPoints(np,x,w,1e-15);
2566 /// double r3 = g->IntegralFast(np,x,w,0,5);
2567 /// double r4 = g->IntegralFast(np,x,w,0,1000);
2568 /// double r5 = g->IntegralFast(np,x,w,0,10000);
2569 /// double r6 = g->IntegralFast(np,x,w,0,100000);
2570 /// printf("g->Integral(0,5) = %g\n",r1);
2571 /// printf("g->Integral(0,1000) = %g\n",r2);
2572 /// printf("g->IntegralFast(n,x,w,0,5) = %g\n",r3);
2573 /// printf("g->IntegralFast(n,x,w,0,1000) = %g\n",r4);
2574 /// printf("g->IntegralFast(n,x,w,0,10000) = %g\n",r5);
2575 /// printf("g->IntegralFast(n,x,w,0,100000)= %g\n",r6);
2576 /// delete [] x;
2577 /// delete [] w;
2578 /// }
2579 /// ~~~
2580 ///
2581 /// This example produces the following results:
2582 ///
2583 /// ~~~ {.cpp}
2584 /// g->Integral(0,5) = 1.25331
2585 /// g->Integral(0,1000) = 1.25319
2586 /// g->IntegralFast(n,x,w,0,5) = 1.25331
2587 /// g->IntegralFast(n,x,w,0,1000) = 1.25331
2588 /// g->IntegralFast(n,x,w,0,10000) = 1.25331
2589 /// g->IntegralFast(n,x,w,0,100000)= 1.253
2590 /// ~~~
2591 
2592 Double_t TF1::IntegralOneDim(Double_t a, Double_t b, Double_t epsrel, Double_t epsabs, Double_t &error)
2593 {
2594  //Double_t *parameters = GetParameters();
2595  TF1_EvalWrapper wf1(this, 0, fgAbsValue);
2596  Double_t result = 0;
2597  Int_t status = 0;
2598  if (epsrel <= 0) epsrel = ROOT::Math::IntegratorOneDimOptions::DefaultRelTolerance();
2599  if (epsabs <= 0) epsabs = ROOT::Math::IntegratorOneDimOptions::DefaultAbsTolerance();
2600  if (ROOT::Math::IntegratorOneDimOptions::DefaultIntegratorType() == ROOT::Math::IntegrationOneDim::kGAUSS) {
2601  ROOT::Math::GaussIntegrator iod(epsabs, epsrel);
2602  iod.SetFunction(wf1);
2603  if (a != - TMath::Infinity() && b != TMath::Infinity())
2604  result = iod.Integral(a, b);
2605  else if (a == - TMath::Infinity() && b != TMath::Infinity())
2606  result = iod.IntegralLow(b);
2607  else if (a != - TMath::Infinity() && b == TMath::Infinity())
2608  result = iod.IntegralUp(a);
2609  else if (a == - TMath::Infinity() && b == TMath::Infinity())
2610  result = iod.Integral();
2611  error = iod.Error();
2612  status = iod.Status();
2613  } else {
2614  ROOT::Math::IntegratorOneDim iod(wf1, ROOT::Math::IntegratorOneDimOptions::DefaultIntegratorType(), epsabs, epsrel);
2615  if (a != - TMath::Infinity() && b != TMath::Infinity())
2616  result = iod.Integral(a, b);
2617  else if (a == - TMath::Infinity() && b != TMath::Infinity())
2618  result = iod.IntegralLow(b);
2619  else if (a != - TMath::Infinity() && b == TMath::Infinity())
2620  result = iod.IntegralUp(a);
2621  else if (a == - TMath::Infinity() && b == TMath::Infinity())
2622  result = iod.Integral();
2623  error = iod.Error();
2624  status = iod.Status();
2625  }
2626  if (status != 0) {
2627  std::string igName = ROOT::Math::IntegratorOneDim::GetName(ROOT::Math::IntegratorOneDimOptions::DefaultIntegratorType());
2628  Warning("IntegralOneDim", "Error found in integrating function %s in [%f,%f] using %s. Result = %f +/- %f - status = %d", GetName(), a, b, igName.c_str(), result, error, status);
2629  TString msg("\t\tFunction Parameters = {");
2630  for (int ipar = 0; ipar < GetNpar(); ++ipar) {
2631  msg += TString::Format(" %s = %f ", GetParName(ipar), GetParameter(ipar));
2632  if (ipar < GetNpar() - 1) msg += TString(",");
2633  else msg += TString("}");
2634  }
2635  Info("IntegralOneDim", "%s", msg.Data());
2636  }
2637  return result;
2638 }
2639 
2640 
2641 //______________________________________________________________________________
2642 // Double_t TF1::Integral(Double_t, Double_t, Double_t, Double_t, Double_t, Double_t)
2643 // {
2644 // // Return Integral of a 2d function in range [ax,bx],[ay,by]
2645 
2646 // Error("Integral","Must be called with a TF2 only");
2647 // return 0;
2648 // }
2649 
2650 
2651 // //______________________________________________________________________________
2652 // Double_t TF1::Integral(Double_t, Double_t, Double_t, Double_t, Double_t, Double_t, Double_t, Double_t)
2653 // {
2654 // // Return Integral of a 3d function in range [ax,bx],[ay,by],[az,bz]
2655 
2656 // Error("Integral","Must be called with a TF3 only");
2657 // return 0;
2658 // }
2659 
2660 ////////////////////////////////////////////////////////////////////////////////
2661 /// Return Error on Integral of a parametric function between a and b
2662 /// due to the parameter uncertainties.
2663 /// A pointer to a vector of parameter values and to the elements of the covariance matrix (covmat)
2664 /// can be optionally passed. By default (i.e. when a zero pointer is passed) the current stored
2665 /// parameter values are used to estimate the integral error together with the covariance matrix
2666 /// from the last fit (retrieved from the global fitter instance)
2667 ///
2668 /// IMPORTANT NOTE1:
2669 ///
2670 /// When no covariance matrix is passed and in the meantime a fit is done
2671 /// using another function, the routine will signal an error and it will return zero only
2672 /// when the number of fit parameter is different than the values stored in TF1 (TF1::GetNpar() ).
2673 /// In the case that npar is the same, an incorrect result is returned.
2674 ///
2675 /// IMPORTANT NOTE2:
2676 ///
2677 /// The user must pass a pointer to the elements of the full covariance matrix
2678 /// dimensioned with the right size (npar*npar), where npar is the total number of parameters (TF1::GetNpar()),
2679 /// including also the fixed parameters. When there are fixed parameters, the pointer returned from
2680 /// TVirtualFitter::GetCovarianceMatrix() cannot be used.
2681 /// One should use the TFitResult class, as shown in the example below.
2682 ///
2683 /// To get the matrix and values from an old fit do for example:
2684 /// TFitResultPtr r = histo->Fit(func, "S");
2685 /// ..... after performing other fits on the same function do
2686 ///
2687 /// func->IntegralError(x1,x2,r->GetParams(), r->GetCovarianceMatrix()->GetMatrixArray() );
2688 
2689 Double_t TF1::IntegralError(Double_t a, Double_t b, const Double_t *params, const Double_t *covmat, Double_t epsilon)
2690 {
2691  Double_t x1[1];
2692  Double_t x2[1];
2693  x1[0] = a, x2[0] = b;
2694  return ROOT::TF1Helper::IntegralError(this, 1, x1, x2, params, covmat, epsilon);
2695 }
2696 
2697 ////////////////////////////////////////////////////////////////////////////////
2698 /// Return Error on Integral of a parametric function with dimension larger tan one
2699 /// between a[] and b[] due to the parameters uncertainties.
2700 /// For a TF1 with dimension larger than 1 (for example a TF2 or TF3)
2701 /// TF1::IntegralMultiple is used for the integral calculation
2702 ///
2703 /// A pointer to a vector of parameter values and to the elements of the covariance matrix (covmat) can be optionally passed.
2704 /// By default (i.e. when a zero pointer is passed) the current stored parameter values are used to estimate the integral error
2705 /// together with the covariance matrix from the last fit (retrieved from the global fitter instance).
2706 ///
2707 /// IMPORTANT NOTE1:
2708 ///
2709 /// When no covariance matrix is passed and in the meantime a fit is done
2710 /// using another function, the routine will signal an error and it will return zero only
2711 /// when the number of fit parameter is different than the values stored in TF1 (TF1::GetNpar() ).
2712 /// In the case that npar is the same, an incorrect result is returned.
2713 ///
2714 /// IMPORTANT NOTE2:
2715 ///
2716 /// The user must pass a pointer to the elements of the full covariance matrix
2717 /// dimensioned with the right size (npar*npar), where npar is the total number of parameters (TF1::GetNpar()),
2718 /// including also the fixed parameters. When there are fixed parameters, the pointer returned from
2719 /// TVirtualFitter::GetCovarianceMatrix() cannot be used.
2720 /// One should use the TFitResult class, as shown in the example below.
2721 ///
2722 /// To get the matrix and values from an old fit do for example:
2723 /// TFitResultPtr r = histo->Fit(func, "S");
2724 /// ..... after performing other fits on the same function do
2725 ///
2726 /// func->IntegralError(x1,x2,r->GetParams(), r->GetCovarianceMatrix()->GetMatrixArray() );
2727 
2728 Double_t TF1::IntegralError(Int_t n, const Double_t *a, const Double_t *b, const Double_t *params, const Double_t *covmat, Double_t epsilon)
2729 {
2730  return ROOT::TF1Helper::IntegralError(this, n, a, b, params, covmat, epsilon);
2731 }
2732 
2733 #ifdef INTHEFUTURE
2734 ////////////////////////////////////////////////////////////////////////////////
2735 /// Gauss-Legendre integral, see CalcGaussLegendreSamplingPoints
2736 
2737 Double_t TF1::IntegralFast(const TGraph *g, Double_t a, Double_t b, Double_t *params)
2738 {
2739  if (!g) return 0;
2740  return IntegralFast(g->GetN(), g->GetX(), g->GetY(), a, b, params);
2741 }
2742 #endif
2743 
2744 
2745 ////////////////////////////////////////////////////////////////////////////////
2746 /// Gauss-Legendre integral, see CalcGaussLegendreSamplingPoints
2747 
2748 Double_t TF1::IntegralFast(Int_t num, Double_t * /* x */, Double_t * /* w */, Double_t a, Double_t b, Double_t *params, Double_t epsilon)
2749 {
2750  // Now x and w are not used!
2751 
2752  ROOT::Math::WrappedTF1 wf1(*this);
2753  if (params)
2754  wf1.SetParameters(params);
2755  ROOT::Math::GaussLegendreIntegrator gli(num, epsilon);
2756  gli.SetFunction(wf1);
2757  return gli.Integral(a, b);
2758 
2759 }
2760 
2761 
2762 ////////////////////////////////////////////////////////////////////////////////
2763 /// See more general prototype below.
2764 /// This interface kept for back compatibility
2765 /// It is recommended to use the other interface where one can specify also epsabs and the maximum number of
2766 /// points
2767 
2768 Double_t TF1::IntegralMultiple(Int_t n, const Double_t *a, const Double_t *b, Double_t epsrel, Double_t &relerr)
2769 {
2770  Int_t nfnevl, ifail;
2771  UInt_t maxpts = TMath::Max(UInt_t(20 * TMath::Power(fNpx, GetNdim())), ROOT::Math::IntegratorMultiDimOptions::DefaultNCalls());
2772  Double_t result = IntegralMultiple(n, a, b, maxpts, epsrel, epsrel, relerr, nfnevl, ifail);
2773  if (ifail > 0) {
2774  Warning("IntegralMultiple", "failed code=%d, ", ifail);
2775  }
2776  return result;
2777 }
2778 
2779 
2780 ////////////////////////////////////////////////////////////////////////////////
2781 /// This function computes, to an attempted specified accuracy, the value of
2782 /// the integral
2783 ///
2784 /// \param[in] n Number of dimensions [2,15]
2785 /// \param[in] a,b One-dimensional arrays of length >= N . On entry A[i], and B[i],
2786 /// contain the lower and upper limits of integration, respectively.
2787 /// \param[in] maxpts Maximum number of function evaluations to be allowed.
2788 /// maxpts >= 2^n +2*n*(n+1) +1
2789 /// if maxpts<minpts, maxpts is set to 10*minpts
2790 /// \param[in] epsrel Specified relative accuracy.
2791 /// \param[in] epsabs Specified absolute accuracy.
2792 /// The integration algorithm will attempt to reach either the relative or the absolute accuracy.
2793 /// In case the maximum function called is reached the algorithm will stop earlier without having reached
2794 /// the desired accuracy
2795 ///
2796 /// \param[out] relerr Contains, on exit, an estimation of the relative accuracy of the result.
2797 /// \param[out] nfnevl number of function evaluations performed.
2798 /// \param[out] ifail
2799 /// \parblock
2800 /// 0 Normal exit. At least minpts and at most maxpts calls to the function were performed.
2801 ///
2802 /// 1 maxpts is too small for the specified accuracy eps. The result and relerr contain the values obtainable for the
2803 /// specified value of maxpts.
2804 ///
2805 /// 3 n<2 or n>15
2806 /// \endparblock
2807 ///
2808 /// Method:
2809 ///
2810 /// The default method used is the Genz-Mallik adaptive multidimensional algorithm
2811 /// using the class ROOT::Math::AdaptiveIntegratorMultiDim (see the reference documentation of the class)
2812 ///
2813 /// Other methods can be used by setting ROOT::Math::IntegratorMultiDimOptions::SetDefaultIntegrator()
2814 /// to different integrators.
2815 /// Other possible integrators are MC integrators based on the ROOT::Math::GSLMCIntegrator class
2816 /// Possible methods are : Vegas, Miser or Plain
2817 /// IN case of MC integration the accuracy is determined by the number of function calls, one should be
2818 /// careful not to use a too large value of maxpts
2819 ///
2820 
2821 Double_t TF1::IntegralMultiple(Int_t n, const Double_t *a, const Double_t *b, Int_t maxpts, Double_t epsrel, Double_t epsabs, Double_t &relerr, Int_t &nfnevl, Int_t &ifail)
2822 {
2823  ROOT::Math::WrappedMultiFunction<TF1 &> wf1(*this, n);
2824 
2825  double result = 0;
2826  if (epsrel <= 0) epsrel = ROOT::Math::IntegratorMultiDimOptions::DefaultRelTolerance();
2827  if (epsabs <= 0) epsabs = ROOT::Math::IntegratorMultiDimOptions::DefaultAbsTolerance();
2828  if (ROOT::Math::IntegratorMultiDimOptions::DefaultIntegratorType() == ROOT::Math::IntegrationMultiDim::kADAPTIVE) {
2829  ROOT::Math::AdaptiveIntegratorMultiDim aimd(wf1, epsabs, epsrel, maxpts);
2830  //aimd.SetMinPts(minpts); // use default minpts ( n^2 + 2 * n * (n+1) +1 )
2831  result = aimd.Integral(a, b);
2832  relerr = aimd.RelError();
2833  nfnevl = aimd.NEval();
2834  ifail = aimd.Status();
2835  } else {
2836  // use default abs tolerance = relative tolerance
2837  ROOT::Math::IntegratorMultiDim imd(wf1, ROOT::Math::IntegratorMultiDimOptions::DefaultIntegratorType(), epsabs, epsrel, maxpts);
2838  result = imd.Integral(a, b);
2839  relerr = (result != 0) ? imd.Error() / std::abs(result) : imd.Error();
2840  nfnevl = 0;
2841  ifail = imd.Status();
2842  }
2843 
2844 
2845  return result;
2846 }
2847 
2848 
2849 ////////////////////////////////////////////////////////////////////////////////
2850 /// Return kTRUE if the function is valid
2851 
2852 Bool_t TF1::IsValid() const
2853 {
2854  if (fFormula) return fFormula->IsValid();
2855  if (fMethodCall) return fMethodCall->IsValid();
2856  // function built on compiled functors are always valid by definition
2857  // (checked at compiled time)
2858  // invalid is a TF1 where the functor is null pointer and has not been saved
2859  if (!fFunctor && fSave.empty()) return kFALSE;
2860  return kTRUE;
2861 }
2862 
2863 
2864 //______________________________________________________________________________
2865 
2866 
2867 void TF1::Print(Option_t *option) const
2868 {
2869  if (fType == EFType::kFormula) {
2870  printf("Formula based function: %s \n", GetName());
2871  assert(fFormula);
2872  fFormula->Print(option);
2873  } else if (fType > 0) {
2874  if (fType == EFType::kInterpreted)
2875  printf("Interpreted based function: %s(double *x, double *p). Ndim = %d, Npar = %d \n", GetName(), GetNdim(),
2876  GetNpar());
2877  else if (fType == EFType::kCompositionFcn) {
2878  printf("Composition based function: %s. Ndim = %d, Npar = %d \n", GetName(), GetNdim(), GetNpar());
2879  if (!fComposition)
2880  printf("fComposition not found!\n"); // this would be bad
2881  } else {
2882  if (fFunctor)
2883  printf("Compiled based function: %s based on a functor object. Ndim = %d, Npar = %d\n", GetName(),
2884  GetNdim(), GetNpar());
2885  else {
2886  printf("Function based on a list of points from a compiled based function: %s. Ndim = %d, Npar = %d, Npx "
2887  "= %zu\n",
2888  GetName(), GetNdim(), GetNpar(), fSave.size());
2889  if (fSave.empty())
2890  Warning("Print", "Function %s is based on a list of points but list is empty", GetName());
2891  }
2892  }
2893  TString opt(option);
2894  opt.ToUpper();
2895  if (opt.Contains("V")) {
2896  // print list of parameters
2897  if (fNpar > 0) {
2898  printf("List of Parameters: \n");
2899  for (int i = 0; i < fNpar; ++i)
2900  printf(" %20s = %10f \n", GetParName(i), GetParameter(i));
2901  }
2902  if (!fSave.empty()) {
2903  // print list of saved points
2904  printf("List of Saved points (N=%d): \n", int(fSave.size()));
2905  for (auto &x : fSave)
2906  printf("( %10f ) ", x);
2907  printf("\n");
2908  }
2909  }
2910  }
2911  if (fHistogram) {
2912  printf("Contained histogram\n");
2913  fHistogram->Print(option);
2914  }
2915 }
2916 
2917 ////////////////////////////////////////////////////////////////////////////////
2918 /// Paint this function with its current attributes.
2919 /// The function is going to be converted in an histogram and the corresponding
2920 /// histogram is painted.
2921 /// The painted histogram can be retrieved calling afterwards the method TF1::GetHistogram()
2922 
2923 void TF1::Paint(Option_t *choptin)
2924 {
2925  fgCurrent = this;
2926 
2927  char option[32];
2928  strlcpy(option,choptin,32);
2929 
2930  TString opt = option;
2931  opt.ToLower();
2932 
2933  Bool_t optSAME = kFALSE;
2934  if (opt.Contains("same")) {
2935  opt.ReplaceAll("same","");
2936  optSAME = kTRUE;
2937  }
2938  opt.ReplaceAll(' ', "");
2939 
2940  Double_t xmin = fXmin, xmax = fXmax, pmin = fXmin, pmax = fXmax;
2941  if (gPad) {
2942  pmin = gPad->PadtoX(gPad->GetUxmin());
2943  pmax = gPad->PadtoX(gPad->GetUxmax());
2944  }
2945  if (optSAME) {
2946  if (xmax < pmin) return; // Completely outside.
2947  if (xmin > pmax) return;
2948  if (xmin < pmin) xmin = pmin;
2949  if (xmax > pmax) xmax = pmax;
2950  }
2951 
2952  // create an histogram using the function content (re-use it if already existing)
2953  fHistogram = DoCreateHistogram(xmin, xmax, kFALSE);
2954 
2955  char *l1 = strstr(option,"PFC"); // Automatic Fill Color
2956  char *l2 = strstr(option,"PLC"); // Automatic Line Color
2957  char *l3 = strstr(option,"PMC"); // Automatic Marker Color
2958  if (l1 || l2 || l3) {
2959  Int_t i = gPad->NextPaletteColor();
2960  if (l1) {memcpy(l1," ",3); fHistogram->SetFillColor(i);}
2961  if (l2) {memcpy(l2," ",3); fHistogram->SetLineColor(i);}
2962  if (l3) {memcpy(l3," ",3); fHistogram->SetMarkerColor(i);}
2963  }
2964 
2965  // set the optimal minimum and maximum
2966  Double_t minimum = fHistogram->GetMinimumStored();
2967  Double_t maximum = fHistogram->GetMaximumStored();
2968  if (minimum <= 0 && gPad && gPad->GetLogy()) minimum = -1111; // This can happen when switching from lin to log scale.
2969  if (gPad && gPad->GetUymin() < fHistogram->GetMinimum() &&
2970  !fHistogram->TestBit(TH1::kIsZoomed)) minimum = -1111; // This can happen after unzooming a fit.
2971  if (minimum == -1111) { // This can happen after unzooming.
2972  if (fHistogram->TestBit(TH1::kIsZoomed)) {
2973  minimum = fHistogram->GetYaxis()->GetXmin();
2974  } else {
2975  minimum = fMinimum;
2976  // Optimize the computation of the scale in Y in case the min/max of the
2977  // function oscillate around a constant value
2978  if (minimum == -1111) {
2979  Double_t hmin;
2980  if (optSAME && gPad) hmin = gPad->GetUymin();
2981  else hmin = fHistogram->GetMinimum();
2982  if (hmin > 0) {
2983  Double_t hmax;
2984  Double_t hminpos = hmin;
2985  if (optSAME && gPad) hmax = gPad->GetUymax();
2986  else hmax = fHistogram->GetMaximum();
2987  hmin -= 0.05 * (hmax - hmin);
2988  if (hmin < 0) hmin = 0;
2989  if (hmin <= 0 && gPad && gPad->GetLogy()) hmin = hminpos;
2990  minimum = hmin;
2991  }
2992  }
2993  }
2994  fHistogram->SetMinimum(minimum);
2995  }
2996  if (maximum == -1111) {
2997  if (fHistogram->TestBit(TH1::kIsZoomed)) {
2998  maximum = fHistogram->GetYaxis()->GetXmax();
2999  } else {
3000  maximum = fMaximum;
3001  }
3002  fHistogram->SetMaximum(maximum);
3003  }
3004 
3005 
3006  // Draw the histogram.
3007  if (!gPad) return;
3008  if (opt.Length() == 0) {
3009  if (optSAME) fHistogram->Paint("lfsame");
3010  else fHistogram->Paint("lf");
3011  } else {
3012  fHistogram->Paint(option);
3013  }
3014 }
3015 
3016 ////////////////////////////////////////////////////////////////////////////////
3017 /// Create histogram with bin content equal to function value
3018 /// computed at the bin center
3019 /// This histogram will be used to paint the function
3020 /// A re-creation is forced and a new histogram is done if recreate=true
3021 
3022 TH1 *TF1::DoCreateHistogram(Double_t xmin, Double_t xmax, Bool_t recreate)
3023 {
3024  Int_t i;
3025  Double_t xv[1];
3026 
3027  TH1 *histogram = 0;
3028 
3029 
3030  // Create a temporary histogram and fill each channel with the function value
3031  // Preserve axis titles
3032  TString xtitle = "";
3033  TString ytitle = "";
3034  char *semicol = (char *)strstr(GetTitle(), ";");
3035  if (semicol) {
3036  Int_t nxt = strlen(semicol);
3037  char *ctemp = new char[nxt];
3038  strlcpy(ctemp, semicol + 1, nxt);
3039  semicol = (char *)strstr(ctemp, ";");
3040  if (semicol) {
3041  *semicol = 0;
3042  ytitle = semicol + 1;
3043  }
3044  xtitle = ctemp;
3045  delete [] ctemp;
3046  }
3047  if (fHistogram) {
3048  // delete previous histograms if were done if done in different mode
3049  xtitle = fHistogram->GetXaxis()->GetTitle();
3050  ytitle = fHistogram->GetYaxis()->GetTitle();
3051  if (!gPad->GetLogx() && fHistogram->TestBit(TH1::kLogX)) {
3052  delete fHistogram;
3053  fHistogram = 0;
3054  recreate = kTRUE;
3055  }
3056  if (gPad->GetLogx() && !fHistogram->TestBit(TH1::kLogX)) {
3057  delete fHistogram;
3058  fHistogram = 0;
3059  recreate = kTRUE;
3060  }
3061  }
3062 
3063  if (fHistogram && !recreate) {
3064  histogram = fHistogram;
3065  fHistogram->GetXaxis()->SetLimits(xmin, xmax);
3066  } else {
3067  // If logx, we must bin in logx and not in x
3068  // otherwise in case of several decades, one gets wrong results.
3069  if (xmin > 0 && gPad && gPad->GetLogx()) {
3070  Double_t *xbins = new Double_t[fNpx + 1];
3071  Double_t xlogmin = TMath::Log10(xmin);
3072  Double_t xlogmax = TMath::Log10(xmax);
3073  Double_t dlogx = (xlogmax - xlogmin) / ((Double_t)fNpx);
3074  for (i = 0; i <= fNpx; i++) {
3075  xbins[i] = gPad->PadtoX(xlogmin + i * dlogx);
3076  }
3077  histogram = new TH1D("Func", GetTitle(), fNpx, xbins);
3078  histogram->SetBit(TH1::kLogX);
3079  delete [] xbins;
3080  } else {
3081  histogram = new TH1D("Func", GetTitle(), fNpx, xmin, xmax);
3082  }
3083  if (fMinimum != -1111) histogram->SetMinimum(fMinimum);
3084  if (fMaximum != -1111) histogram->SetMaximum(fMaximum);
3085  histogram->SetDirectory(0);
3086  }
3087  R__ASSERT(histogram);
3088 
3089  // Restore axis titles.
3090  histogram->GetXaxis()->SetTitle(xtitle.Data());
3091  histogram->GetYaxis()->SetTitle(ytitle.Data());
3092  Double_t *parameters = GetParameters();
3093 
3094  InitArgs(xv, parameters);
3095  for (i = 1; i <= fNpx; i++) {
3096  xv[0] = histogram->GetBinCenter(i);
3097  histogram->SetBinContent(i, EvalPar(xv, parameters));
3098  }
3099 
3100  // Copy Function attributes to histogram attributes.
3101  histogram->SetBit(TH1::kNoStats);
3102  histogram->SetLineColor(GetLineColor());
3103  histogram->SetLineStyle(GetLineStyle());
3104  histogram->SetLineWidth(GetLineWidth());
3105  histogram->SetFillColor(GetFillColor());
3106  histogram->SetFillStyle(GetFillStyle());
3107  histogram->SetMarkerColor(GetMarkerColor());
3108  histogram->SetMarkerStyle(GetMarkerStyle());
3109  histogram->SetMarkerSize(GetMarkerSize());
3110 
3111  // update saved histogram in case it was deleted or if it is the first time the method is called
3112  // for example when called from TF1::GetHistogram()
3113  if (!fHistogram) fHistogram = histogram;
3114  return histogram;
3115 
3116 }
3117 
3118 
3119 ////////////////////////////////////////////////////////////////////////////////
3120 /// Release parameter number ipar If used in a fit, the parameter
3121 /// can vary freely. The parameter limits are reset to 0,0.
3122 
3123 void TF1::ReleaseParameter(Int_t ipar)
3124 {
3125  if (ipar < 0 || ipar > GetNpar() - 1) return;
3126  SetParLimits(ipar, 0, 0);
3127 }
3128 
3129 
3130 ////////////////////////////////////////////////////////////////////////////////
3131 /// Save values of function in array fSave
3132 
3133 void TF1::Save(Double_t xmin, Double_t xmax, Double_t, Double_t, Double_t, Double_t)
3134 {
3135  Double_t *parameters = GetParameters();
3136  //if (fSave != 0) {delete [] fSave; fSave = 0;}
3137  if (fParent && fParent->InheritsFrom(TH1::Class())) {
3138  //if parent is a histogram save the function at the center of the bins
3139  if ((xmin > 0 && xmax > 0) && TMath::Abs(TMath::Log10(xmax / xmin) > TMath::Log10(fNpx))) {
3140  TH1 *h = (TH1 *)fParent;
3141  Int_t bin1 = h->GetXaxis()->FindBin(xmin);
3142  Int_t bin2 = h->GetXaxis()->FindBin(xmax);
3143  int fNsave = bin2 - bin1 + 4;
3144  //fSave = new Double_t[fNsave];
3145  fSave.resize(fNsave);
3146  Double_t xv[1];
3147 
3148  InitArgs(xv, parameters);
3149  for (Int_t i = bin1; i <= bin2; i++) {
3150  xv[0] = h->GetXaxis()->GetBinCenter(i);
3151  fSave[i - bin1] = EvalPar(xv, parameters);
3152  }
3153  fSave[fNsave - 3] = xmin;
3154  fSave[fNsave - 2] = xmax;
3155  fSave[fNsave - 1] = xmax;
3156  return;
3157  }
3158  }
3159  int fNsave = fNpx + 3;
3160  if (fNsave <= 3) {
3161  return;
3162  }
3163  //fSave = new Double_t[fNsave];
3164  fSave.resize(fNsave);
3165  Double_t dx = (xmax - xmin) / fNpx;
3166  if (dx <= 0) {
3167  dx = (fXmax - fXmin) / fNpx;
3168  fNsave--;
3169  xmin = fXmin + 0.5 * dx;
3170  xmax = fXmax - 0.5 * dx;
3171  }
3172  Double_t xv[1];
3173  InitArgs(xv, parameters);
3174  for (Int_t i = 0; i <= fNpx; i++) {
3175  xv[0] = xmin + dx * i;
3176  fSave[i] = EvalPar(xv, parameters);
3177  }
3178  fSave[fNpx + 1] = xmin;
3179  fSave[fNpx + 2] = xmax;
3180 }
3181 
3182 
3183 ////////////////////////////////////////////////////////////////////////////////
3184 /// Save primitive as a C++ statement(s) on output stream out
3185 
3186 void TF1::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
3187 {
3188  Int_t i;
3189  char quote = '"';
3190 
3191  // Save the function as C code independant from ROOT.
3192  if (strstr(option, "cc")) {
3193  out << "double " << GetName() << "(double xv) {" << std::endl;
3194  Double_t dx = (fXmax - fXmin) / (fNpx - 1);
3195  out << " double x[" << fNpx << "] = {" << std::endl;
3196  out << " ";
3197  Int_t n = 0;
3198  for (i = 0; i < fNpx; i++) {
3199  out << fXmin + dx *i ;
3200  if (i < fNpx - 1) out << ", ";
3201  if (n++ == 10) {
3202  out << std::endl;
3203  out << " ";
3204  n = 0;
3205  }
3206  }
3207  out << std::endl;
3208  out << " };" << std::endl;
3209  out << " double y[" << fNpx << "] = {" << std::endl;
3210  out << " ";
3211  n = 0;
3212  for (i = 0; i < fNpx; i++) {
3213  out << Eval(fXmin + dx * i);
3214  if (i < fNpx - 1) out << ", ";
3215  if (n++ == 10) {
3216  out << std::endl;
3217  out << " ";
3218  n = 0;
3219  }
3220  }
3221  out << std::endl;
3222  out << " };" << std::endl;
3223  out << " if (xv<x[0]) return y[0];" << std::endl;
3224  out << " if (xv>x[" << fNpx - 1 << "]) return y[" << fNpx - 1 << "];" << std::endl;
3225  out << " int i, j=0;" << std::endl;
3226  out << " for (i=1; i<" << fNpx << "; i++) { if (xv < x[i]) break; j++; }" << std::endl;
3227  out << " return y[j] + (y[j + 1] - y[j]) / (x[j + 1] - x[j]) * (xv - x[j]);" << std::endl;
3228  out << "}" << std::endl;
3229  return;
3230  }
3231 
3232  out << " " << std::endl;
3233 
3234  // Either f1Number is computed locally or set from outside
3235  static Int_t f1Number = 0;
3236  TString f1Name(GetName());
3237  const char *l = strstr(option, "#");
3238  if (l != 0) {
3239  sscanf(&l[1], "%d", &f1Number);
3240  } else {
3241  ++f1Number;
3242  }
3243  f1Name += f1Number;
3244 
3245  const char *addToGlobList = fParent ? ", TF1::EAddToList::kNo" : ", TF1::EAddToList::kDefault";
3246 
3247  if (!fType) {
3248  out << " TF1 *" << f1Name.Data() << " = new TF1(" << quote << GetName() << quote << "," << quote << GetTitle() << quote << "," << fXmin << "," << fXmax << addToGlobList << ");" << std::endl;
3249  if (fNpx != 100) {
3250  out << " " << f1Name.Data() << "->SetNpx(" << fNpx << ");" << std::endl;
3251  }
3252  } else {
3253  out << " TF1 *" << f1Name.Data() << " = new TF1(" << quote << "*" << GetName() << quote << "," << fXmin << "," << fXmax << "," << GetNpar() << ");" << std::endl;
3254  out << " //The original function : " << GetTitle() << " had originally been created by:" << std::endl;
3255  out << " //TF1 *" << GetName() << " = new TF1(" << quote << GetName() << quote << "," << GetTitle() << "," << fXmin << "," << fXmax << "," << GetNpar();
3256  out << ", 1" << addToGlobList << ");" << std::endl;
3257  out << " " << f1Name.Data() << "->SetRange(" << fXmin << "," << fXmax << ");" << std::endl;
3258  out << " " << f1Name.Data() << "->SetName(" << quote << GetName() << quote << ");" << std::endl;
3259  out << " " << f1Name.Data() << "->SetTitle(" << quote << GetTitle() << quote << ");" << std::endl;
3260  if (fNpx != 100) {
3261  out << " " << f1Name.Data() << "->SetNpx(" << fNpx << ");" << std::endl;
3262  }
3263  Double_t dx = (fXmax - fXmin) / fNpx;
3264  Double_t xv[1];
3265  Double_t *parameters = GetParameters();
3266  InitArgs(xv, parameters);
3267  for (i = 0; i <= fNpx; i++) {
3268  xv[0] = fXmin + dx * i;
3269  Double_t save = EvalPar(xv, parameters);
3270  out << " " << f1Name.Data() << "->SetSavedPoint(" << i << "," << save << ");" << std::endl;
3271  }
3272  out << " " << f1Name.Data() << "->SetSavedPoint(" << fNpx + 1 << "," << fXmin << ");" << std::endl;
3273  out << " " << f1Name.Data() << "->SetSavedPoint(" << fNpx + 2 << "," << fXmax << ");" << std::endl;
3274  }
3275 
3276  if (TestBit(kNotDraw)) {
3277  out << " " << f1Name.Data() << "->SetBit(TF1::kNotDraw);" << std::endl;
3278  }
3279  if (GetFillColor() != 0) {
3280  if (GetFillColor() > 228) {
3281  TColor::SaveColor(out, GetFillColor());
3282  out << " " << f1Name.Data() << "->SetFillColor(ci);" << std::endl;
3283  } else
3284  out << " " << f1Name.Data() << "->SetFillColor(" << GetFillColor() << ");" << std::endl;
3285  }
3286  if (GetFillStyle() != 1001) {
3287  out << " " << f1Name.Data() << "->SetFillStyle(" << GetFillStyle() << ");" << std::endl;
3288  }
3289  if (GetMarkerColor() != 1) {
3290  if (GetMarkerColor() > 228) {
3291  TColor::SaveColor(out, GetMarkerColor());
3292  out << " " << f1Name.Data() << "->SetMarkerColor(ci);" << std::endl;
3293  } else
3294  out << " " << f1Name.Data() << "->SetMarkerColor(" << GetMarkerColor() << ");" << std::endl;
3295  }
3296  if (GetMarkerStyle() != 1) {
3297  out << " " << f1Name.Data() << "->SetMarkerStyle(" << GetMarkerStyle() << ");" << std::endl;
3298  }
3299  if (GetMarkerSize() != 1) {
3300  out << " " << f1Name.Data() << "->SetMarkerSize(" << GetMarkerSize() << ");" << std::endl;
3301  }
3302  if (GetLineColor() != 1) {
3303  if (GetLineColor() > 228) {
3304  TColor::SaveColor(out, GetLineColor());
3305  out << " " << f1Name.Data() << "->SetLineColor(ci);" << std::endl;
3306  } else
3307  out << " " << f1Name.Data() << "->SetLineColor(" << GetLineColor() << ");" << std::endl;
3308  }
3309  if (GetLineWidth() != 4) {
3310  out << " " << f1Name.Data() << "->SetLineWidth(" << GetLineWidth() << ");" << std::endl;
3311  }
3312  if (GetLineStyle() != 1) {
3313  out << " " << f1Name.Data() << "->SetLineStyle(" << GetLineStyle() << ");" << std::endl;
3314  }
3315  if (GetChisquare() != 0) {
3316  out << " " << f1Name.Data() << "->SetChisquare(" << GetChisquare() << ");" << std::endl;
3317  out << " " << f1Name.Data() << "->SetNDF(" << GetNDF() << ");" << std::endl;
3318  }
3319 
3320  if (GetXaxis()) GetXaxis()->SaveAttributes(out, f1Name.Data(), "->GetXaxis()");
3321  if (GetYaxis()) GetYaxis()->SaveAttributes(out, f1Name.Data(), "->GetYaxis()");
3322 
3323  Double_t parmin, parmax;
3324  for (i = 0; i < GetNpar(); i++) {
3325  out << " " << f1Name.Data() << "->SetParameter(" << i << "," << GetParameter(i) << ");" << std::endl;
3326  out << " " << f1Name.Data() << "->SetParError(" << i << "," << GetParError(i) << ");" << std::endl;
3327  GetParLimits(i, parmin, parmax);
3328  out << " " << f1Name.Data() << "->SetParLimits(" << i << "," << parmin << "," << parmax << ");" << std::endl;
3329  }
3330  if (!strstr(option, "nodraw")) {
3331  out << " " << f1Name.Data() << "->Draw("
3332  << quote << option << quote << ");" << std::endl;
3333  }
3334 }
3335 
3336 
3337 ////////////////////////////////////////////////////////////////////////////////
3338 /// Static function setting the current function.
3339 /// the current function may be accessed in static C-like functions
3340 /// when fitting or painting a function.
3341 
3342 void TF1::SetCurrent(TF1 *f1)
3343 {
3344  fgCurrent = f1;
3345 }
3346 
3347 ////////////////////////////////////////////////////////////////////////////////
3348 /// Set the result from the fit
3349 /// parameter values, errors, chi2, etc...
3350 /// Optionally a pointer to a vector (with size fNpar) of the parameter indices in the FitResult can be passed
3351 /// This is useful in the case of a combined fit with different functions, and the FitResult contains the global result
3352 /// By default it is assume that indpar = {0,1,2,....,fNpar-1}.
3353 
3354 void TF1::SetFitResult(const ROOT::Fit::FitResult &result, const Int_t *indpar)
3355 {
3356  Int_t npar = GetNpar();
3357  if (result.IsEmpty()) {
3358  Warning("SetFitResult", "Empty Fit result - nothing is set in TF1");
3359  return;
3360  }
3361  if (indpar == 0 && npar != (int) result.NPar()) {
3362  Error("SetFitResult", "Invalid Fit result passed - number of parameter is %d , different than TF1::GetNpar() = %d", npar, result.NPar());
3363  return;
3364  }
3365  if (result.Chi2() > 0)
3366  SetChisquare(result.Chi2());
3367  else
3368  SetChisquare(result.MinFcnValue());
3369 
3370  SetNDF(result.Ndf());
3371  SetNumberFitPoints(result.Ndf() + result.NFreeParameters());
3372 
3373 
3374  for (Int_t i = 0; i < npar; ++i) {
3375  Int_t ipar = (indpar != 0) ? indpar[i] : i;
3376  if (ipar < 0) continue;
3377  GetParameters()[i] = result.Parameter(ipar);
3378  // in case errors are not present do not set them
3379  if (ipar < (int) result.Errors().size())
3380  fParErrors[i] = result.Error(ipar);
3381  }
3382  //invalidate cached integral since parameters have changed
3383  Update();
3384 
3385 }
3386 
3387 
3388 ////////////////////////////////////////////////////////////////////////////////
3389 /// Set the maximum value along Y for this function
3390 /// In case the function is already drawn, set also the maximum in the
3391 /// helper histogram
3392 
3393 void TF1::SetMaximum(Double_t maximum)
3394 {
3395  fMaximum = maximum;
3396  if (fHistogram) fHistogram->SetMaximum(maximum);
3397  if (gPad) gPad->Modified();
3398 }
3399 
3400 
3401 ////////////////////////////////////////////////////////////////////////////////
3402 /// Set the minimum value along Y for this function
3403 /// In case the function is already drawn, set also the minimum in the
3404 /// helper histogram
3405 
3406 void TF1::SetMinimum(Double_t minimum)
3407 {
3408  fMinimum = minimum;
3409  if (fHistogram) fHistogram->SetMinimum(minimum);
3410  if (gPad) gPad->Modified();
3411 }
3412 
3413 
3414 ////////////////////////////////////////////////////////////////////////////////
3415 /// Set the number of degrees of freedom
3416 /// ndf should be the number of points used in a fit - the number of free parameters
3417 
3418 void TF1::SetNDF(Int_t ndf)
3419 {
3420  fNDF = ndf;
3421 }
3422 
3423 
3424 ////////////////////////////////////////////////////////////////////////////////
3425 /// Set the number of points used to draw the function
3426 ///
3427 /// The default number of points along x is 100 for 1-d functions and 30 for 2-d/3-d functions
3428 /// You can increase this value to get a better resolution when drawing
3429 /// pictures with sharp peaks or to get a better result when using TF1::GetRandom
3430 /// the minimum number of points is 4, the maximum is 10000000 for 1-d and 10000 for 2-d/3-d functions
3431 
3432 void TF1::SetNpx(Int_t npx)
3433 {
3434  const Int_t minPx = 4;
3435  Int_t maxPx = 10000000;
3436  if (GetNdim() > 1) maxPx = 10000;
3437  if (npx >= minPx && npx <= maxPx) {
3438  fNpx = npx;
3439  } else {
3440  if (npx < minPx) fNpx = minPx;
3441  if (npx > maxPx) fNpx = maxPx;
3442  Warning("SetNpx", "Number of points must be >=%d && <= %d, fNpx set to %d", minPx, maxPx, fNpx);
3443  }
3444  Update();
3445 }
3446 ////////////////////////////////////////////////////////////////////////////////
3447 /// Set name of parameter number ipar
3448 
3449 void TF1::SetParName(Int_t ipar, const char *name)
3450 {
3451  if (fFormula) {
3452  if (ipar < 0 || ipar >= GetNpar()) return;
3453  fFormula->SetParName(ipar, name);
3454  } else
3455  fParams->SetParName(ipar, name);
3456 }
3457 
3458 ////////////////////////////////////////////////////////////////////////////////
3459 /// Set up to 10 parameter names
3460 
3461 void TF1::SetParNames(const char *name0, const char *name1, const char *name2, const char *name3, const char *name4,
3462  const char *name5, const char *name6, const char *name7, const char *name8, const char *name9, const char *name10)
3463 {
3464  if (fFormula)
3465  fFormula->SetParNames(name0, name1, name2, name3, name4, name5, name6, name7, name8, name9, name10);
3466  else
3467  fParams->SetParNames(name0, name1, name2, name3, name4, name5, name6, name7, name8, name9, name10);
3468 }
3469 ////////////////////////////////////////////////////////////////////////////////
3470 /// Set error for parameter number ipar
3471 
3472 void TF1::SetParError(Int_t ipar, Double_t error)
3473 {
3474  if (ipar < 0 || ipar > GetNpar() - 1) return;
3475  fParErrors[ipar] = error;
3476 }
3477 
3478 
3479 ////////////////////////////////////////////////////////////////////////////////
3480 /// Set errors for all active parameters
3481 /// when calling this function, the array errors must have at least fNpar values
3482 
3483 void TF1::SetParErrors(const Double_t *errors)
3484 {
3485  if (!errors) return;
3486  for (Int_t i = 0; i < GetNpar(); i++) fParErrors[i] = errors[i];
3487 }
3488 
3489 
3490 ////////////////////////////////////////////////////////////////////////////////
3491 /// Set limits for parameter ipar.
3492 ///
3493 /// The specified limits will be used in a fit operation
3494 /// when the option "B" is specified (Bounds).
3495 /// To fix a parameter, use TF1::FixParameter
3496 
3497 void TF1::SetParLimits(Int_t ipar, Double_t parmin, Double_t parmax)
3498 {
3499  Int_t npar = GetNpar();
3500  if (ipar < 0 || ipar > npar - 1) return;
3501  if (int(fParMin.size()) != npar) {
3502  fParMin.resize(npar);
3503  }
3504  if (int(fParMax.size()) != npar) {
3505  fParMax.resize(npar);
3506  }
3507  fParMin[ipar] = parmin;
3508  fParMax[ipar] = parmax;
3509 }
3510 
3511 
3512 ////////////////////////////////////////////////////////////////////////////////
3513 /// Initialize the upper and lower bounds to draw the function.
3514 ///
3515 /// The function range is also used in an histogram fit operation
3516 /// when the option "R" is specified.
3517 
3518 void TF1::SetRange(Double_t xmin, Double_t xmax)
3519 {
3520  fXmin = xmin;
3521  fXmax = xmax;
3522  if (fType == EFType::kCompositionFcn && fComposition) {
3523  fComposition->SetRange(xmin, xmax); // automatically updates sub-functions
3524  }
3525  Update();
3526 }
3527 
3528 
3529 ////////////////////////////////////////////////////////////////////////////////
3530 /// Restore value of function saved at point
3531 
3532 void TF1::SetSavedPoint(Int_t point, Double_t value)
3533 {
3534  if (fSave.size() == 0) {
3535  fSave.resize(fNpx + 3);
3536  }
3537  if (point < 0 || point >= int(fSave.size())) return;
3538  fSave[point] = value;
3539 }
3540 
3541 
3542 ////////////////////////////////////////////////////////////////////////////////
3543 /// Set function title
3544 /// if title has the form "fffffff;xxxx;yyyy", it is assumed that
3545 /// the function title is "fffffff" and "xxxx" and "yyyy" are the
3546 /// titles for the X and Y axis respectively.
3547 
3548 void TF1::SetTitle(const char *title)
3549 {
3550  if (!title) return;
3551  fTitle = title;
3552  if (!fHistogram) return;
3553  fHistogram->SetTitle(title);
3554  if (gPad) gPad->Modified();
3555 }
3556 
3557 
3558 ////////////////////////////////////////////////////////////////////////////////
3559 /// Stream a class object.
3560 
3561 void TF1::Streamer(TBuffer &b)
3562 {
3563  if (b.IsReading()) {
3564  UInt_t R__s, R__c;
3565  Version_t v = b.ReadVersion(&R__s, &R__c);
3566  // process new version with new TFormula class which is contained in TF1
3567  //printf("reading TF1....- version %d..\n",v);
3568 
3569  if (v > 7) {
3570  // new classes with new TFormula
3571  // need to register the objects
3572  b.ReadClassBuffer(TF1::Class(), this, v, R__s, R__c);
3573  if (!TestBit(kNotGlobal)) {
3574  R__LOCKGUARD(gROOTMutex);
3575  gROOT->GetListOfFunctions()->Add(this);
3576  }
3577  if (v >= 10)
3578  fComposition = std::unique_ptr<TF1AbsComposition>(fComposition_ptr);
3579  return;
3580  } else {
3581  ROOT::v5::TF1Data fold;
3582  //printf("Reading TF1 as v5::TF1Data- version %d \n",v);
3583  fold.Streamer(b, v, R__s, R__c, TF1::Class());
3584  // convert old TF1 to new one
3585  ((TF1v5Convert *)this)->Convert(fold);
3586  }
3587  }
3588 
3589  // Writing
3590  else {
3591  Int_t saved = 0;
3592  // save not-formula functions as array of points
3593  if (fType > 0 && fSave.empty() && fType != EFType::kCompositionFcn) {
3594  saved = 1;
3595  Save(fXmin, fXmax, 0, 0, 0, 0);
3596  }
3597  if (fType == EFType::kCompositionFcn)
3598  fComposition_ptr = fComposition.get();
3599  else
3600  fComposition_ptr = nullptr;
3601  b.WriteClassBuffer(TF1::Class(), this);
3602 
3603  // clear vector contents
3604  if (saved) {
3605  fSave.clear();
3606  }
3607  }
3608 }
3609 
3610 
3611 ////////////////////////////////////////////////////////////////////////////////
3612 /// Called by functions such as SetRange, SetNpx, SetParameters
3613 /// to force the deletion of the associated histogram or Integral
3614 
3615 void TF1::Update()
3616 {
3617  delete fHistogram;
3618  fHistogram = 0;
3619  if (!fIntegral.empty()) {
3620  fIntegral.clear();
3621  fAlpha.clear();
3622  fBeta.clear();
3623  fGamma.clear();
3624  }
3625  if (fNormalized) {
3626  // need to compute the integral of the not-normalized function
3627  fNormalized = false;
3628  fNormIntegral = Integral(fXmin, fXmax, 0.0);
3629  fNormalized = true;
3630  } else
3631  fNormIntegral = 0;
3632 
3633  // std::vector<double>x(fNdim);
3634  // if ((fType == 1) && !fFunctor->Empty()) (*fFunctor)x.data(), (Double_t*)fParams);
3635  if (fType == EFType::kCompositionFcn && fComposition) {
3636  // double-check that the parameters are correct
3637  fComposition->SetParameters(GetParameters());
3638 
3639  fComposition->Update(); // should not be necessary, but just to be safe
3640  }
3641 }
3642 
3643 ////////////////////////////////////////////////////////////////////////////////
3644 /// Static function to set the global flag to reject points
3645 /// the fgRejectPoint global flag is tested by all fit functions
3646 /// if TRUE the point is not included in the fit.
3647 /// This flag can be set by a user in a fitting function.
3648 /// The fgRejectPoint flag is reset by the TH1 and TGraph fitting functions.
3649 
3650 void TF1::RejectPoint(Bool_t reject)
3651 {
3652  fgRejectPoint = reject;
3653 }
3654 
3655 
3656 ////////////////////////////////////////////////////////////////////////////////
3657 /// See TF1::RejectPoint above
3658 
3659 Bool_t TF1::RejectedPoint()
3660 {
3661  return fgRejectPoint;
3662 }
3663 
3664 ////////////////////////////////////////////////////////////////////////////////
3665 /// Return nth moment of function between a and b
3666 ///
3667 /// See TF1::Integral() for parameter definitions
3668 
3669 Double_t TF1::Moment(Double_t n, Double_t a, Double_t b, const Double_t *params, Double_t epsilon)
3670 {
3671  // wrapped function in interface for integral calculation
3672  // using abs value of integral
3673 
3674  TF1_EvalWrapper func(this, params, kTRUE, n);
3675 
3676  ROOT::Math::GaussIntegrator giod;
3677 
3678  giod.SetFunction(func);
3679  giod.SetRelTolerance(epsilon);
3680 
3681  Double_t norm = giod.Integral(a, b);
3682  if (norm == 0) {
3683  Error("Moment", "Integral zero over range");
3684  return 0;
3685  }
3686 
3687  // calculate now integral of x^n f(x)
3688  // wrapped the member function EvalNum in interface required by integrator using the functor class
3689  ROOT::Math::Functor1D xnfunc(&func, &TF1_EvalWrapper::EvalNMom);
3690  giod.SetFunction(xnfunc);
3691 
3692  Double_t res = giod.Integral(a, b) / norm;
3693 
3694  return res;
3695 }
3696 
3697 
3698 ////////////////////////////////////////////////////////////////////////////////
3699 /// Return nth central moment of function between a and b
3700 /// (i.e the n-th moment around the mean value)
3701 ///
3702 /// See TF1::Integral() for parameter definitions
3703 ///
3704 /// \author Gene Van Buren <gene@bnl.gov>
3705 
3706 Double_t TF1::CentralMoment(Double_t n, Double_t a, Double_t b, const Double_t *params, Double_t epsilon)
3707 {
3708  TF1_EvalWrapper func(this, params, kTRUE, n);
3709 
3710  ROOT::Math::GaussIntegrator giod;
3711 
3712  giod.SetFunction(func);
3713  giod.SetRelTolerance(epsilon);
3714 
3715  Double_t norm = giod.Integral(a, b);
3716  if (norm == 0) {
3717  Error("Moment", "Integral zero over range");
3718  return 0;
3719  }
3720 
3721  // calculate now integral of xf(x)
3722  // wrapped the member function EvalFirstMom in interface required by integrator using the functor class
3723  ROOT::Math::Functor1D xfunc(&func, &TF1_EvalWrapper::EvalFirstMom);
3724  giod.SetFunction(xfunc);
3725 
3726  // estimate of mean value
3727  Double_t xbar = giod.Integral(a, b) / norm;
3728 
3729  // use different mean value in function wrapper
3730  func.fX0 = xbar;
3731  ROOT::Math::Functor1D xnfunc(&func, &TF1_EvalWrapper::EvalNMom);
3732  giod.SetFunction(xnfunc);
3733 
3734  Double_t res = giod.Integral(a, b) / norm;
3735  return res;
3736 }
3737 
3738 
3739 //______________________________________________________________________________
3740 // some useful static utility functions to compute sampling points for IntegralFast
3741 ////////////////////////////////////////////////////////////////////////////////
3742 /// Type safe interface (static method)
3743 /// The number of sampling points are taken from the TGraph
3744 
3745 #ifdef INTHEFUTURE
3746 void TF1::CalcGaussLegendreSamplingPoints(TGraph *g, Double_t eps)
3747 {
3748  if (!g) return;
3749  CalcGaussLegendreSamplingPoints(g->GetN(), g->GetX(), g->GetY(), eps);
3750 }
3751 
3752 
3753 ////////////////////////////////////////////////////////////////////////////////
3754 /// Type safe interface (static method)
3755 /// A TGraph is created with new with num points and the pointer to the
3756 /// graph is returned by the function. It is the responsibility of the
3757 /// user to delete the object.
3758 /// if num is invalid (<=0) NULL is returned
3759 
3760 TGraph *TF1::CalcGaussLegendreSamplingPoints(Int_t num, Double_t eps)
3761 {
3762  if (num <= 0)
3763  return 0;
3764 
3765  TGraph *g = new TGraph(num);
3766  CalcGaussLegendreSamplingPoints(g->GetN(), g->GetX(), g->GetY(), eps);
3767  return g;
3768 }
3769 #endif
3770 
3771 
3772 ////////////////////////////////////////////////////////////////////////////////
3773 /// Type: unsafe but fast interface filling the arrays x and w (static method)
3774 ///
3775 /// Given the number of sampling points this routine fills the arrays x and w
3776 /// of length num, containing the abscissa and weight of the Gauss-Legendre
3777 /// n-point quadrature formula.
3778 ///
3779 /// Gauss-Legendre:
3780 /** \f[
3781  W(x)=1 -1<x<1 \\
3782  (j+1)P_{j+1} = (2j+1)xP_j-jP_{j-1}
3783  \f]
3784 **/
3785 /// num is the number of sampling points (>0)
3786 /// x and w are arrays of size num
3787 /// eps is the relative precision
3788 ///
3789 /// If num<=0 or eps<=0 no action is done.
3790 ///
3791 /// Reference: Numerical Recipes in C, Second Edition
3792 
3793 void TF1::CalcGaussLegendreSamplingPoints(Int_t num, Double_t *x, Double_t *w, Double_t eps)
3794 {
3795  // This function is just kept like this for backward compatibility!
3796 
3797  ROOT::Math::GaussLegendreIntegrator gli(num, eps);
3798  gli.GetWeightVectors(x, w);
3799 
3800 
3801 }
3802 
3803 
3804 /** \class TF1Parameters
3805 TF1 Parameters class
3806 */
3807 
3808 ////////////////////////////////////////////////////////////////////////////////
3809 /// Returns the parameter number given a name
3810 /// not very efficient but list of parameters is typically small
3811 /// could use a map if needed
3812 
3813 Int_t TF1Parameters::GetParNumber(const char *name) const
3814 {
3815  for (unsigned int i = 0; i < fParNames.size(); ++i) {
3816  if (fParNames[i] == std::string(name)) return i;
3817  }
3818  return -1;
3819 }
3820 
3821 ////////////////////////////////////////////////////////////////////////////////
3822 /// Set parameter values
3823 
3824 void TF1Parameters::SetParameters(Double_t p0, Double_t p1, Double_t p2, Double_t p3, Double_t p4,
3825  Double_t p5, Double_t p6, Double_t p7, Double_t p8,
3826  Double_t p9, Double_t p10)
3827 {
3828  unsigned int npar = fParameters.size();
3829  if (npar > 0) fParameters[0] = p0;
3830  if (npar > 1) fParameters[1] = p1;
3831  if (npar > 2) fParameters[2] = p2;
3832  if (npar > 3) fParameters[3] = p3;
3833  if (npar > 4) fParameters[4] = p4;
3834  if (npar > 5) fParameters[5] = p5;
3835  if (npar > 6) fParameters[6] = p6;
3836  if (npar > 7) fParameters[7] = p7;
3837  if (npar > 8) fParameters[8] = p8;
3838  if (npar > 9) fParameters[9] = p9;
3839  if (npar > 10) fParameters[10] = p10;
3840 }
3841 
3842 ////////////////////////////////////////////////////////////////////////////////
3843 /// Set parameter names
3844 
3845 void TF1Parameters::SetParNames(const char *name0, const char *name1, const char *name2, const char *name3,
3846  const char *name4, const char *name5, const char *name6, const char *name7,
3847  const char *name8, const char *name9, const char *name10)
3848 {
3849  unsigned int npar = fParNames.size();
3850  if (npar > 0) fParNames[0] = name0;
3851  if (npar > 1) fParNames[1] = name1;
3852  if (npar > 2) fParNames[2] = name2;
3853  if (npar > 3) fParNames[3] = name3;
3854  if (npar > 4) fParNames[4] = name4;
3855  if (npar > 5) fParNames[5] = name5;
3856  if (npar > 6) fParNames[6] = name6;
3857  if (npar > 7) fParNames[7] = name7;
3858  if (npar > 8) fParNames[8] = name8;
3859  if (npar > 9) fParNames[9] = name9;
3860  if (npar > 10) fParNames[10] = name10;
3861 }