Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TLinearFitter.cxx
Go to the documentation of this file.
1// @(#)root/minuit:$Id$
2// Author: Anna Kreshuk 04/03/2005
3
4/*************************************************************************
5 * Copyright (C) 1995-2005, 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 "TLinearFitter.h"
13#include "TMath.h"
14#include "TDecompChol.h"
15#include "TGraph.h"
16#include "TGraph2D.h"
17#include "TMultiGraph.h"
18#include "TRandom2.h"
19#include "TObjString.h"
20#include "TF2.h"
21#include "TH1.h"
22#include "TList.h"
23#include "TClass.h"
24#include "TBuffer.h"
25#include "TROOT.h"
26#include "strlcpy.h"
27
28#include <string>
29
31
32
33std::map<TString,TFormula*> TLinearFitter::fgFormulaMap;
34
35
36
37/**
38
39\class TLinearFitter
40
41\note An alternative to this class is to use ROOT::Fit::Fitter, calling the LinearFit() method.
42
43\ingroup MinuitOld
44
45The Linear Fitter - For fitting functions that are LINEAR IN PARAMETERS
46
47## The Linear Fitter
48
49Linear fitter is used to fit a set of data points with a linear
50combination of specified functions. Note, that "linear" in the name
51stands only for the model dependency on parameters, the specified
52functions can be nonlinear.
53The general form of this kind of model is
54~~~~
55 y(x) = a[0] + a[1]*f[1](x)+...a[n]*f[n](x)
56~~~~
57
58Functions f are fixed functions of x. For example, fitting with a
59polynomial is linear fitting in this sense.
60
61### Introduction
62
63#### The fitting method
64
65The fit is performed using the Normal Equations method with Cholesky
66decomposition.
67
68#### Why should it be used?
69
70The linear fitter is considerably faster than general non-linear
71fitters and doesn't require to set the initial values of parameters.
72
73### Using the fitter:
74
75### 1.Adding the data points:
76
77#### 1.1 To store or not to store the input data?
78 - There are 2 options in the constructor - to store or not
79 store the input data. The advantages of storing the data
80 are that you'll be able to reset the fitting model without
81 adding all the points again, and that for very large sets
82 of points the chisquare is calculated more precisely.
83 The obvious disadvantage is the amount of memory used to
84 keep all the points.
85 - Before you start adding the points, you can change the
86 store/not store option by StoreData() method.
87
88#### 1.2 The data can be added:
89 - simply point by point - AddPoint() method
90 - an array of points at once:
91 If the data is already stored in some arrays, this data
92 can be assigned to the linear fitter without physically
93 coping bytes, thanks to the Use() method of
94 TVector and TMatrix classes - AssignData() method
95
96### 2.Setting the formula
97
98#### 2.1 The linear formula syntax:
99 -Additive parts are separated by 2 plus signs "++"
100 --for example "1 ++ x" - for fitting a straight line
101 -All standard functions, undrestood by TFormula, can be used
102 as additive parts
103 --TMath functions can be used too
104 -Functions, used as additive parts, shouldn't have any parameters,
105 even if those parameters are set.
106 --for example, if normalizing a sum of a gaus(0, 1) and a
107 gaus(0, 2), don't use the built-in "gaus" of TFormula,
108 because it has parameters, take TMath::Gaus(x, 0, 1) instead.
109 -Polynomials can be used like "pol3", .."polN"
110 -If fitting a more than 3-dimensional formula, variables should
111 be numbered as follows:
112 -- x[0], x[1], x[2]... For example, to fit "1 ++ x[0] ++ x[1] ++ x[2] ++ x[3]*x[3]"
113
114#### 2.2 Setting the formula:
115
116##### 2.2.1 If fitting a 1-2-3-dimensional formula, one can create a
117 TF123 based on a linear expression and pass this function
118 to the fitter:
119 --Example:
120~~~~
121 TLinearFitter *lf = new TLinearFitter();
122 TF2 *f2 = new TF2("f2", "x ++ y ++ x*x*y*y", -2, 2, -2, 2);
123 lf->SetFormula(f2);
124~~~~
125 --The results of the fit are then stored in the function,
126 just like when the TH1::Fit or TGraph::Fit is used
127 --A linear function of this kind is by no means different
128 from any other function, it can be drawn, evaluated, etc.
129
130 --For multidimensional fitting, TFormulas of the form:
131 x[0]++...++x[n] can be used
132##### 2.2.2 There is no need to create the function if you don't want to,
133 the formula can be set by expression:
134 --Example:
135~~~~
136 // 2 is the number of dimensions
137 TLinearFitter *lf = new TLinearFitter(2);
138 lf->SetFormula("x ++ y ++ x*x*y*y");
139~~~~
140
141##### 2.2.3 The fastest functions to compute are polynomials and hyperplanes.
142 --Polynomials are set the usual way: "pol1", "pol2",...
143 --Hyperplanes are set by expression "hyp3", "hyp4", ...
144 ---The "hypN" expressions only work when the linear fitter
145 is used directly, not through TH1::Fit or TGraph::Fit.
146 To fit a graph or a histogram with a hyperplane, define
147 the function as "1++x++y".
148 ---A constant term is assumed for a hyperplane, when using
149 the "hypN" expression, so "hyp3" is in fact fitting with
150 "1++x++y++z" function.
151 --Fitting hyperplanes is much faster than fitting other
152 expressions so if performance is vital, calculate the
153 function values beforehand and give them to the fitter
154 as variables
155 --Example:
156 You want to fit "sin(x)|cos(2*x)" very fast. Calculate
157 sin(x) and cos(2*x) beforehand and store them in array *data.
158 Then:
159 TLinearFitter *lf=new TLinearFitter(2, "hyp2");
160 lf->AssignData(npoint, 2, data, y);
161
162#### 2.3 Resetting the formula
163
164##### 2.3.1 If the input data is stored (or added via AssignData() function),
165 the fitting formula can be reset without re-adding all the points.
166 --Example:
167~~~~
168 TLinearFitter *lf=new TLinearFitter("1++x++x*x");
169 lf->AssignData(n, 1, x, y, e);
170 lf->Eval()
171 //looking at the parameter significance, you see,
172 // that maybe the fit will improve, if you take out
173 // the constant term
174 lf->SetFormula("x++x*x");
175 lf->Eval();
176 ...
177~~~~
178
179##### 2.3.2 If the input data is not stored, the fitter will have to be
180 cleared and the data will have to be added again to try a
181 different formula.
182
183### 3.Accessing the fit results
184
185#### 3.1 There are methods in the fitter to access all relevant information:
186 --GetParameters, GetCovarianceMatrix, etc
187 --the t-values of parameters and their significance can be reached by
188 GetParTValue() and GetParSignificance() methods
189
190#### 3.2 If fitting with a pre-defined TF123, the fit results are also
191 written into this function.
192
193
194### 4.Robust fitting - Least Trimmed Squares regression (LTS)
195 Outliers are atypical(by definition), infrequant observations; data points
196 which do not appear to follow the characteristic distribution of the rest
197 of the data. These may reflect genuine properties of the underlying
198 phenomenon(variable), or be due to measurement errors or anomalies which
199 shouldn't be modelled. (StatSoft electronic textbook)
200
201 Even a single gross outlier can greatly influence the results of least-
202 squares fitting procedure, and in this case use of robust(resistant) methods
203 is recommended.
204
205 The method implemented here is based on the article and algorithm:
206 "Computing LTS Regression for Large Data Sets" by
207 P.J.Rousseeuw and Katrien Van Driessen
208 The idea of the method is to find the fitting coefficients for a subset
209 of h observations (out of n) with the smallest sum of squared residuals.
210 The size of the subset h should lie between (npoints + nparameters +1)/2
211 and n, and represents the minimal number of good points in the dataset.
212 The default value is set to (npoints + nparameters +1)/2, but of course
213 if you are sure that the data contains less outliers it's better to change
214 h according to your data.
215
216 To perform a robust fit, call EvalRobust() function instead of Eval() after
217 adding the points and setting the fitting function.
218 Note, that standard errors on parameters are not computed!
219
220*/
221
222
223
224////////////////////////////////////////////////////////////////////////////////
225///default c-tor, input data is stored
226///If you don't want to store the input data,
227///run the function StoreData(kFALSE) after constructor
228
230 fVal()
231{
232 fChisquare =0;
233 fNpoints =0;
234 fNdim =0;
235 fY2 =0;
236 fY2Temp =0;
237 fNfixed =0;
238 fIsSet =kFALSE;
239 fFormula =nullptr;
240 fFixedParams=nullptr;
241 fSpecial =0;
242 fInputFunction=nullptr;
245 fNfunctions = 0;
246 fFormulaSize = 0;
247 fH = 0;
248}
249
250////////////////////////////////////////////////////////////////////////////////
251///The parameter stands for number of dimensions in the fitting formula
252///The input data is stored. If you don't want to store the input data,
253///run the function StoreData(kFALSE) after constructor
254
256 fVal()
257{
258 fNdim =ndim;
259 fNpoints =0;
260 fY2 =0;
261 fY2Temp =0;
262 fNfixed =0;
263 fFixedParams=nullptr;
264 fFormula =nullptr;
265 fIsSet =kFALSE;
266 fChisquare=0;
267 fSpecial =0;
268 fInputFunction=nullptr;
270 fRobust = kFALSE;
271 fNfunctions = 0;
272 fFormulaSize = 0;
273 fH = 0;
274}
275
276////////////////////////////////////////////////////////////////////////////////
277///First parameter stands for number of dimensions in the fitting formula
278///Second parameter is the fitting formula: see class description for formula syntax
279///Options:
280///The option is to store or not to store the data
281///If you don't want to store the data, choose "" for the option, or run
282///StoreData(kFalse) member function after the constructor
283
284TLinearFitter::TLinearFitter(Int_t ndim, const char *formula, Option_t *opt)
285{
286 fNdim=ndim;
287 fNpoints=0;
288 fChisquare=0;
289 fY2=0;
290 fNfixed=0;
291 fFixedParams=nullptr;
292 fSpecial=0;
293 fInputFunction=nullptr;
294 fFormula = nullptr;
295 TString option=opt;
296 option.ToUpper();
297 if (option.Contains("D"))
299 else
302 SetFormula(formula);
303}
304
305////////////////////////////////////////////////////////////////////////////////
306///This constructor uses a linear function. How to create it?
307///TFormula now accepts formulas of the following kind:
308///TFormula("f", "x++y++z++x*x") or
309///TFormula("f", "x[0]++x[1]++x[2]*x[2]");
310///Other than the look, it's in no
311///way different from the regular formula, it can be evaluated,
312///drawn, etc.
313///The option is to store or not to store the data
314///If you don't want to store the data, choose "" for the option, or run
315///StoreData(kFalse) member function after the constructor
316
318{
319 fNdim=function->GetNdim();
320 if (!function->IsLinear()){
321 Int_t number=function->GetNumber();
322 if (number<299 || number>310){
323 Error("TLinearFitter", "Trying to fit with a nonlinear function");
324 return;
325 }
326 }
327 fNpoints=0;
328 fChisquare=0;
329 fY2=0;
330 fNfixed=0;
331 fFixedParams=nullptr;
332 fSpecial=0;
333 fFormula = nullptr;
334 TString option=opt;
335 option.ToUpper();
336 if (option.Contains("D"))
338 else
342 fInputFunction=nullptr;
343
344 SetFormula(function);
345}
346
347
348////////////////////////////////////////////////////////////////////////////////
349/// Linear fitter cleanup.
350
352{
353 if (fFormula) {
354 delete [] fFormula;
355 fFormula = nullptr;
356 }
357 if (fFixedParams) {
358 delete [] fFixedParams;
359 fFixedParams = nullptr;
360 }
361 fInputFunction = nullptr;
362
363 //fFunctions.Delete();
365
366}
367
368////////////////////////////////////////////////////////////////////////////////
369///Add another linear fitter to this linear fitter. Points and Design matrices
370///are added, but the previous fitting results (if any) are deleted.
371///Fitters must have same formulas (this is not checked). Fixed parameters are not changed
372
374{
375 fParams.Zero();
376 fParCovar.Zero();
377 fTValues.Zero();
378 fParSign.Zero();
379
380 fDesign += tlf->fDesign;
381
382 fDesignTemp += tlf->fDesignTemp;
383 fDesignTemp2 += tlf->fDesignTemp2;
384 fDesignTemp3 += tlf->fDesignTemp3;
385 fAtb += tlf->fAtb;
386 fAtbTemp += tlf->fAtbTemp;
387 fAtbTemp2 += tlf->fAtbTemp2;
388 fAtbTemp3 += tlf->fAtbTemp3;
389
390 if (fStoreData){
392 Int_t newsize = fNpoints+tlf->fNpoints;
393 if (size<newsize){
397 }
398 for (Int_t i=fNpoints; i<newsize; i++){
399 fY(i)=tlf->fY(i-fNpoints);
400 fE(i)=tlf->fE(i-fNpoints);
401 for (Int_t j=0; j<fNdim; j++){
402 fX(i,j)=tlf->fX(i-fNpoints, j);
403 }
404 }
405 }
406 fY2 += tlf->fY2;
407 fY2Temp += tlf->fY2Temp;
408 fNpoints += tlf->fNpoints;
409 //fInputFunction=(TFormula*)tlf.fInputFunction->Clone();
410
411 fChisquare=0;
412 fH=0;
413 fRobust=false;
414}
415
416////////////////////////////////////////////////////////////////////////////////
417///Adds 1 point to the fitter.
418///First parameter stands for the coordinates of the point, where the function is measured
419///Second parameter - the value being fitted
420///Third parameter - weight(measurement error) of this point (=1 by default)
421
423{
424 Int_t size;
425 fNpoints++;
426 if (fStoreData){
428 if (size<fNpoints){
432 }
433
434 Int_t j=fNpoints-1;
435 fY(j)=y;
436 fE(j)=e;
437 for (Int_t i=0; i<fNdim; i++)
438 fX(j,i)=x[i];
439 }
440 //add the point to the design matrix, if the formula has been set
441 // (LM: why condition !fRobust ?? - remove it to fix Coverity 11602)
442 // when 100< fSpecial < 200 (Polynomial) fFunctions is not empty
443 // (see implementation of SetFormula method)
444 if (fFunctions.IsEmpty()&&(!fInputFunction)&&(fSpecial<=200)){
445 Error("AddPoint", "Point can't be added, because the formula hasn't been set");
446 return;
447 }
448 if (!fRobust) AddToDesign(x, y, e);
449}
450
451////////////////////////////////////////////////////////////////////////////////
452///This function is to use when you already have all the data in arrays
453///and don't want to copy them into the fitter. In this function, the Use() method
454///of TVectorD and TMatrixD is used, so no bytes are physically moved around.
455///First parameter - number of points to fit
456///Second parameter - number of variables in the model
457///Third parameter - the variables of the model, stored in the following way:
458///(x0(0), x1(0), x2(0), x3(0), x0(1), x1(1), x2(1), x3(1),...
459
461{
462 if (npoints<fNpoints){
463 Error("AddData", "Those points are already added");
464 return;
465 }
467 if (fX.GetMatrixArray()==x && fY.GetMatrixArray()==y){
468 if (e){
469 if (fE.GetMatrixArray()==e)
470 same=kTRUE;
471 }
472 }
473
474 fX.Use(npoints, xncols, x);
475 fY.Use(npoints, y);
476 if (e)
477 fE.Use(npoints, e);
478 else {
480 fE=1;
481 }
482 Int_t xfirst;
483 if (!fFunctions.IsEmpty() || fInputFunction || fSpecial>200) {
484 if (same)
485 xfirst=fNpoints;
486
487 else
488 xfirst=0;
489 for (Int_t i=xfirst; i<npoints; i++)
490 AddToDesign(TMatrixDRow(fX, i).GetPtr(), fY(i), fE(i));
491 }
493}
494
495////////////////////////////////////////////////////////////////////////////////
496///Add a point to the AtA matrix and to the Atb vector.
497
499{
500
501
502 Int_t i, j, ii;
503 y/=e;
504
505// Double_t fVal[1000];
506
507 if ((fSpecial>100)&&(fSpecial<200)){
508 //polynomial fitting
509 Int_t npar=fSpecial-100;
510 fVal[0]=1;
511 for (i=1; i<npar; i++)
512 fVal[i]=fVal[i-1]*x[0];
513 for (i=0; i<npar; i++)
514 fVal[i]/=e;
515 } else if (fSpecial>200){
516 //Hyperplane fitting. Constant term is added
517 Int_t npar=fSpecial-201;
518 fVal[0]=1./e;
519 for (i=0; i<npar; i++)
520 fVal[i+1]=x[i]/e;
521 } else {
522 //general case
523 for (ii=0; ii<fNfunctions; ii++){
524 if (!fFunctions.IsEmpty()){
525 // ffunctions can be TF1 or TFormula depending on how they are created
527 if (obj->IsA() == TFormula::Class() ) {
528 TFormula *f1 = (TFormula*)(obj);
529 fVal[ii]=f1->EvalPar(x)/e;
530 }
531 else if (obj->IsA() == TF1::Class() ) {
532 TF1 *f1 = (TF1*)(obj);
533 fVal[ii]=f1->EvalPar(x)/e;
534 }
535 else {
536 Error("AddToDesign","Basis Function %s is of an invalid type %s",obj->GetName(),obj->IsA()->GetName());
537 return;
538 }
539 } else {
541 if (!f){
542 Error("AddToDesign","Function %s has no linear parts - maybe missing a ++ in the formula expression",fInputFunction->GetName());
543 return;
544 }
545 fVal[ii]=f->EvalPar(x)/e;
546 }
547 }
548 }
549 //additional matrices for numerical stability
550 for (i=0; i<fNfunctions; i++){
551 for (j=0; j<i; j++)
552 fDesignTemp3(j, i)+=fVal[i]*fVal[j];
553 fDesignTemp3(i, i)+=fVal[i]*fVal[i];
554 fAtbTemp3(i)+=fVal[i]*y;
555
556 }
557 fY2Temp+=y*y;
559
560 if (fNpoints % 100 == 0 && fNpoints>100){
564 fAtbTemp3.Zero();
565 if (fNpoints % 10000 == 0 && fNpoints>10000){
569 fAtbTemp2.Zero();
570 fY2+=fY2Temp;
571 fY2Temp=0;
572 if (fNpoints % 1000000 == 0 && fNpoints>1000000){
575 fAtb+=fAtbTemp;
576 fAtbTemp.Zero();
577 }
578 }
579 }
580}
581
582////////////////////////////////////////////////////////////////////////////////
583
604
605////////////////////////////////////////////////////////////////////////////////
606///Clears everything. Used in TH1::Fit and TGraph::Fit().
607
609{
610 fParams.Clear();
612 fTValues.Clear();
613 fParSign.Clear();
614 fDesign.Clear();
618 fAtb.Clear();
619 fAtbTemp.Clear();
623 fInputFunction=nullptr;
624 fY.Clear();
625 fX.Clear();
626 fE.Clear();
627
628 fNpoints=0;
629 fNfunctions=0;
630 fFormulaSize=0;
631 fNdim=0;
632 if (fFormula) delete [] fFormula;
633 fFormula=nullptr;
634 fIsSet=false;
635 if (fFixedParams) delete [] fFixedParams;
636 fFixedParams=nullptr;
637
638 fChisquare=0;
639 fY2=0;
640 fSpecial=0;
643}
644
645////////////////////////////////////////////////////////////////////////////////
646///To be used when different sets of points are fitted with the same formula.
647
649{
650 fDesign.Zero();
651 fAtb.Zero();
655 fAtbTemp.Zero();
656 fAtbTemp2.Zero();
657 fAtbTemp3.Zero();
658
659 fParams.Zero();
660 fParCovar.Zero();
661 fTValues.Zero();
662 fParSign.Zero();
663
664 for (Int_t i=0; i<fNfunctions; i++)
665 fFixedParams[i]=false;
666 fChisquare=0;
667 fNpoints=0;
668
669}
670
671////////////////////////////////////////////////////////////////////////////////
672///Calculates the chisquare.
673
675{
676 Int_t i, j;
678 Double_t temp, temp2;
679
680 if (!fStoreData){
681 sumtotal2 = 0;
682 for (i=0; i<fNfunctions; i++){
683 for (j=0; j<i; j++){
684 sumtotal2 += 2*fParams(i)*fParams(j)*fDesign(j, i);
685 }
686 sumtotal2 += fParams(i)*fParams(i)*fDesign(i, i);
687 sumtotal2 -= 2*fParams(i)*fAtb(i);
688 }
689 sumtotal2 += fY2;
690 } else {
691 sumtotal2 = 0;
692 if (fInputFunction){
693 for (i=0; i<fNpoints; i++){
694 temp = fInputFunction->EvalPar(TMatrixDRow(fX, i).GetPtr());
695 temp2 = (fY(i)-temp)*(fY(i)-temp);
696 temp2 /= fE(i)*fE(i);
697 sumtotal2 += temp2;
698 }
699 } else {
700 sumtotal2 = 0;
701 Double_t val[100];
702 for (Int_t point=0; point<fNpoints; point++){
703 temp = 0;
704 if ((fSpecial>100)&&(fSpecial<200)){
705 Int_t npar = fSpecial-100;
706 val[0] = 1;
707 for (i=1; i<npar; i++)
708 val[i] = val[i-1]*fX(point, 0);
709 for (i=0; i<npar; i++)
710 temp += fParams(i)*val[i];
711 } else {
712 if (fSpecial>200) {
713 //hyperplane case
714 Int_t npar = fSpecial-201;
715 temp+=fParams(0);
716 for (i=0; i<npar; i++)
717 temp += fParams(i+1)*fX(point, i);
718 } else {
719 for (j=0; j<fNfunctions; j++) {
721 val[j] = f1->EvalPar(TMatrixDRow(fX, point).GetPtr());
722 temp += fParams(j)*val[j];
723 }
724 }
725 }
726 temp2 = (fY(point)-temp)*(fY(point)-temp);
727 temp2 /= fE(point)*fE(point);
728 sumtotal2 += temp2;
729 }
730 }
731 }
733
734}
735
736////////////////////////////////////////////////////////////////////////////////
737/// Computes parameters' t-values and significance
738
740{
741 for (Int_t i=0; i<fNfunctions; i++){
742 fTValues(i) = fParams(i)/(TMath::Sqrt(fParCovar(i, i)));
744 }
745}
746
747////////////////////////////////////////////////////////////////////////////////
748/// Perform the fit and evaluate the parameters
749/// Returns 0 if the fit is ok, 1 if there are errors
750
752{
753 Double_t e;
754 if (fFunctions.IsEmpty()&&(!fInputFunction)&&(fSpecial<=200)){
755 Error("TLinearFitter::Eval", "The formula hasn't been set");
756 return 1;
757 }
758 //
763
764 fChisquare=0;
765
766 if (!fIsSet){
768 if (!update){
769 //no points to fit
770 fParams.Zero();
771 fParCovar.Zero();
772 fTValues.Zero();
773 fParSign.Zero();
774 fChisquare=0;
775 if (fInputFunction){
777 for (Int_t i=0; i<fNfunctions; i++)
778 ((TF1*)fInputFunction)->SetParError(i, 0);
779 ((TF1*)fInputFunction)->SetChisquare(0);
780 ((TF1*)fInputFunction)->SetNDF(0);
781 ((TF1*)fInputFunction)->SetNumberFitPoints(0);
782 }
783 return 1;
784 }
785 }
786
788
789//fixing fixed parameters, if there are any
790 Int_t i, ii, j=0;
791 if (fNfixed>0){
792 for (ii=0; ii<fNfunctions; ii++)
794 for (i=0; i<fNfunctions; i++){
795 if (fFixedParams[i]){
796 for (ii=0; ii<i; ii++)
797 fDesignTemp(ii, j) = fDesign(ii, i);
798 for (ii=i; ii<fNfunctions; ii++)
799 fDesignTemp(ii, j) = fDesign(i, ii);
800 j++;
801 for (ii=0; ii<fNfunctions; ii++){
802 fAtb(ii)-=fParams(i)*(fDesignTemp(ii, j-1));
803 }
804 }
805 }
806 for (i=0; i<fNfunctions; i++){
807 if (fFixedParams[i]){
808 for (ii=0; ii<fNfunctions; ii++){
809 fDesign(ii, i) = 0;
810 fDesign(i, ii) = 0;
811 }
812 fDesign (i, i) = 1;
813 fAtb(i) = fParams(i);
814 }
815 }
816 }
817
819 Bool_t ok;
820 TVectorD coef(fNfunctions);
821 coef=chol.Solve(fAtb, ok);
822 if (!ok){
823 Error("Eval","Matrix inversion failed");
824 fParams.Zero();
825 fParCovar.Zero();
826 fTValues.Zero();
827 fParSign.Zero();
828 if (fInputFunction){
831 ((TF1*)fInputFunction)->SetChisquare(0);
833 ((TF1*)fInputFunction)->SetNumberFitPoints(fNpoints);
834 }
835 }
836 return 1;
837 }
838 fParams=coef;
839 fParCovar=chol.Invert();
840
841 if (fInputFunction){
844 for (i=0; i<fNfunctions; i++){
845 e = TMath::Sqrt(fParCovar(i, i));
846 ((TF1*)fInputFunction)->SetParError(i, e);
847 }
848 if (!fObjectFit)
849 ((TF1*)fInputFunction)->SetChisquare(GetChisquare());
851 ((TF1*)fInputFunction)->SetNumberFitPoints(fNpoints);
852 }
853 }
854
855 //if parameters were fixed, change the design matrix back as it was before fixing
856 j = 0;
857 if (fNfixed>0){
858 for (i=0; i<fNfunctions; i++){
859 if (fFixedParams[i]){
860 for (ii=0; ii<i; ii++){
861 fDesign(ii, i) = fDesignTemp(ii, j);
863 }
864 for (ii=i; ii<fNfunctions; ii++){
865 fDesign(i, ii) = fDesignTemp(ii, j);
867 }
868 j++;
869 }
870 }
871 }
872 return 0;
873}
874
875////////////////////////////////////////////////////////////////////////////////
876///Fixes paramter `#ipar` at its current value.
877
879{
880 if (fParams.NonZeros()<1){
881 Error("FixParameter", "no value available to fix the parameter");
882 return;
883 }
884 if (ipar>fNfunctions || ipar<0){
885 Error("FixParameter", "illegal parameter value");
886 return;
887 }
888 if (fNfixed==fNfunctions) {
889 Error("FixParameter", "no free parameters left");
890 return;
891 }
892 if (!fFixedParams)
894 fFixedParams[ipar] = true;
895 fNfixed++;
896}
897
898////////////////////////////////////////////////////////////////////////////////
899///Fixes parameter `#ipar` at value `parvalue`.
900
902{
903 if (ipar>fNfunctions || ipar<0){
904 Error("FixParameter", "illegal parameter value");
905 return;
906 }
907 if (fNfixed==fNfunctions) {
908 Error("FixParameter", "no free parameters left");
909 return;
910 }
911 if(!fFixedParams)
913 fFixedParams[ipar] = true;
916 fParams(ipar) = parvalue;
917 fNfixed++;
918}
919
920////////////////////////////////////////////////////////////////////////////////
921///Releases parameter `#ipar`.
922
924{
925 if (ipar>fNfunctions || ipar<0){
926 Error("ReleaseParameter", "illegal parameter value");
927 return;
928 }
929 if (!fFixedParams[ipar]){
930 Warning("ReleaseParameter","This parameter is not fixed\n");
931 return;
932 } else {
933 fFixedParams[ipar] = false;
934 fNfixed--;
935 }
936}
937
938////////////////////////////////////////////////////////////////////////////////
939///Get the Atb vector - a vector, used for internal computations
940
942{
943 if (v.GetNoElements()!=fAtb.GetNoElements())
944 v.ResizeTo(fAtb.GetNoElements());
945 v = fAtb;
946}
947
948////////////////////////////////////////////////////////////////////////////////
949/// Get the Chisquare.
950
952{
953 if (fChisquare > 1e-16)
954 return fChisquare;
955 else {
956 Chisquare();
957 return fChisquare;
958 }
959}
960
961////////////////////////////////////////////////////////////////////////////////
962///Computes point-by-point confidence intervals for the fitted function
963///Parameters:
964///n - number of points
965///ndim - dimensions of points
966///x - points, at which to compute the intervals, for ndim > 1
967/// should be in order: (x0,y0, x1, y1, ... xn, yn)
968///ci - computed intervals are returned in this array
969///cl - confidence level, default=0.95
970///
971///NOTE, that this method can only be used when the fitting function inherits from a TF1,
972///so it's not possible when the fitting function was set as a string or as a pure TFormula
973
975{
976 if (fInputFunction){
977 Double_t *grad = new Double_t[fNfunctions];
979 Double_t c=0;
981 Double_t t = TMath::StudentQuantile(0.5 + cl/2, df);
983
984 for (Int_t ipoint=0; ipoint<n; ipoint++){
985 c=0;
986 ((TF1*)(fInputFunction))->GradientPar(x+ndim*ipoint, grad);
987 //multiply the covariance matrix by gradient
988 for (Int_t irow=0; irow<fNfunctions; irow++){
989 sum_vector[irow]=0;
990 for (Int_t icol=0; icol<fNfunctions; icol++){
992 }
993 }
994 for (Int_t i=0; i<fNfunctions; i++)
995 c+=grad[i]*sum_vector[i];
996 c=TMath::Sqrt(c);
997 ci[ipoint]=c*t*chidf;
998 }
999
1000 delete [] grad;
1001 delete [] sum_vector;
1002 }
1003}
1004
1005////////////////////////////////////////////////////////////////////////////////
1006///Computes confidence intervals at level cl. Default is 0.95
1007///The TObject parameter can be a TGraphErrors, a TGraph2DErrors or a TH123.
1008///For Graphs, confidence intervals are computed for each point,
1009///the value of the graph at that point is set to the function value at that
1010///point, and the graph y-errors (or z-errors) are set to the value of
1011///the confidence interval at that point
1012///For Histograms, confidence intervals are computed for each bin center
1013///The bin content of this bin is then set to the function value at the bin
1014///center, and the bin error is set to the confidence interval value.
1015///Allowed combinations:
1016///Fitted object Passed object
1017///TGraph TGraphErrors, TH1
1018///TGraphErrors, AsymmErrors TGraphErrors, TH1
1019///TH1 TGraphErrors, TH1
1020///TGraph2D TGraph2DErrors, TH2
1021///TGraph2DErrors TGraph2DErrors, TH2
1022///TH2 TGraph2DErrors, TH2
1023///TH3 TH3
1024
1026{
1027 if (!fInputFunction) {
1028 Error("GetConfidenceIntervals", "The case of fitting not with a TFormula is not yet implemented");
1029 return;
1030 }
1031
1032 //TGraph//////////////////
1033
1034 if (obj->InheritsFrom(TGraph::Class())) {
1035 TGraph *gr = (TGraph*)obj;
1036 if (!gr->GetEY()){
1037 Error("GetConfidenceIntervals", "A TGraphErrors should be passed instead of a graph");
1038 return;
1039 }
1041 Error("GetConfidenceIntervals", "A TGraph2DErrors should be passed instead of a graph");
1042 return;
1043 }
1045 if (((TH1*)(fObjectFit))->GetDimension()>1){
1046 Error("GetConfidenceIntervals", "A TGraph2DErrors or a TH23 should be passed instead of a graph");
1047 return;
1048 }
1049 }
1050
1051 GetConfidenceIntervals(gr->GetN(),1,gr->GetX(), gr->GetEY(), cl);
1052 for (Int_t i=0; i<gr->GetN(); i++)
1053 gr->SetPoint(i, gr->GetX()[i], fInputFunction->Eval(gr->GetX()[i]));
1054 }
1055
1056 //TGraph2D///////////////
1057 else if (obj->InheritsFrom(TGraph2D::Class())) {
1058 TGraph2D *gr2 = (TGraph2D*)obj;
1059 if (!gr2->GetEZ()){
1060 Error("GetConfidenceIntervals", "A TGraph2DErrors should be passed instead of a TGraph2D");
1061 return;
1062 }
1064 Error("GetConfidenceIntervals", "A TGraphErrors should be passed instead of a TGraph2D");
1065 return;
1066 }
1068 if (((TH1*)(fObjectFit))->GetDimension()==1){
1069 Error("GetConfidenceIntervals", "A TGraphErrors or a TH1 should be passed instead of a graph");
1070 return;
1071 }
1072 }
1073 Double_t xy[2];
1074 Int_t np = gr2->GetN();
1075 Double_t *grad = new Double_t[fNfunctions];
1077 Double_t *x = gr2->GetX();
1078 Double_t *y = gr2->GetY();
1079 Double_t t = TMath::StudentQuantile(0.5 + cl/2, ((TF1*)(fInputFunction))->GetNDF());
1081 Double_t c = 0;
1082 for (Int_t ipoint=0; ipoint<np; ipoint++){
1083 c=0;
1084 xy[0]=x[ipoint];
1085 xy[1]=y[ipoint];
1086 ((TF1*)(fInputFunction))->GradientPar(xy, grad);
1087 for (Int_t irow=0; irow<fNfunctions; irow++){
1088 sum_vector[irow]=0;
1089 for (Int_t icol=0; icol<fNfunctions; icol++)
1091 }
1092 for (Int_t i=0; i<fNfunctions; i++)
1093 c+=grad[i]*sum_vector[i];
1094 c=TMath::Sqrt(c);
1095 gr2->SetPoint(ipoint, xy[0], xy[1], fInputFunction->EvalPar(xy));
1096 gr2->GetEZ()[ipoint]=c*t*chidf;
1097 }
1098 delete [] grad;
1099 delete [] sum_vector;
1100 }
1101
1102 //TH1////////////////////////
1103 else if (obj->InheritsFrom(TH1::Class())) {
1105 if (((TH1*)obj)->GetDimension()>1){
1106 Error("GetConfidenceIntervals", "Fitted graph and passed histogram have different number of dimensions");
1107 return;
1108 }
1109 }
1111 if (((TH1*)obj)->GetDimension()!=2){
1112 Error("GetConfidenceIntervals", "Fitted graph and passed histogram have different number of dimensions");
1113 return;
1114 }
1115 }
1117 if (((TH1*)(fObjectFit))->GetDimension()!=((TH1*)(obj))->GetDimension()){
1118 Error("GetConfidenceIntervals", "Fitted and passed histograms have different number of dimensions");
1119 return;
1120 }
1121 }
1122
1123
1124 TH1 *hfit = (TH1*)obj;
1125 Double_t *grad = new Double_t[fNfunctions];
1127 Double_t x[3];
1128 Int_t hxfirst = hfit->GetXaxis()->GetFirst();
1129 Int_t hxlast = hfit->GetXaxis()->GetLast();
1130 Int_t hyfirst = hfit->GetYaxis()->GetFirst();
1131 Int_t hylast = hfit->GetYaxis()->GetLast();
1132 Int_t hzfirst = hfit->GetZaxis()->GetFirst();
1133 Int_t hzlast = hfit->GetZaxis()->GetLast();
1134
1135 TAxis *xaxis = hfit->GetXaxis();
1136 TAxis *yaxis = hfit->GetYaxis();
1137 TAxis *zaxis = hfit->GetZaxis();
1138 Double_t t = TMath::StudentQuantile(0.5 + cl/2, ((TF1*)(fInputFunction))->GetNDF());
1140 Double_t c=0;
1141 for (Int_t binz=hzfirst; binz<=hzlast; binz++){
1142 x[2]=zaxis->GetBinCenter(binz);
1143 for (Int_t biny=hyfirst; biny<=hylast; biny++) {
1144 x[1]=yaxis->GetBinCenter(biny);
1145 for (Int_t binx=hxfirst; binx<=hxlast; binx++) {
1146 x[0]=xaxis->GetBinCenter(binx);
1147 ((TF1*)(fInputFunction))->GradientPar(x, grad);
1148 c=0;
1149 for (Int_t irow=0; irow<fNfunctions; irow++){
1150 sum_vector[irow]=0;
1151 for (Int_t icol=0; icol<fNfunctions; icol++)
1153 }
1154 for (Int_t i=0; i<fNfunctions; i++)
1155 c+=grad[i]*sum_vector[i];
1156 c=TMath::Sqrt(c);
1157 hfit->SetBinContent(binx, biny, binz, fInputFunction->EvalPar(x));
1158 hfit->SetBinError(binx, biny, binz, c*t*chidf);
1159 }
1160 }
1161 }
1162 delete [] grad;
1163 delete [] sum_vector;
1164 }
1165 else {
1166 Error("GetConfidenceIntervals", "This object type is not supported");
1167 return;
1168 }
1169}
1170
1171////////////////////////////////////////////////////////////////////////////////
1172///Returns covariance matrix
1173
1175{
1176 Double_t *p = const_cast<Double_t*>(fParCovar.GetMatrixArray());
1177 return p;
1178}
1179
1180////////////////////////////////////////////////////////////////////////////////
1181///Returns covariance matrix
1182
1184{
1185 if (matr.GetNrows()!=fNfunctions || matr.GetNcols()!=fNfunctions){
1187 }
1188 matr = fParCovar;
1189}
1190
1191////////////////////////////////////////////////////////////////////////////////
1192///Returns the internal design matrix
1193
1195{
1196 if (matr.GetNrows()!=fNfunctions || matr.GetNcols()!=fNfunctions){
1198 }
1199 matr = fDesign;
1200}
1201
1202////////////////////////////////////////////////////////////////////////////////
1203///Returns parameter errors
1204
1206{
1207 if (vpar.GetNoElements()!=fNfunctions) {
1208 vpar.ResizeTo(fNfunctions);
1209 }
1210 for (Int_t i=0; i<fNfunctions; i++)
1211 vpar(i) = TMath::Sqrt(fParCovar(i, i));
1212
1213}
1214
1215////////////////////////////////////////////////////////////////////////////////
1216///Returns parameter values
1217
1219{
1220 if (vpar.GetNoElements()!=fNfunctions) {
1221 vpar.ResizeTo(fNfunctions);
1222 }
1223 vpar=fParams;
1224}
1225
1226////////////////////////////////////////////////////////////////////////////////
1227///Returns the value and the name of the parameter `#ipar`
1228///NB: In the calling function the argument name must be set large enough
1229
1230Int_t TLinearFitter::GetParameter(Int_t ipar,char* name,Double_t& value,Double_t& /*verr*/,Double_t& /*vlow*/, Double_t& /*vhigh*/) const
1231{
1233 Error("GetParError", "illegal value of parameter");
1234 return 0;
1235 }
1236 value = fParams(ipar);
1237 if (fInputFunction)
1239 else
1240 name = nullptr;
1241 return 1;
1242}
1243
1244
1245////////////////////////////////////////////////////////////////////////////////
1246///Returns the error of parameter `#ipar`
1247
1249{
1251 Error("GetParError", "illegal value of parameter");
1252 return 0;
1253 }
1254
1255 return TMath::Sqrt(fParCovar(ipar, ipar));
1256}
1257
1258
1259////////////////////////////////////////////////////////////////////////////////
1260///Returns name of parameter `#ipar`
1261
1262const char *TLinearFitter::GetParName(Int_t ipar) const
1263{
1265 Error("GetParError", "illegal value of parameter");
1266 return nullptr;
1267 }
1268 if (fInputFunction)
1269 return fInputFunction->GetParName(ipar);
1270 return "";
1271}
1272
1273////////////////////////////////////////////////////////////////////////////////
1274///Returns the t-value for parameter `#ipar`
1275
1277{
1279 Error("GetParTValue", "illegal value of parameter");
1280 return 0;
1281 }
1282 if (!fTValues.NonZeros())
1284 return fTValues(ipar);
1285}
1286
1287////////////////////////////////////////////////////////////////////////////////
1288///Returns the significance of parameter `#ipar`
1289
1291{
1293 Error("GetParSignificance", "illegal value of parameter");
1294 return 0;
1295 }
1296 if (!fParSign.NonZeros())
1298 return fParSign(ipar);
1299}
1300
1301////////////////////////////////////////////////////////////////////////////////
1302///For robust lts fitting, returns the sample, on which the best fit was based
1303
1305{
1306 if (!fRobust){
1307 Error("GetFitSample", "there is no fit sample in ordinary least-squares fit");
1308 return;
1309 }
1310 for (Int_t i=0; i<fNpoints; i++)
1312
1313}
1314
1315////////////////////////////////////////////////////////////////////////////////
1316///Merge objects in list
1317
1319{
1320 if (!list) return -1;
1321 TIter next(list);
1322 TLinearFitter *lfit = nullptr;
1323 while ((lfit = (TLinearFitter*)next())) {
1324 if (!lfit->InheritsFrom(TLinearFitter::Class())) {
1325 Error("Add","Attempt to add object of class: %s to a %s",lfit->ClassName(),this->ClassName());
1326 return -1;
1327 }
1328 Add(lfit);
1329 }
1330 return 0;
1331}
1332////////////////////////////////////////////////////////////////////////////////
1333///set the basis functions in case the fitting function is not
1334/// set directly
1335/// The TLinearFitter will manage and delete the functions contained in the list
1336
1338{
1339 fFunctions = *(functions);
1341 int size = fFunctions.GetEntries();
1342
1344 //change the size of design matrix
1353 if (fFixedParams)
1354 delete [] fFixedParams;
1356 fDesign.Zero();
1357 fAtb.Zero();
1358 fDesignTemp.Zero();
1361 fAtbTemp.Zero();
1362 fAtbTemp2.Zero();
1363 fAtbTemp3.Zero();
1364 fY2Temp=0;
1365 fY2=0;
1366 for (int i=0; i<size; i++)
1367 fFixedParams[i]=false;
1368 fIsSet=kFALSE;
1369 fChisquare=0;
1370
1371}
1372
1373
1374////////////////////////////////////////////////////////////////////////////////
1375///set the number of dimensions
1376
1378{
1379 fNdim=ndim;
1380 fY.ResizeTo(ndim+1);
1381 fX.ResizeTo(ndim+1, ndim);
1382 fE.ResizeTo(ndim+1);
1383
1384 fNpoints=0;
1385 fIsSet=kFALSE;
1386}
1387
1388////////////////////////////////////////////////////////////////////////////////
1389///Additive parts should be separated by "++".
1390///Examples (ai are parameters to fit):
1391///1.fitting function: a0*x0 + a1*x1 + a2*x2
1392/// input formula "x[0]++x[1]++x[2]"
1393///2.TMath functions can be used:
1394/// fitting function: a0*TMath::Gaus(x, 0, 1) + a1*y
1395/// input formula: "TMath::Gaus(x, 0, 1)++y"
1396///fills the array of functions
1397
1398void TLinearFitter::SetFormula(const char *formula)
1399{
1400 Int_t size = 0, special = 0;
1401 Int_t i;
1402 //Int_t len = strlen(formula);
1403 if (fInputFunction)
1404 fInputFunction = nullptr;
1405 if (fFormula)
1406 delete [] fFormula;
1407 fFormulaSize = strlen(formula);
1408 fFormula = new char[fFormulaSize+1];
1409 strlcpy(fFormula, formula,fFormulaSize+1);
1410 fSpecial = 0;
1411 //in case of a hyperplane:
1412 char *fstring;
1413 fstring = (char *)strstr(fFormula, "hyp");
1414 if (fstring!=nullptr){
1415 // isHyper = kTRUE;
1416 fstring+=3;
1417 sscanf(fstring, "%d", &size);
1418 //+1 for the constant term
1419 size++;
1420 fSpecial=200+size;
1421 }
1422
1423 if (fSpecial==0) {
1424 //in case it's not a hyperplane
1426 sstring = sstring.ReplaceAll("++", 2, "|", 1);
1428
1429 //count the number of functions
1430
1431 TObjArray *oa = sstring.Tokenize("|");
1432
1433 //change the size of functions array and clear it
1434 if (!fFunctions.IsEmpty())
1435 fFunctions.Clear();
1436
1437 // do not own the functions in this case
1439
1440 fNfunctions = oa->GetEntriesFast();
1442
1443 //check if the old notation of xi is used somewhere instead of x[i]
1444 for (i=0; i<fNdim; i++){
1445 std::string pattern = "x" + std::to_string(i);
1446 std::string replacement = "x[" + std::to_string(i) + "]";
1447 sstring = sstring.ReplaceAll(pattern.c_str(), replacement.c_str());
1448 }
1449
1450 //fill the array of functions
1451 oa = sstring.Tokenize("|");
1452 for (i=0; i<fNfunctions; i++) {
1453 replaceformula = ((TObjString *)oa->UncheckedAt(i))->GetString();
1454 // look first if exists in the map
1455 TFormula * f = nullptr;
1456 auto elem = fgFormulaMap.find(replaceformula );
1457 if (elem != fgFormulaMap.end() )
1458 f = elem->second;
1459 else {
1460 // create a new formula and add in the static map
1461 f = new TFormula("f", replaceformula.Data());
1462 {
1465 }
1466 }
1467 if (!f) {
1468 Error("TLinearFitter", "f_linear not allocated");
1469 return;
1470 }
1471 special=f->GetNumber();
1472 fFunctions.Add(f);
1473 }
1474
1475 if ((fNfunctions==1)&&(special>299)&&(special<310)){
1476 //if fitting a polynomial
1477 size=special-299;
1478 fSpecial=100+size;
1479 } else
1481 oa->Delete();
1482 delete oa;
1483 }
1485 //change the size of design matrix
1494 if (fFixedParams)
1495 delete [] fFixedParams;
1497 fDesign.Zero();
1498 fAtb.Zero();
1499 fDesignTemp.Zero();
1502 fAtbTemp.Zero();
1503 fAtbTemp2.Zero();
1504 fAtbTemp3.Zero();
1505 fY2Temp=0;
1506 fY2=0;
1507 for (i=0; i<size; i++)
1508 fFixedParams[i]=false;
1509 fIsSet=kFALSE;
1510 fChisquare=0;
1511
1512}
1513
1514////////////////////////////////////////////////////////////////////////////////
1515///Set the fitting function.
1516
1518{
1520 fInputFunction=function;
1522 fSpecial = 0;
1524 if (!fFunctions.IsEmpty())
1526
1527 if ((special>299)&&(special<310)){
1528 //if fitting a polynomial
1529 size=special-299;
1530 fSpecial=100+size;
1531 } else
1533
1535 //change the size of design matrix
1540
1543
1546 //
1547 if (fFixedParams)
1548 delete [] fFixedParams;
1550 fDesign.Zero();
1551 fAtb.Zero();
1552 fDesignTemp.Zero();
1553 fAtbTemp.Zero();
1554
1557
1558 fAtbTemp2.Zero();
1559 fAtbTemp3.Zero();
1560 fY2Temp=0;
1561 fY2=0;
1562 for (Int_t i=0; i<size; i++)
1563 fFixedParams[i]=false;
1564 //check if any parameters are fixed (not for pure TFormula)
1565
1566 if (function->InheritsFrom(TF1::Class())){
1567 Double_t al,bl;
1568 for (Int_t i=0;i<fNfunctions;i++) {
1569 ((TF1*)function)->GetParLimits(i,al,bl);
1570 if (al*bl !=0 && al >= bl) {
1571 FixParameter(i, function->GetParameter(i));
1572 }
1573 }
1574 }
1575
1576 fIsSet=kFALSE;
1577 fChisquare=0;
1578
1579}
1580
1581////////////////////////////////////////////////////////////////////////////////
1582///Update the design matrix after the formula has been changed.
1583
1585{
1586 if (fStoreData) {
1587 for (Int_t i=0; i<fNpoints; i++) {
1588 AddToDesign(TMatrixDRow(fX, i).GetPtr(), fY(i), fE(i));
1589 }
1590 return true;
1591 } else
1592 return false;
1593
1594}
1595
1596////////////////////////////////////////////////////////////////////////////////
1597///To use in TGraph::Fit and TH1::Fit().
1598
1600{
1601 if (!strcmp(command, "FitGraph")){
1602 if (args) return GraphLinearFitter(args[0]);
1603 else return GraphLinearFitter(0);
1604 }
1605 if (!strcmp(command, "FitGraph2D")){
1606 if (args) return Graph2DLinearFitter(args[0]);
1607 else return Graph2DLinearFitter(0);
1608 }
1609 if (!strcmp(command, "FitMultiGraph")){
1610 if (args) return MultiGraphLinearFitter(args[0]);
1611 else return MultiGraphLinearFitter(0);
1612 }
1613 if (!strcmp(command, "FitHist")) return HistLinearFitter();
1614// if (!strcmp(command, "FitMultiGraph")) MultiGraphLinearFitter();
1615
1616 return 0;
1617}
1618
1619////////////////////////////////////////////////////////////////////////////////
1620/// Level = 3 (to be consistent with minuit) prints parameters and parameter
1621/// errors.
1622
1623void TLinearFitter::PrintResults(Int_t level, Double_t /*amin*/) const
1624{
1625 if (level==3){
1626 if (!fRobust){
1627 printf("Fitting results:\nParameters:\nNO.\t\tVALUE\t\tERROR\n");
1628 for (Int_t i=0; i<fNfunctions; i++){
1629 printf("%d\t%e\t%e\n", i, fParams(i), TMath::Sqrt(fParCovar(i, i)));
1630 }
1631 } else {
1632 printf("Fitting results:\nParameters:\nNO.\t\tVALUE\n");
1633 for (Int_t i=0; i<fNfunctions; i++){
1634 printf("%d\t%e\n", i, fParams(i));
1635 }
1636 }
1637 }
1638}
1639
1640////////////////////////////////////////////////////////////////////////////////
1641///Used in TGraph::Fit().
1642
1644{
1647 TF1 *f1=(TF1*)GetUserFunc();
1649
1650 //Int_t np=0;
1651 Double_t *x=grr->GetX();
1652 Double_t *y=grr->GetY();
1653 Double_t e;
1654
1655 Int_t fitResult = 0;
1656 //set the fitting formula
1657 SetDim(1);
1659
1660 if (fitOption.Robust){
1661 fRobust=kTRUE;
1663 }
1664 //put the points into the fitter
1665 Int_t n=grr->GetN();
1666 for (Int_t i=0; i<n; i++){
1667 if (!f1->IsInside(&x[i])) continue;
1668 e=grr->GetErrorY(i);
1669 if (e<0 || fitOption.W1)
1670 e=1;
1671 AddPoint(&x[i], y[i], e);
1672 }
1673
1674 if (fitOption.Robust){
1675 return EvalRobust(h);
1676 }
1677
1678 fitResult = Eval();
1679
1680 //calculate the precise chisquare
1681 if (!fitResult){
1682 if (!fitOption.Nochisq){
1683 Double_t temp, temp2, sumtotal=0;
1684 for (Int_t i=0; i<n; i++){
1685 if (!f1->IsInside(&x[i])) continue;
1686 temp=f1->Eval(x[i]);
1687 temp2=(y[i]-temp)*(y[i]-temp);
1688 e=grr->GetErrorY(i);
1689 if (e<0 || fitOption.W1)
1690 e=1;
1691 temp2/=(e*e);
1692
1693 sumtotal+=temp2;
1694 }
1697 }
1698 }
1699 return fitResult;
1700}
1701
1702////////////////////////////////////////////////////////////////////////////////
1703///Minimisation function for a TGraph2D
1704
1706{
1708
1710 TF2 *f2=(TF2*)GetUserFunc();
1711
1713 Int_t n = gr->GetN();
1714 Double_t *gx = gr->GetX();
1715 Double_t *gy = gr->GetY();
1716 Double_t *gz = gr->GetZ();
1717 Double_t x[2];
1718 Double_t z, e;
1719 Int_t fitResult=0;
1720 SetDim(2);
1721 SetFormula(f2->GetFormula());
1722
1723 if (fitOption.Robust){
1724 fRobust=kTRUE;
1726 }
1727
1728 for (Int_t bin=0;bin<n;bin++) {
1729 x[0] = gx[bin];
1730 x[1] = gy[bin];
1731 if (!f2->IsInside(x)) {
1732 continue;
1733 }
1734 z = gz[bin];
1735 e=gr->GetErrorZ(bin);
1736 if (e<0 || fitOption.W1)
1737 e=1;
1738 AddPoint(x, z, e);
1739 }
1740
1741 if (fitOption.Robust){
1742 return EvalRobust(h);
1743 }
1744
1745 fitResult = Eval();
1746
1747 if (!fitResult){
1748 if (!fitOption.Nochisq){
1749 //calculate the precise chisquare
1750 Double_t temp, temp2, sumtotal=0;
1751 for (Int_t bin=0; bin<n; bin++){
1752 x[0] = gx[bin];
1753 x[1] = gy[bin];
1754 if (!f2->IsInside(x)) {
1755 continue;
1756 }
1757 z = gz[bin];
1758
1759 temp=f2->Eval(x[0], x[1]);
1760 temp2=(z-temp)*(z-temp);
1761 e=gr->GetErrorZ(bin);
1762 if (e<0 || fitOption.W1)
1763 e=1;
1764 temp2/=(e*e);
1765
1766 sumtotal+=temp2;
1767 }
1770 }
1771 }
1772 return fitResult;
1773}
1774
1775////////////////////////////////////////////////////////////////////////////////
1776///Minimisation function for a TMultiGraph
1777
1779{
1780 Int_t n, i;
1781 Double_t *gx, *gy;
1782 Double_t e;
1784 TMultiGraph *mg = (TMultiGraph*)grFitter->GetObjectFit();
1785 TF1 *f1 = (TF1*)grFitter->GetUserFunc();
1786 Foption_t fitOption = grFitter->GetFitOption();
1787 Int_t fitResult=0;
1788 SetDim(1);
1789
1790 if (fitOption.Robust){
1791 fRobust=kTRUE;
1793 }
1795
1796 TGraph *gr;
1797 TIter next(mg->GetListOfGraphs());
1798 while ((gr = (TGraph*) next())) {
1799 n = gr->GetN();
1800 gx = gr->GetX();
1801 gy = gr->GetY();
1802 for (i=0; i<n; i++){
1803 if (!f1->IsInside(&gx[i])) continue;
1804 e=gr->GetErrorY(i);
1805 if (e<0 || fitOption.W1)
1806 e=1;
1807 AddPoint(&gx[i], gy[i], e);
1808 }
1809 }
1810
1811 if (fitOption.Robust){
1812 return EvalRobust(h);
1813 }
1814
1815 fitResult = Eval();
1816
1817 //calculate the chisquare
1818 if (!fitResult){
1819 if (!fitOption.Nochisq){
1820 Double_t temp, temp2, sumtotal=0;
1821 next.Reset();
1822 while((gr = (TGraph*)next())) {
1823 n = gr->GetN();
1824 gx = gr->GetX();
1825 gy = gr->GetY();
1826 for (i=0; i<n; i++){
1827 if (!f1->IsInside(&gx[i])) continue;
1828 temp=f1->Eval(gx[i]);
1829 temp2=(gy[i]-temp)*(gy[i]-temp);
1830 e=gr->GetErrorY(i);
1831 if (e<0 || fitOption.W1)
1832 e=1;
1833 temp2/=(e*e);
1834
1835 sumtotal+=temp2;
1836 }
1837
1838 }
1841 }
1842 }
1843 return fitResult;
1844}
1845
1846////////////////////////////////////////////////////////////////////////////////
1847/// Minimization function for H1s using a Chisquare method.
1848
1850{
1852 Double_t cu,eu;
1853 // Double_t dersum[100], grad[100];
1854 Double_t x[3];
1855 Int_t bin,binx,biny,binz;
1856 // Axis_t binlow, binup, binsize;
1857
1858 TH1 *hfit = (TH1*)GetObjectFit();
1859 TF1 *f1 = (TF1*)GetUserFunc();
1860 Int_t fitResult;
1862 //SetDim(hfit->GetDimension());
1863 SetDim(f1->GetNdim());
1865
1867 Int_t hxlast = GetXlast();
1869 Int_t hylast = GetYlast();
1871 Int_t hzlast = GetZlast();
1872 TAxis *xaxis = hfit->GetXaxis();
1873 TAxis *yaxis = hfit->GetYaxis();
1874 TAxis *zaxis = hfit->GetZaxis();
1875
1876 for (binz=hzfirst;binz<=hzlast;binz++) {
1877 x[2] = zaxis->GetBinCenter(binz);
1878 for (biny=hyfirst;biny<=hylast;biny++) {
1879 x[1] = yaxis->GetBinCenter(biny);
1880 for (binx=hxfirst;binx<=hxlast;binx++) {
1881 x[0] = xaxis->GetBinCenter(binx);
1882 if (!f1->IsInside(x)) continue;
1883 bin = hfit->GetBin(binx,biny,binz);
1884 cu = hfit->GetBinContent(bin);
1885 if (f1->GetNdim() < hfit->GetDimension()) {
1886 if (hfit->GetDimension() > 2) cu = x[2];
1887 else cu = x[1];
1888 }
1889 if (fitOption.W1) {
1890 if (fitOption.W1==1 && cu == 0) continue;
1891 eu = 1;
1892 } else {
1893 eu = hfit->GetBinError(bin);
1894 if (eu <= 0) continue;
1895 }
1896 AddPoint(x, cu, eu);
1897 }
1898 }
1899 }
1900
1901 fitResult = Eval();
1902
1903 if (!fitResult){
1904 if (!fitOption.Nochisq){
1905 Double_t temp, temp2, sumtotal=0;
1906 for (binz=hzfirst;binz<=hzlast;binz++) {
1907 x[2] = zaxis->GetBinCenter(binz);
1908 for (biny=hyfirst;biny<=hylast;biny++) {
1909 x[1] = yaxis->GetBinCenter(biny);
1910 for (binx=hxfirst;binx<=hxlast;binx++) {
1911 x[0] = xaxis->GetBinCenter(binx);
1912 if (!f1->IsInside(x)) continue;
1913 bin = hfit->GetBin(binx,biny,binz);
1914 cu = hfit->GetBinContent(bin);
1915
1916 if (fitOption.W1) {
1917 if (fitOption.W1==1 && cu == 0) continue;
1918 eu = 1;
1919 } else {
1920 eu = hfit->GetBinError(bin);
1921 if (eu <= 0) continue;
1922 }
1923 temp=f1->EvalPar(x);
1924 temp2=(cu-temp)*(cu-temp);
1925 temp2/=(eu*eu);
1926 sumtotal+=temp2;
1927 }
1928 }
1929 }
1930
1933 }
1934 }
1935 return fitResult;
1936}
1937
1938////////////////////////////////////////////////////////////////////////////////
1939
1941{
1942 if (R__b.IsReading()) {
1944 R__b.ReadClassBuffer(TLinearFitter::Class(),this);
1945 if (old_matr_size < fNfunctions) {
1948
1951
1954 }
1955 } else {
1956 if (fAtb.NonZeros()==0) AddTempMatrices();
1957 R__b.WriteClassBuffer(TLinearFitter::Class(),this);
1958 }
1959}
1960
1961////////////////////////////////////////////////////////////////////////////////
1962///Finds the parameters of the fitted function in case data contains
1963///outliers.
1964///Parameter h stands for the minimal fraction of good points in the
1965///dataset (h < 1, i.e. for 70% of good points take h=0.7).
1966///The default value of h*Npoints is (Npoints + Nparameters+1)/2
1967///If the user provides a value of h smaller than above, default is taken
1968///See class description for the algorithm details
1969
1971{
1972 fRobust = kTRUE;
1973 Double_t kEps = 1e-13;
1974 Int_t nmini = 300;
1975 Int_t i, j, maxind=0, k, k1 = 500;
1976 Int_t nbest = 10;
1977 Double_t chi2 = -1;
1978
1979 if (fFunctions.IsEmpty()&&(!fInputFunction)&&(fSpecial<=200)){
1980 Error("TLinearFitter::EvalRobust", "The formula hasn't been set");
1981 return 1;
1982 }
1983
1984
1986 for (i=0; i<nbest; i++)
1987 bestchi2[i]=1e30;
1988
1990
1991 if (h>0.000001 && h<1 && fNpoints*h > hdef)
1992 fH = Int_t(fNpoints*h);
1993 else {
1994 // print message only when h is not zero
1995 if (h>0) Warning("Fitting:", "illegal value of H, default is taken, h = %3.2f",double(hdef)/fNpoints);
1996 fH=hdef;
1997 }
1998
2002
2003 Int_t *index = new Int_t[fNpoints];
2005
2006 if (fNpoints < 2*nmini) {
2007 //when number of cases is small
2008
2009 //to store the best coefficients (columnwise)
2011 for (k = 0; k < k1; k++) {
2013 chi2 = CStep(1, fH, residuals,index, index, -1, -1);
2014 chi2 = CStep(2, fH, residuals,index, index, -1, -1);
2016 if (chi2 < bestchi2[maxind]) {
2017 bestchi2[maxind] = chi2;
2018 for (i=0; i<fNfunctions; i++)
2019 cstock(i, maxind) = fParams(i);
2020 }
2021 }
2022
2023 //for the nbest best results, perform CSteps until convergence
2024 Int_t *bestindex = new Int_t[fH];
2026 for (i=0; i<nbest; i++) {
2027 for (j=0; j<fNfunctions; j++)
2028 fParams(j) = cstock(j, i);
2029 chi2 = 1;
2030 while (chi2 > kEps) {
2031 chi2 = CStep(2, fH, residuals,index, index, -1, -1);
2032 if (TMath::Abs(chi2 - bestchi2[i]) < kEps)
2033 break;
2034 else
2035 bestchi2[i] = chi2;
2036 }
2038 if (chi2 <= currentbest + kEps) {
2039 for (j=0; j<fH; j++){
2040 bestindex[j]=index[j];
2041 }
2042 maxind = i;
2043 }
2044 for (j=0; j<fNfunctions; j++)
2045 cstock(j, i) = fParams(j);
2046 }
2047 //report the result with the lowest chisquare
2048 for (j=0; j<fNfunctions; j++)
2049 fParams(j) = cstock(j, maxind);
2051 for (j=0; j<fH; j++){
2052 //printf("bestindex[%d]=%d\n", j, bestindex[j]);
2054 }
2056 ((TF1*)fInputFunction)->SetChisquare(bestchi2[maxind]);
2057 ((TF1*)fInputFunction)->SetNumberFitPoints(fH);
2058 ((TF1*)fInputFunction)->SetNDF(fH-fNfunctions);
2059 }
2060 delete [] index;
2061 delete [] bestindex;
2062 delete [] residuals;
2063 delete [] bestchi2;
2064 return 0;
2065 }
2066 //if n is large, the dataset should be partitioned
2067 Int_t indsubdat[5];
2068 for (i=0; i<5; i++)
2069 indsubdat[i] = 0;
2070
2072 Int_t hsub;
2073
2075
2076 Int_t *subdat = new Int_t[sum]; //to store the indices of selected cases
2078
2080 Int_t *beststock = new Int_t[nbest];
2081 Int_t i_start = 0;
2082 Int_t i_end = indsubdat[0];
2083 Int_t k2 = Int_t(k1/nsub);
2084 for (Int_t kgroup = 0; kgroup < nsub; kgroup++) {
2085
2087 for (i=0; i<nbest; i++)
2088 bestchi2[i] = 1e16;
2089 for (k=0; k<k2; k++) {
2094 if (chi2 < bestchi2[maxind]){
2095 for (i=0; i<fNfunctions; i++)
2096 cstockbig(i, nbest*kgroup + maxind) = fParams(i);
2097 bestchi2[maxind] = chi2;
2098 }
2099 }
2100 if (kgroup != nsub - 1){
2102 i_end += indsubdat[kgroup+1];
2103 }
2104 }
2105
2106 for (i=0; i<nbest; i++)
2107 bestchi2[i] = 1e30;
2108 //on the pooled subset
2110 for (k=0; k<nbest*5; k++) {
2111 for (i=0; i<fNfunctions; i++)
2112 fParams(i)=cstockbig(i, k);
2113 chi2 = CStep(1, hsub2, residuals, index, subdat, 0, sum);
2114 chi2 = CStep(2, hsub2, residuals, index, subdat, 0, sum);
2116 if (chi2 < bestchi2[maxind]){
2117 beststock[maxind] = k;
2118 bestchi2[maxind] = chi2;
2119 }
2120 }
2121
2122 //now the array beststock keeps indices of 10 best candidates in cstockbig matrix
2123 for (k=0; k<nbest; k++) {
2124 for (i=0; i<fNfunctions; i++)
2125 fParams(i) = cstockbig(i, beststock[k]);
2126 chi2 = CStep(1, fH, residuals, index, index, -1, -1);
2127 chi2 = CStep(2, fH, residuals, index, index, -1, -1);
2128 bestchi2[k] = chi2;
2129 }
2130
2132 for (i=0; i<fNfunctions; i++)
2134
2135 chi2 = 1;
2136 while (chi2 > kEps) {
2137 chi2 = CStep(2, fH, residuals, index, index, -1, -1);
2139 break;
2140 else
2141 bestchi2[maxind] = chi2;
2142 }
2143
2145 for (j=0; j<fH; j++)
2147 if (fInputFunction){
2148 ((TF1*)fInputFunction)->SetChisquare(bestchi2[maxind]);
2149 ((TF1*)fInputFunction)->SetNumberFitPoints(fH);
2150 ((TF1*)fInputFunction)->SetNDF(fH-fNfunctions);
2151 }
2152
2153 delete [] subdat;
2154 delete [] beststock;
2155 delete [] bestchi2;
2156 delete [] residuals;
2157 delete [] index;
2158
2159 return 0;
2160}
2161
2162////////////////////////////////////////////////////////////////////////////////
2163///Creates a p-subset to start
2164///ntotal - total number of points from which the subset is chosen
2165
2167{
2168 Int_t i, j;
2170 Int_t nindex=0;
2171 Int_t num;
2172 for(i=0; i<ntotal; i++)
2173 index[i] = ntotal+1;
2174
2175 TRandom2 r;
2176 //create a p-subset
2177 for (i=0; i<fNfunctions; i++) {
2178 num=Int_t(r.Uniform(0, 1)*(ntotal-1));
2179 if (i>0){
2180 for(j=0; j<=i-1; j++) {
2181 if(index[j]==num)
2182 repeat = kTRUE;
2183 }
2184 }
2185 if(repeat==kTRUE) {
2186 i--;
2187 repeat = kFALSE;
2188 } else {
2189 index[i] = num;
2190 nindex++;
2191 }
2192 }
2193
2194 //compute the coefficients of a hyperplane through the p-subset
2195 fDesign.Zero();
2196 fAtb.Zero();
2197 for (i=0; i<fNfunctions; i++){
2198 AddToDesign(TMatrixDRow(fX, index[i]).GetPtr(), fY(index[i]), fE(index[i]));
2199 }
2200 Bool_t ok;
2201
2202 ok = Linf();
2203
2204 //if the chosen points don't define a hyperplane, add more
2205 while (!ok && (nindex < h)) {
2206 repeat=kFALSE;
2207 do{
2208 num=Int_t(r.Uniform(0,1)*(ntotal-1));
2209 repeat=kFALSE;
2210 for(i=0; i<nindex; i++) {
2211 if(index[i]==num) {
2212 repeat=kTRUE;
2213 break;
2214 }
2215 }
2216 } while(repeat==kTRUE);
2217
2218 index[nindex] = num;
2219 nindex++;
2220 //check if the system is of full rank now
2221 AddToDesign(TMatrixDRow(fX, index[nindex-1]).GetPtr(), fY(index[nindex-1]), fE(index[nindex-1]));
2222 ok = Linf();
2223 }
2224}
2225
2226////////////////////////////////////////////////////////////////////////////////
2227///The CStep procedure, as described in the article
2228
2230{
2232
2233 Int_t i, j, itemp, n;
2234 Double_t func;
2235 Double_t val[100];
2236 Int_t npar;
2237 if (start > -1) {
2238 n = end - start;
2239 for (i=0; i<n; i++) {
2240 func = 0;
2241 itemp = subdat[start+i];
2242 if (fInputFunction){
2244 func=fInputFunction->EvalPar(TMatrixDRow(fX, itemp).GetPtr());
2245 } else {
2246 func=0;
2247 if ((fSpecial>100)&&(fSpecial<200)){
2248 npar = fSpecial-100;
2249 val[0] = 1;
2250 for (j=1; j<npar; j++)
2251 val[j] = val[j-1]*fX(itemp, 0);
2252 for (j=0; j<npar; j++)
2253 func += fParams(j)*val[j];
2254 } else if (fSpecial>200) {
2255 //hyperplane case
2256 npar = fSpecial-201;
2257 func+=fParams(0);
2258 for (j=0; j<npar; j++)
2259 func += fParams(j+1)*fX(itemp, j);
2260 } else {
2261 // general case
2262 for (j=0; j<fNfunctions; j++) {
2263 TF1 *f1 = (TF1*)(fFunctions.UncheckedAt(j));
2264 val[j] = f1->EvalPar(TMatrixDRow(fX, itemp).GetPtr());
2265 func += fParams(j)*val[j];
2266 }
2267 }
2268 }
2269 residuals[i] = (fY(itemp) - func)*(fY(itemp) - func)/(fE(i)*fE(i));
2270 }
2271 } else {
2272 n=fNpoints;
2273 for (i=0; i<fNpoints; i++) {
2274 func = 0;
2275 if (fInputFunction){
2277 func=fInputFunction->EvalPar(TMatrixDRow(fX, i).GetPtr());
2278 } else {
2279 func=0;
2280 if ((fSpecial>100)&&(fSpecial<200)){
2281 npar = fSpecial-100;
2282 val[0] = 1;
2283 for (j=1; j<npar; j++)
2284 val[j] = val[j-1]*fX(i, 0);
2285 for (j=0; j<npar; j++)
2286 func += fParams(j)*val[j];
2287 } else if (fSpecial>200) {
2288 //hyperplane case
2289 npar = fSpecial-201;
2290 func+=fParams(0);
2291 for (j=0; j<npar; j++)
2292 func += fParams(j+1)*fX(i, j);
2293 } else {
2294 for (j=0; j<fNfunctions; j++) {
2295 TF1 *f1 = (TF1*)(fFunctions.UncheckedAt(j));
2296 val[j] = f1->EvalPar(TMatrixDRow(fX, i).GetPtr());
2297 func += fParams(j)*val[j];
2298 }
2299 }
2300 }
2301 residuals[i] = (fY(i) - func)*(fY(i) - func)/(fE(i)*fE(i));
2302 }
2303 }
2304 //take h with smallest residuals
2306 //add them to the design matrix
2307 fDesign.Zero();
2308 fAtb.Zero();
2309 for (i=0; i<h; i++)
2310 AddToDesign(TMatrixDRow(fX, index[i]).GetPtr(), fY(index[i]), fE(index[i]));
2311
2312 Linf();
2313
2314 //don't calculate the chisquare at the 1st cstep
2315 if (step==1) return 0;
2316 Double_t sum=0;
2317
2318
2319 if (start > -1) {
2320 for (i=0; i<h; i++) {
2321 itemp = subdat[start+index[i]];
2322 if (fInputFunction){
2324 func=fInputFunction->EvalPar(TMatrixDRow(fX, itemp).GetPtr());
2325 } else {
2326 func=0;
2327 if ((fSpecial>100)&&(fSpecial<200)){
2328 npar = fSpecial-100;
2329 val[0] = 1;
2330 for (j=1; j<npar; j++)
2331 val[j] = val[j-1]*fX(itemp, 0);
2332 for (j=0; j<npar; j++)
2333 func += fParams(j)*val[j];
2334 } else if (fSpecial>200) {
2335 //hyperplane case
2336 npar = fSpecial-201;
2337 func+=fParams(0);
2338 for (j=0; j<npar; j++)
2339 func += fParams(j+1)*fX(itemp, j);
2340 } else {
2341 for (j=0; j<fNfunctions; j++) {
2342 TF1 *f1 = (TF1*)(fFunctions.UncheckedAt(j));
2343 val[j] = f1->EvalPar(TMatrixDRow(fX, itemp).GetPtr());
2344 func += fParams(j)*val[j];
2345 }
2346 }
2347 }
2348 sum+=(fY(itemp)-func)*(fY(itemp)-func)/(fE(itemp)*fE(itemp));
2349 }
2350 } else {
2351 for (i=0; i<h; i++) {
2352 if (fInputFunction){
2354 func=fInputFunction->EvalPar(TMatrixDRow(fX, index[i]).GetPtr());
2355 } else {
2356 func=0;
2357 if ((fSpecial>100)&&(fSpecial<200)){
2358 npar = fSpecial-100;
2359 val[0] = 1;
2360 for (j=1; j<npar; j++)
2361 val[j] = val[j-1]*fX(index[i], 0);
2362 for (j=0; j<npar; j++)
2363 func += fParams(j)*val[j];
2364 } else {
2365 if (fSpecial>200) {
2366 //hyperplane case
2367 npar = fSpecial-201;
2368 func+=fParams(0);
2369 for (j=0; j<npar; j++)
2370 func += fParams(j+1)*fX(index[i], j);
2371 } else {
2372 for (j=0; j<fNfunctions; j++) {
2373 TF1 *f1 = (TF1*)(fFunctions.UncheckedAt(j));
2374 val[j] = f1->EvalPar(TMatrixDRow(fX, index[i]).GetPtr());
2375 func += fParams(j)*val[j];
2376 }
2377 }
2378 }
2379 }
2380
2381 sum+=(fY(index[i])-func)*(fY(index[i])-func)/(fE(index[i])*fE(index[i]));
2382 }
2383 }
2384
2385 return sum;
2386}
2387
2388////////////////////////////////////////////////////////////////////////////////
2389
2391{
2392 //currently without the intercept term
2398 fDesignTemp.Zero();
2401 fAtb+=fAtbTemp;
2402 fAtbTemp3.Zero();
2403 fAtbTemp2.Zero();
2404 fAtbTemp.Zero();
2405
2406 fY2+=fY2Temp;
2407 fY2Temp=0;
2408
2409
2411 TVectorD temp(fNfunctions);
2412 Bool_t ok;
2413 temp = chol.Solve(fAtb, ok);
2414 if (!ok){
2415 Error("Linf","Matrix inversion failed");
2416 //fDesign.Print();
2417 fParams.Zero();
2418 return kFALSE;
2419 }
2420 fParams = temp;
2421 return ok;
2422}
2423
2424////////////////////////////////////////////////////////////////////////////////
2425///divides the elements into approximately equal subgroups
2426///number of elements in each subgroup is stored in indsubdat
2427///number of subgroups is returned
2428
2430{
2431 Int_t nsub;
2432
2433 if ((fNpoints>=2*nmini) && (fNpoints<=(3*nmini-1))) {
2434 if (fNpoints%2==1){
2435 indsubdat[0]=Int_t(fNpoints*0.5);
2436 indsubdat[1]=Int_t(fNpoints*0.5)+1;
2437 } else
2439 nsub=2;
2440 }
2441 else{
2442 if((fNpoints>=3*nmini) && (fNpoints<(4*nmini -1))) {
2443 if(fNpoints%3==0){
2445 } else {
2446 indsubdat[0]=Int_t(fNpoints/3);
2447 indsubdat[1]=Int_t(fNpoints/3)+1;
2448 if (fNpoints%3==1) indsubdat[2]=Int_t(fNpoints/3);
2449 else indsubdat[2]=Int_t(fNpoints/3)+1;
2450 }
2451 nsub=3;
2452 }
2453 else{
2454 if((fNpoints>=4*nmini)&&(fNpoints<=(5*nmini-1))){
2455 if (fNpoints%4==0) indsubdat[0]=indsubdat[1]=indsubdat[2]=indsubdat[3]=Int_t(fNpoints/4);
2456 else {
2457 indsubdat[0]=Int_t(fNpoints/4);
2458 indsubdat[1]=Int_t(fNpoints/4)+1;
2459 if(fNpoints%4==1) indsubdat[2]=indsubdat[3]=Int_t(fNpoints/4);
2460 if(fNpoints%4==2) {
2461 indsubdat[2]=Int_t(fNpoints/4)+1;
2462 indsubdat[3]=Int_t(fNpoints/4);
2463 }
2464 if(fNpoints%4==3) indsubdat[2]=indsubdat[3]=Int_t(fNpoints/4)+1;
2465 }
2466 nsub=4;
2467 } else {
2468 for(Int_t i=0; i<5; i++)
2469 indsubdat[i]=nmini;
2470 nsub=5;
2471 }
2472 }
2473 }
2474 return nsub;
2475}
2476
2477////////////////////////////////////////////////////////////////////////////////
2478///Draws ngroup nonoverlapping subdatasets out of a dataset of size n
2479///such that the selected case numbers are uniformly distributed from 1 to n
2480
2482{
2483 Int_t jndex = 0;
2484 Int_t nrand;
2485 Int_t i, k, m, j;
2486 Int_t ngroup=0;
2487 for (i=0; i<5; i++) {
2488 if (indsubdat[i]!=0)
2489 ngroup++;
2490 }
2491 TRandom r;
2492 for (k=1; k<=ngroup; k++) {
2493 for (m=1; m<=indsubdat[k-1]; m++) {
2494 nrand = Int_t(r.Uniform(0, 1) * (fNpoints-jndex)) + 1;
2495 jndex++;
2496 if (jndex==1) {
2497 subdat[0] = nrand;
2498 } else {
2499 subdat[jndex-1] = nrand + jndex - 2;
2500 for (i=1; i<=jndex-1; i++) {
2501 if(subdat[i-1] > nrand+i-2) {
2502 for(j=jndex; j>=i+1; j--) {
2503 subdat[j-1] = subdat[j-2];
2504 }
2505 subdat[i-1] = nrand+i-2;
2506 break; //breaking the loop for(i=1...
2507 }
2508 }
2509 }
2510 }
2511 }
2512}
2513
2514
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
static void update(gsl_integration_workspace *workspace, double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition RtypesCore.h:45
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:374
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t np
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint xy
char name[80]
Definition TGX11.cxx:110
TMatrixTRow< Double_t > TMatrixDRow
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define R__LOCKGUARD(mutex)
const_iterator end() const
Class to manage histogram axis.
Definition TAxis.h:32
Container of bits.
Definition TBits.h:26
void Clear(Option_t *option="") override
Clear the value.
Definition TBits.cxx:84
Bool_t TestBitNumber(UInt_t bitnumber) const
Definition TBits.h:222
void SetBitNumber(UInt_t bitnumber, Bool_t value=kTRUE)
Definition TBits.h:206
Buffer base class used for serializing objects.
Definition TBuffer.h:43
Collection abstract base class.
Definition TCollection.h:65
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Cholesky Decomposition class.
Definition TDecompChol.h:25
1-Dim function class
Definition TF1.h:233
static TClass * Class()
virtual void SetChisquare(Double_t chi2)
Definition TF1.h:640
virtual TFormula * GetFormula()
Definition TF1.h:481
virtual Double_t EvalPar(const Double_t *x, const Double_t *params=nullptr)
Evaluate function with given coordinates and parameters.
Definition TF1.cxx:1468
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
Evaluate this function.
Definition TF1.cxx:1439
virtual Bool_t IsInside(const Double_t *x) const
return kTRUE if the point is inside the function range
Definition TF1.h:626
virtual Int_t GetNdim() const
Definition TF1.h:513
A 2-Dim function with parameters.
Definition TF2.h:29
Bool_t IsInside(const Double_t *x) const override
Return kTRUE is the point is inside the function range.
Definition TF2.cxx:685
The Formula class.
Definition TFormula.h:89
const TObject * GetLinearPart(Int_t i) const
Return linear part.
Double_t Eval(Args... args) const
Set first 1, 2, 3 or 4 variables (e.g.
Definition TFormula.h:324
static TClass * Class()
const char * GetParName(Int_t ipar) const
Return parameter name given by integer.
Int_t GetNumber() const
Definition TFormula.h:261
void SetParameters(const Double_t *params)
Set a vector of parameters value.
Int_t GetNpar() const
Definition TFormula.h:260
Double_t EvalPar(const Double_t *x, const Double_t *params=nullptr) const
Graphics object made of three arrays X, Y and Z with the same number of points each.
Definition TGraph2D.h:41
static TClass * Class()
Double_t GetErrorY(Int_t bin) const override
It returns the error along Y at point i.
Double_t * GetEY() const override
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
static TClass * Class()
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Set x and y values for point number i.
Definition TGraph.cxx:2337
Double_t * GetY() const
Definition TGraph.h:140
Int_t GetN() const
Definition TGraph.h:132
Double_t * GetX() const
Definition TGraph.h:139
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:59
static TClass * Class()
void Reset()
virtual void AddTempMatrices()
TMatrixDSym fDesignTemp2
temporary matrix, used for num.stability
Int_t GraphLinearFitter(Double_t h)
Used in TGraph::Fit().
~TLinearFitter() override
Linear fitter cleanup.
TMatrixDSym fDesignTemp
virtual Double_t GetChisquare()
Get the Chisquare.
Int_t Partition(Int_t nmini, Int_t *indsubdat)
divides the elements into approximately equal subgroups number of elements in each subgroup is stored...
virtual void GetErrors(TVectorD &vpar)
Returns parameter errors.
Double_t CStep(Int_t step, Int_t h, Double_t *residuals, Int_t *index, Int_t *subdat, Int_t start, Int_t end)
The CStep procedure, as described in the article.
virtual Int_t Merge(TCollection *list)
Merge objects in list.
Double_t fChisquare
void ComputeTValues()
Computes parameters' t-values and significance.
Bool_t * fFixedParams
TVectorD fParSign
void Clear(Option_t *option="") override
Clears everything. Used in TH1::Fit and TGraph::Fit().
TLinearFitter()
default c-tor, input data is stored If you don't want to store the input data, run the function Store...
const char * GetParName(Int_t ipar) const override
Returns name of parameter #ipar
Int_t MultiGraphLinearFitter(Double_t h)
Minimisation function for a TMultiGraph.
virtual Double_t GetParSignificance(Int_t ipar)
Returns the significance of parameter #ipar
TMatrixDSym fDesign
virtual Int_t Eval()
Perform the fit and evaluate the parameters Returns 0 if the fit is ok, 1 if there are errors.
TVectorD fAtbTemp2
temporary vector, used for num.stability
void PrintResults(Int_t level, Double_t amin=0) const override
Level = 3 (to be consistent with minuit) prints parameters and parameter errors.
Int_t HistLinearFitter()
Minimization function for H1s using a Chisquare method.
Int_t Graph2DLinearFitter(Double_t h)
Minimisation function for a TGraph2D.
static TClass * Class()
TVectorD fAtbTemp
virtual void ClearPoints()
To be used when different sets of points are fitted with the same formula.
TMatrixDSym fDesignTemp3
TObjArray fFunctions
map of basis functions and formula
Int_t ExecuteCommand(const char *command, Double_t *args, Int_t nargs) override
To use in TGraph::Fit and TH1::Fit().
virtual void GetFitSample(TBits &bits)
For robust lts fitting, returns the sample, on which the best fit was based.
virtual void Add(TLinearFitter *tlf)
Add another linear fitter to this linear fitter.
virtual void GetDesignMatrix(TMatrixD &matr)
Returns the internal design matrix.
void Streamer(TBuffer &) override
Stream an object of class TObject.
virtual void AssignData(Int_t npoints, Int_t xncols, Double_t *x, Double_t *y, Double_t *e=nullptr)
This function is to use when you already have all the data in arrays and don't want to copy them into...
virtual void GetParameters(TVectorD &vpar)
Returns parameter values.
void RDraw(Int_t *subdat, Int_t *indsubdat)
Draws ngroup nonoverlapping subdatasets out of a dataset of size n such that the selected case number...
static std::map< TString, TFormula * > fgFormulaMap
virtual void SetDim(Int_t n)
set the number of dimensions
TFormula * fInputFunction
void GetConfidenceIntervals(Int_t n, Int_t ndim, const Double_t *x, Double_t *ci, Double_t cl=0.95) override
Computes point-by-point confidence intervals for the fitted function Parameters: n - number of points...
TMatrixD fX
temporary variable used for num.stability
virtual Bool_t UpdateMatrix()
Update the design matrix after the formula has been changed.
virtual void GetAtbVector(TVectorD &v)
Get the Atb vector - a vector, used for internal computations.
virtual void Chisquare()
Calculates the chisquare.
virtual void SetBasisFunctions(TObjArray *functions)
set the basis functions in case the fitting function is not set directly The TLinearFitter will manag...
Int_t fNpoints
temporary
Double_t fVal[1000]
virtual Int_t EvalRobust(Double_t h=-1)
Finds the parameters of the fitted function in case data contains outliers.
TVectorD fTValues
Double_t GetParError(Int_t ipar) const override
Returns the error of parameter #ipar
void AddToDesign(Double_t *x, Double_t y, Double_t e)
Add a point to the AtA matrix and to the Atb vector.
TVectorD fAtbTemp3
void FixParameter(Int_t ipar) override
Fixes paramter #ipar at its current value.
void CreateSubset(Int_t ntotal, Int_t h, Int_t *index)
Creates a p-subset to start ntotal - total number of points from which the subset is chosen.
virtual void SetFormula(const char *formula)
Additive parts should be separated by "++".
void ReleaseParameter(Int_t ipar) override
Releases parameter #ipar.
virtual void AddPoint(Double_t *x, Double_t y, Double_t e=1)
Adds 1 point to the fitter.
TMatrixDSym fParCovar
virtual Double_t GetParTValue(Int_t ipar)
Returns the t-value for parameter #ipar
Double_t * GetCovarianceMatrix() const override
Returns covariance matrix.
Double_t GetParameter(Int_t ipar) const override
virtual void StoreData(Bool_t store)
Int_t GetNrows() const
virtual TMatrixTBase< Element > & Zero()
Set matrix elements to zero.
Int_t GetNcols() const
TMatrixTBase< Element > & ResizeTo(Int_t nrows, Int_t ncols, Int_t=-1) override
Set size of the matrix to nrows x ncols New dynamic elements are created, the overlapping part of the...
void Clear(Option_t *="") override
Definition TMatrixTSym.h:96
const Element * GetMatrixArray() const override
TMatrixT< Element > & Use(Int_t row_lwb, Int_t row_upb, Int_t col_lwb, Int_t col_upb, Element *data)
Use the array data to fill the matrix ([row_lwb..row_upb] x [col_lwb..col_upb])
void Clear(Option_t *="") override
Definition TMatrixT.h:123
const Element * GetMatrixArray() const override
Definition TMatrixT.h:228
TMatrixTBase< Element > & ResizeTo(Int_t nrows, Int_t ncols, Int_t=-1) override
Set size of the matrix to nrows x ncols New dynamic elements are created, the overlapping part of the...
A TMultiGraph is a collection of TGraph (or derived) objects.
Definition TMultiGraph.h:34
TList * GetListOfGraphs() const
Definition TMultiGraph.h:68
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
void Clear(Option_t *option="") override
Remove all objects from the array.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
Bool_t IsEmpty() const override
Definition TObjArray.h:65
void Add(TObject *obj) override
Definition TObjArray.h:68
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:456
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1006
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:542
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1020
virtual TClass * IsA() const
Definition TObject.h:245
Random number generator class based on the maximally quidistributed combined Tausworthe generator by ...
Definition TRandom2.h:27
This is the base class for the ROOT Random number generators.
Definition TRandom.h:27
Basic string class.
Definition TString.h:139
TVectorT< Element > & Zero()
Set vector elements to zero.
Definition TVectorT.cxx:453
TVectorT< Element > & ResizeTo(Int_t lwb, Int_t upb)
Resize the vector to [lwb:upb] .
Definition TVectorT.cxx:294
TVectorT< Element > & Use(Int_t lwb, Int_t upb, Element *data)
Use the array data to fill the vector lwb..upb].
Definition TVectorT.cxx:349
void Clear(Option_t *="") override
Definition TVectorT.h:194
Int_t NonZeros() const
Compute the number of elements != 0.0.
Definition TVectorT.cxx:620
Int_t GetNoElements() const
Definition TVectorT.h:76
Element * GetMatrixArray()
Definition TVectorT.h:78
Abstract Base Class for Fitting.
virtual Int_t GetXlast() const
virtual Int_t GetYfirst() const
virtual TObject * GetObjectFit() const
virtual Foption_t GetFitOption() const
virtual Int_t GetZfirst() const
virtual Int_t GetZlast() const
virtual Int_t GetXfirst() const
TObject * fObjectFit
Pointer to object being fitted.
virtual Int_t GetYlast() const
static TVirtualFitter * GetFitter()
static: return the current Fitter
virtual TObject * GetUserFunc() const
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TGraphErrors * gr
Definition legend1.C:25
TF1 * f1
Definition legend1.C:11
Element KOrdStat(Size n, const Element *a, Size k, Size *work=0)
Returns k_th order statistic of the array a of size n (k_th smallest element out of n elements).
Definition TMath.h:1439
Long64_t LocMin(Long64_t n, const T *a)
Returns index of array with the minimum element.
Definition TMath.h:986
T MinElement(Long64_t n, const T *a)
Returns minimum of array a of length n.
Definition TMath.h:964
Long64_t LocMax(Long64_t n, const T *a)
Returns index of array with the maximum element.
Definition TMath.h:1092
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:666
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:198
Double_t StudentI(Double_t T, Double_t ndf)
Calculates the cumulative distribution function of Student's t-distribution second parameter stands f...
Definition TMath.cxx:2645
Double_t StudentQuantile(Double_t p, Double_t ndf, Bool_t lower_tail=kTRUE)
Computes quantiles of the Student's t-distribution 1st argument is the probability,...
Definition TMath.cxx:2673
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:123
TMarker m
Definition textangle.C:8
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345