// @(#)root/minuit:$Id$
// Author: L. Moneta Wed Oct 25 16:28:55 2006

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 *                                                                    *
 **********************************************************************/

// Implementation file for class TLinearMinimizer

#include "TLinearMinimizer.h"
#include "Math/IParamFunction.h"
#include "TF1.h"
#include "TUUID.h"
#include "TROOT.h"
#include "Fit/Chi2FCN.h"

#include "TLinearFitter.h"

#include <iostream>
#include <cassert>
#include <algorithm>
#include <functional>



// namespace ROOT { 

//    namespace Fit { 


// structure used for creating the TF1 representing the basis functions
// they are the derivatives w.r.t the parameters of the model function 
template<class Func> 
struct BasisFunction { 
   BasisFunction(const Func & f, int k) : 
      fKPar(k), 
      fFunc(&f) 
   {}

   double operator() ( double * x, double *)  { 
      return fFunc->ParameterDerivative(x,fKPar); 
   }

   unsigned int fKPar; // param component
   const Func * fFunc; 
};


//______________________________________________________________________________
//
//  TLinearMinimizer, simple class implementing the ROOT::Math::Minimizer interface using 
//  TLinearFitter. 
//  This class uses TLinearFitter to find directly (by solving a system of linear equations) 
//  the minimum of a 
//  least-square function which has a linear dependence in the fit parameters. 
//  This class is not used directly, but via the ROOT::Fitter class, when calling the 
//  LinearFit method. It is instantiates using the plug-in manager (plug-in name is "Linear")
//  
//__________________________________________________________________________________________


ClassImp(TLinearMinimizer)


TLinearMinimizer::TLinearMinimizer(int ) : 
   fRobust(false), 
   fDim(0),
   fNFree(0),
   fMinVal(0),
   fObjFunc(0),
   fFitter(0)
{
   // Default constructor implementation.
   // type is not used - needed for consistency with other minimizer plug-ins
}

TLinearMinimizer::TLinearMinimizer ( const char * type ) : 
   fRobust(false),
   fDim(0),
   fNFree(0),
   fMinVal(0),
   fObjFunc(0),
   fFitter(0)
{
   // constructor passing a type of algorithm, (supported now robust via LTS regression)

   // select type from the string
   std::string algoname(type);
   std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int(*)(int)) tolower ); 

   if (algoname.find("robust") != std::string::npos) fRobust = true;

}

TLinearMinimizer::~TLinearMinimizer() 
{
   // Destructor implementation.
   if (fFitter) delete fFitter; 
}

TLinearMinimizer::TLinearMinimizer(const TLinearMinimizer &) : 
   Minimizer()
{
   // Implementation of copy constructor.
}

TLinearMinimizer & TLinearMinimizer::operator = (const TLinearMinimizer &rhs) 
{
   // Implementation of assignment operator.
   if (this == &rhs) return *this;  // time saving self-test
   return *this;
}


void TLinearMinimizer::SetFunction(const  ROOT::Math::IMultiGenFunction & ) { 
   // Set function to be minimized. Flag an error since only support Gradient objective functions

   Error("TLinearMinimizer::SetFunction(IMultiGenFunction)","Wrong type of function used for Linear fitter");
}


void TLinearMinimizer::SetFunction(const  ROOT::Math::IMultiGradFunction & objfunc) { 
   // Set the function to be minimized. The function must be a Chi2 gradient function 
   // When performing a linear fit we need the basis functions, which are the partial derivatives with respect to the parameters of the model function.

   typedef ROOT::Fit::Chi2FCN<ROOT::Math::IMultiGradFunction> Chi2Func; 
   const Chi2Func * chi2func = dynamic_cast<const Chi2Func *>(&objfunc); 
   if (chi2func ==0) { 
      Error("TLinearMinimizer::SetFunction(IMultiGradFunction)","Wrong type of function used for Linear fitter");
      return; 
   }
   fObjFunc = chi2func;

   // need to get the gradient parametric model function
   typedef  ROOT::Math::IParamMultiGradFunction ModelFunc; 
   const  ModelFunc * modfunc = dynamic_cast<const ModelFunc*>( &(chi2func->ModelFunction()) ); 
   assert(modfunc != 0);

   fDim = chi2func->NDim(); // number of parameters
   fNFree = fDim;
   // get the basis functions (derivatives of the modelfunc)
   TObjArray flist; 
   for (unsigned int i = 0; i < fDim; ++i) { 
      // t.b.f: should not create TF1 classes
      // when creating TF1 (if onother function with same name exists it is 
      // deleted since it is added in function list in gROOT 
      // fix the problem using meaniful names (difficult to re-produce)
      BasisFunction<ModelFunc > bf(*modfunc,i); 
      TUUID u; 
      std::string fname = "_LinearMinimimizer_BasisFunction_" + 
         std::string(u.AsString() );
      TF1 * f = new TF1(fname.c_str(),ROOT::Math::ParamFunctor(bf));
      flist.Add(f);
      // remove this functions from gROOT
      gROOT->GetListOfFunctions()->Remove(f); 
      
   }

   // create TLinearFitter (do it now because olny now now the coordinate dimensions)
   if (fFitter) delete fFitter; // reset by deleting previous copy
   fFitter = new TLinearFitter( static_cast<const ModelFunc::BaseFunc&>(*modfunc).NDim() ); 

   fFitter->StoreData(fRobust); //  need a copy of data in case of robust fitting 

   fFitter->SetBasisFunctions(&flist); 

   // get the fitter data
   const ROOT::Fit::BinData & data = chi2func->Data(); 
   // add the data but not store them 
   for (unsigned int i = 0; i < data.Size(); ++i) { 
      double y = 0; 
      const double * x = data.GetPoint(i,y); 
      double ey = 1;
      if (! data.Opt().fErrors1) { 
         ey = data.Error(i); 
      } 
      // interface should take a double *
      fFitter->AddPoint( const_cast<double *>(x) , y, ey); 
   }

}

bool TLinearMinimizer::SetFixedVariable(unsigned int ivar, const std::string & /* name */ , double val) { 
   // set a fixed variable.
   if (!fFitter) return false; 
   fFitter->FixParameter(ivar, val);
   return true; 
}

bool TLinearMinimizer::Minimize() { 
   // find directly the minimum of the chi2 function 
   // solving the linear equation. Use  TVirtualFitter::Eval. 

   if (fFitter == 0 || fObjFunc == 0) return false;

   int iret = 0; 
   if (!fRobust) 
      iret = fFitter->Eval(); 
   else { 
      // robust fitting - get h parameter using tolerance (t.b. improved)
      double h = Tolerance(); 
      if (PrintLevel() >  0)
         std::cout << "TLinearMinimizer: Robust fitting with h = " << h << std::endl; 
      iret = fFitter->EvalRobust(h); 
   }
   fStatus = iret; 
 
   if (iret != 0) { 
      Warning("Minimize","TLinearFitter failed in finding the solution");  
      return false; 
   }
   

   // get parameter values 
   fParams.resize( fDim); 
   // no error available for robust fitting
   if (!fRobust) fErrors.resize( fDim); 
   for (unsigned int i = 0; i < fDim; ++i) { 
      fParams[i] = fFitter->GetParameter( i);
      if (!fRobust) fErrors[i] = fFitter->GetParError( i ); 
   }
   fCovar.resize(fDim*fDim); 
   double * cov = fFitter->GetCovarianceMatrix();

   if (!fRobust && cov) std::copy(cov,cov+fDim*fDim,fCovar.begin() );

   // calculate chi2 value
   
   fMinVal = (*fObjFunc)(&fParams.front());

   return true;

}


//    } // end namespace Fit

// } // end namespace ROOT

 TLinearMinimizer.cxx:1
 TLinearMinimizer.cxx:2
 TLinearMinimizer.cxx:3
 TLinearMinimizer.cxx:4
 TLinearMinimizer.cxx:5
 TLinearMinimizer.cxx:6
 TLinearMinimizer.cxx:7
 TLinearMinimizer.cxx:8
 TLinearMinimizer.cxx:9
 TLinearMinimizer.cxx:10
 TLinearMinimizer.cxx:11
 TLinearMinimizer.cxx:12
 TLinearMinimizer.cxx:13
 TLinearMinimizer.cxx:14
 TLinearMinimizer.cxx:15
 TLinearMinimizer.cxx:16
 TLinearMinimizer.cxx:17
 TLinearMinimizer.cxx:18
 TLinearMinimizer.cxx:19
 TLinearMinimizer.cxx:20
 TLinearMinimizer.cxx:21
 TLinearMinimizer.cxx:22
 TLinearMinimizer.cxx:23
 TLinearMinimizer.cxx:24
 TLinearMinimizer.cxx:25
 TLinearMinimizer.cxx:26
 TLinearMinimizer.cxx:27
 TLinearMinimizer.cxx:28
 TLinearMinimizer.cxx:29
 TLinearMinimizer.cxx:30
 TLinearMinimizer.cxx:31
 TLinearMinimizer.cxx:32
 TLinearMinimizer.cxx:33
 TLinearMinimizer.cxx:34
 TLinearMinimizer.cxx:35
 TLinearMinimizer.cxx:36
 TLinearMinimizer.cxx:37
 TLinearMinimizer.cxx:38
 TLinearMinimizer.cxx:39
 TLinearMinimizer.cxx:40
 TLinearMinimizer.cxx:41
 TLinearMinimizer.cxx:42
 TLinearMinimizer.cxx:43
 TLinearMinimizer.cxx:44
 TLinearMinimizer.cxx:45
 TLinearMinimizer.cxx:46
 TLinearMinimizer.cxx:47
 TLinearMinimizer.cxx:48
 TLinearMinimizer.cxx:49
 TLinearMinimizer.cxx:50
 TLinearMinimizer.cxx:51
 TLinearMinimizer.cxx:52
 TLinearMinimizer.cxx:53
 TLinearMinimizer.cxx:54
 TLinearMinimizer.cxx:55
 TLinearMinimizer.cxx:56
 TLinearMinimizer.cxx:57
 TLinearMinimizer.cxx:58
 TLinearMinimizer.cxx:59
 TLinearMinimizer.cxx:60
 TLinearMinimizer.cxx:61
 TLinearMinimizer.cxx:62
 TLinearMinimizer.cxx:63
 TLinearMinimizer.cxx:64
 TLinearMinimizer.cxx:65
 TLinearMinimizer.cxx:66
 TLinearMinimizer.cxx:67
 TLinearMinimizer.cxx:68
 TLinearMinimizer.cxx:69
 TLinearMinimizer.cxx:70
 TLinearMinimizer.cxx:71
 TLinearMinimizer.cxx:72
 TLinearMinimizer.cxx:73
 TLinearMinimizer.cxx:74
 TLinearMinimizer.cxx:75
 TLinearMinimizer.cxx:76
 TLinearMinimizer.cxx:77
 TLinearMinimizer.cxx:78
 TLinearMinimizer.cxx:79
 TLinearMinimizer.cxx:80
 TLinearMinimizer.cxx:81
 TLinearMinimizer.cxx:82
 TLinearMinimizer.cxx:83
 TLinearMinimizer.cxx:84
 TLinearMinimizer.cxx:85
 TLinearMinimizer.cxx:86
 TLinearMinimizer.cxx:87
 TLinearMinimizer.cxx:88
 TLinearMinimizer.cxx:89
 TLinearMinimizer.cxx:90
 TLinearMinimizer.cxx:91
 TLinearMinimizer.cxx:92
 TLinearMinimizer.cxx:93
 TLinearMinimizer.cxx:94
 TLinearMinimizer.cxx:95
 TLinearMinimizer.cxx:96
 TLinearMinimizer.cxx:97
 TLinearMinimizer.cxx:98
 TLinearMinimizer.cxx:99
 TLinearMinimizer.cxx:100
 TLinearMinimizer.cxx:101
 TLinearMinimizer.cxx:102
 TLinearMinimizer.cxx:103
 TLinearMinimizer.cxx:104
 TLinearMinimizer.cxx:105
 TLinearMinimizer.cxx:106
 TLinearMinimizer.cxx:107
 TLinearMinimizer.cxx:108
 TLinearMinimizer.cxx:109
 TLinearMinimizer.cxx:110
 TLinearMinimizer.cxx:111
 TLinearMinimizer.cxx:112
 TLinearMinimizer.cxx:113
 TLinearMinimizer.cxx:114
 TLinearMinimizer.cxx:115
 TLinearMinimizer.cxx:116
 TLinearMinimizer.cxx:117
 TLinearMinimizer.cxx:118
 TLinearMinimizer.cxx:119
 TLinearMinimizer.cxx:120
 TLinearMinimizer.cxx:121
 TLinearMinimizer.cxx:122
 TLinearMinimizer.cxx:123
 TLinearMinimizer.cxx:124
 TLinearMinimizer.cxx:125
 TLinearMinimizer.cxx:126
 TLinearMinimizer.cxx:127
 TLinearMinimizer.cxx:128
 TLinearMinimizer.cxx:129
 TLinearMinimizer.cxx:130
 TLinearMinimizer.cxx:131
 TLinearMinimizer.cxx:132
 TLinearMinimizer.cxx:133
 TLinearMinimizer.cxx:134
 TLinearMinimizer.cxx:135
 TLinearMinimizer.cxx:136
 TLinearMinimizer.cxx:137
 TLinearMinimizer.cxx:138
 TLinearMinimizer.cxx:139
 TLinearMinimizer.cxx:140
 TLinearMinimizer.cxx:141
 TLinearMinimizer.cxx:142
 TLinearMinimizer.cxx:143
 TLinearMinimizer.cxx:144
 TLinearMinimizer.cxx:145
 TLinearMinimizer.cxx:146
 TLinearMinimizer.cxx:147
 TLinearMinimizer.cxx:148
 TLinearMinimizer.cxx:149
 TLinearMinimizer.cxx:150
 TLinearMinimizer.cxx:151
 TLinearMinimizer.cxx:152
 TLinearMinimizer.cxx:153
 TLinearMinimizer.cxx:154
 TLinearMinimizer.cxx:155
 TLinearMinimizer.cxx:156
 TLinearMinimizer.cxx:157
 TLinearMinimizer.cxx:158
 TLinearMinimizer.cxx:159
 TLinearMinimizer.cxx:160
 TLinearMinimizer.cxx:161
 TLinearMinimizer.cxx:162
 TLinearMinimizer.cxx:163
 TLinearMinimizer.cxx:164
 TLinearMinimizer.cxx:165
 TLinearMinimizer.cxx:166
 TLinearMinimizer.cxx:167
 TLinearMinimizer.cxx:168
 TLinearMinimizer.cxx:169
 TLinearMinimizer.cxx:170
 TLinearMinimizer.cxx:171
 TLinearMinimizer.cxx:172
 TLinearMinimizer.cxx:173
 TLinearMinimizer.cxx:174
 TLinearMinimizer.cxx:175
 TLinearMinimizer.cxx:176
 TLinearMinimizer.cxx:177
 TLinearMinimizer.cxx:178
 TLinearMinimizer.cxx:179
 TLinearMinimizer.cxx:180
 TLinearMinimizer.cxx:181
 TLinearMinimizer.cxx:182
 TLinearMinimizer.cxx:183
 TLinearMinimizer.cxx:184
 TLinearMinimizer.cxx:185
 TLinearMinimizer.cxx:186
 TLinearMinimizer.cxx:187
 TLinearMinimizer.cxx:188
 TLinearMinimizer.cxx:189
 TLinearMinimizer.cxx:190
 TLinearMinimizer.cxx:191
 TLinearMinimizer.cxx:192
 TLinearMinimizer.cxx:193
 TLinearMinimizer.cxx:194
 TLinearMinimizer.cxx:195
 TLinearMinimizer.cxx:196
 TLinearMinimizer.cxx:197
 TLinearMinimizer.cxx:198
 TLinearMinimizer.cxx:199
 TLinearMinimizer.cxx:200
 TLinearMinimizer.cxx:201
 TLinearMinimizer.cxx:202
 TLinearMinimizer.cxx:203
 TLinearMinimizer.cxx:204
 TLinearMinimizer.cxx:205
 TLinearMinimizer.cxx:206
 TLinearMinimizer.cxx:207
 TLinearMinimizer.cxx:208
 TLinearMinimizer.cxx:209
 TLinearMinimizer.cxx:210
 TLinearMinimizer.cxx:211
 TLinearMinimizer.cxx:212
 TLinearMinimizer.cxx:213
 TLinearMinimizer.cxx:214
 TLinearMinimizer.cxx:215
 TLinearMinimizer.cxx:216
 TLinearMinimizer.cxx:217
 TLinearMinimizer.cxx:218
 TLinearMinimizer.cxx:219
 TLinearMinimizer.cxx:220
 TLinearMinimizer.cxx:221
 TLinearMinimizer.cxx:222
 TLinearMinimizer.cxx:223
 TLinearMinimizer.cxx:224
 TLinearMinimizer.cxx:225
 TLinearMinimizer.cxx:226
 TLinearMinimizer.cxx:227
 TLinearMinimizer.cxx:228
 TLinearMinimizer.cxx:229
 TLinearMinimizer.cxx:230
 TLinearMinimizer.cxx:231
 TLinearMinimizer.cxx:232
 TLinearMinimizer.cxx:233
 TLinearMinimizer.cxx:234
 TLinearMinimizer.cxx:235
 TLinearMinimizer.cxx:236
 TLinearMinimizer.cxx:237
 TLinearMinimizer.cxx:238
 TLinearMinimizer.cxx:239
 TLinearMinimizer.cxx:240
 TLinearMinimizer.cxx:241
 TLinearMinimizer.cxx:242