Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TLinearMinimizer.cxx
Go to the documentation of this file.
1 // @(#)root/minuit:$Id$
2 // Author: L. Moneta Wed Oct 25 16:28:55 2006
3 
4 /**********************************************************************
5  * *
6  * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7  * *
8  * *
9  **********************************************************************/
10 
11 // Implementation file for class TLinearMinimizer
12 
13 #include "TLinearMinimizer.h"
14 #include "Math/IParamFunction.h"
15 #include "TF1.h"
16 #include "TUUID.h"
17 #include "TROOT.h"
18 #include "Fit/BasicFCN.h"
19 #include "Fit/BinData.h"
20 #include "Fit/Chi2FCN.h"
21 
22 #include "TLinearFitter.h"
23 #include "TVirtualMutex.h"
24 
25 #include <iostream>
26 #include <cassert>
27 #include <algorithm>
28 #include <functional>
29 
30 
31 
32 // namespace ROOT {
33 
34 // namespace Fit {
35 
36 
37 // structure used for creating the TF1 representing the basis functions
38 // they are the derivatives w.r.t the parameters of the model function
39 template<class Func>
40 struct BasisFunction {
41  BasisFunction(const Func & f, int k) :
42  fKPar(k),
43  fFunc(&f)
44  {}
45 
46  double operator() ( double * x, double *) {
47  return fFunc->ParameterDerivative(x,fKPar);
48  }
49 
50  unsigned int fKPar; // param component
51  const Func * fFunc;
52 };
53 
54 
55 //______________________________________________________________________________
56 //
57 // TLinearMinimizer, simple class implementing the ROOT::Math::Minimizer interface using
58 // TLinearFitter.
59 // This class uses TLinearFitter to find directly (by solving a system of linear equations)
60 // the minimum of a
61 // least-square function which has a linear dependence in the fit parameters.
62 // This class is not used directly, but via the ROOT::Fitter class, when calling the
63 // LinearFit method. It is instantiates using the plug-in manager (plug-in name is "Linear")
64 //
65 //__________________________________________________________________________________________
66 
67 
68 ClassImp(TLinearMinimizer);
69 
70 
71 TLinearMinimizer::TLinearMinimizer(int ) :
72  fRobust(false),
73  fDim(0),
74  fNFree(0),
75  fMinVal(0),
76  fObjFunc(0),
77  fFitter(0)
78 {
79  // Default constructor implementation.
80  // type is not used - needed for consistency with other minimizer plug-ins
81 }
82 
83 TLinearMinimizer::TLinearMinimizer ( const char * type ) :
84  fRobust(false),
85  fDim(0),
86  fNFree(0),
87  fMinVal(0),
88  fObjFunc(0),
89  fFitter(0)
90 {
91  // constructor passing a type of algorithm, (supported now robust via LTS regression)
92 
93  // select type from the string
94  std::string algoname(type);
95  std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int(*)(int)) tolower );
96 
97  if (algoname.find("robust") != std::string::npos) fRobust = true;
98 
99 }
100 
101 TLinearMinimizer::~TLinearMinimizer()
102 {
103  // Destructor implementation.
104  if (fFitter) delete fFitter;
105 }
106 
107 TLinearMinimizer::TLinearMinimizer(const TLinearMinimizer &) :
108  Minimizer()
109 {
110  // Implementation of copy constructor.
111 }
112 
113 TLinearMinimizer & TLinearMinimizer::operator = (const TLinearMinimizer &rhs)
114 {
115  // Implementation of assignment operator.
116  if (this == &rhs) return *this; // time saving self-test
117  return *this;
118 }
119 
120 
121 void TLinearMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & ) {
122  // Set function to be minimized. Flag an error since only support Gradient objective functions
123 
124  Error("TLinearMinimizer::SetFunction(IMultiGenFunction)","Wrong type of function used for Linear fitter");
125 }
126 
127 
128 void TLinearMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & objfunc) {
129  // Set the function to be minimized. The function must be a Chi2 gradient function
130  // When performing a linear fit we need the basis functions, which are the partial derivatives with respect to the parameters of the model function.
131 
132  typedef ROOT::Fit::Chi2FCN<ROOT::Math::IMultiGradFunction> Chi2Func;
133  const Chi2Func * chi2func = dynamic_cast<const Chi2Func *>(&objfunc);
134  if (chi2func ==0) {
135  Error("TLinearMinimizer::SetFunction(IMultiGradFunction)","Wrong type of function used for Linear fitter");
136  return;
137  }
138  fObjFunc = chi2func;
139 
140  // need to get the gradient parametric model function
141  typedef ROOT::Math::IParamMultiGradFunction ModelFunc;
142  const ModelFunc * modfunc = dynamic_cast<const ModelFunc*>( &(chi2func->ModelFunction()) );
143  assert(modfunc != 0);
144 
145  fDim = chi2func->NDim(); // number of parameters
146  fNFree = fDim;
147  // get the basis functions (derivatives of the modelfunc)
148  TObjArray flist(fDim);
149  flist.SetOwner(kFALSE); // we do not want to own the list - it will be owned by the TLinearFitter class
150  for (unsigned int i = 0; i < fDim; ++i) {
151  // t.b.f: should not create TF1 classes
152  // when creating TF1 (if onother function with same name exists it is
153  // deleted since it is added in function list in gROOT
154  // fix the problem using meaniful names (difficult to re-produce)
155  BasisFunction<ModelFunc > bf(*modfunc,i);
156  TUUID u;
157  std::string fname = "_LinearMinimimizer_BasisFunction_" +
158  std::string(u.AsString() );
159  TF1 * f = new TF1(fname.c_str(),ROOT::Math::ParamFunctor(bf),0,1,0,1,TF1::EAddToList::kNo);
160  flist.Add(f);
161  }
162 
163  // create TLinearFitter (do it now because olny now now the coordinate dimensions)
164  if (fFitter) delete fFitter; // reset by deleting previous copy
165  fFitter = new TLinearFitter( static_cast<const ModelFunc::BaseFunc&>(*modfunc).NDim() );
166 
167  fFitter->StoreData(fRobust); // need a copy of data in case of robust fitting
168 
169  fFitter->SetBasisFunctions(&flist);
170 
171  // get the fitter data
172  const ROOT::Fit::BinData & data = chi2func->Data();
173  // add the data but not store them
174  for (unsigned int i = 0; i < data.Size(); ++i) {
175  double y = 0;
176  const double * x = data.GetPoint(i,y);
177  double ey = 1;
178  if (! data.Opt().fErrors1) {
179  ey = data.Error(i);
180  }
181  // interface should take a double *
182  fFitter->AddPoint( const_cast<double *>(x) , y, ey);
183  }
184 
185 }
186 
187 bool TLinearMinimizer::SetFixedVariable(unsigned int ivar, const std::string & /* name */ , double val) {
188  // set a fixed variable.
189  if (!fFitter) return false;
190  fFitter->FixParameter(ivar, val);
191  return true;
192 }
193 
194 bool TLinearMinimizer::Minimize() {
195  // find directly the minimum of the chi2 function
196  // solving the linear equation. Use TVirtualFitter::Eval.
197 
198  if (fFitter == 0 || fObjFunc == 0) return false;
199 
200  int iret = 0;
201  if (!fRobust)
202  iret = fFitter->Eval();
203  else {
204  // robust fitting - get h parameter using tolerance (t.b. improved)
205  double h = Tolerance();
206  if (PrintLevel() > 0)
207  std::cout << "TLinearMinimizer: Robust fitting with h = " << h << std::endl;
208  iret = fFitter->EvalRobust(h);
209  }
210  fStatus = iret;
211 
212  if (iret != 0) {
213  Warning("Minimize","TLinearFitter failed in finding the solution");
214  return false;
215  }
216 
217 
218  // get parameter values
219  fParams.resize( fDim);
220  // no error available for robust fitting
221  if (!fRobust) fErrors.resize( fDim);
222  for (unsigned int i = 0; i < fDim; ++i) {
223  fParams[i] = fFitter->GetParameter( i);
224  if (!fRobust) fErrors[i] = fFitter->GetParError( i );
225  }
226  fCovar.resize(fDim*fDim);
227  double * cov = fFitter->GetCovarianceMatrix();
228 
229  if (!fRobust && cov) std::copy(cov,cov+fDim*fDim,fCovar.begin() );
230 
231  // calculate chi2 value
232 
233  fMinVal = (*fObjFunc)(&fParams.front());
234 
235  return true;
236 
237 }
238 
239 
240 // } // end namespace Fit
241 
242 // } // end namespace ROOT
243