00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "TFumiliMinimizer.h"
00014 #include "Math/IFunction.h"
00015 #include "Math/Util.h"
00016 #include "TError.h"
00017
00018 #include "TFumili.h"
00019
00020 #include <iostream>
00021 #include <cassert>
00022 #include <algorithm>
00023 #include <functional>
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifdef USE_FUMILI_FUNCTION
00036 bool gUseFumiliFunction = true;
00037
00038
00039
00040 #include "Fit/PoissonLikelihoodFCN.h"
00041 #include "Fit/LogLikelihoodFCN.h"
00042 #include "Fit/Chi2FCN.h"
00043 #include "TF1.h"
00044 #include "TFumili.h"
00045
00046 template<class MethodFunc>
00047 class FumiliFunction : public ROOT::Math::FitMethodFunction {
00048
00049 typedef ROOT::Math::FitMethodFunction::BaseFunction BaseFunction;
00050
00051 public:
00052 FumiliFunction(TFumili * fumili, const ROOT::Math::FitMethodFunction * func) :
00053 ROOT::Math::FitMethodFunction(func->NDim(), func->NPoints() ),
00054 fFumili(fumili),
00055 fObjFunc(0)
00056 {
00057 fObjFunc = dynamic_cast<const MethodFunc *>(func);
00058 assert(fObjFunc != 0);
00059
00060
00061 fModFunc = new TF1("modfunc",ROOT::Math::ParamFunctor( &fObjFunc->ModelFunction() ) );
00062 fFumili->SetUserFunc(fModFunc);
00063 }
00064
00065 ROOT::Math::FitMethodFunction::Type_t Type() const { return fObjFunc->Type(); }
00066
00067 FumiliFunction * Clone() const { return new FumiliFunction(fFumili, fObjFunc); }
00068
00069
00070
00071 double DataElement(const double * , unsigned int i, double * g) const {
00072
00073
00074
00075
00076 unsigned int npar = fObjFunc->NDim();
00077 double y = 0;
00078 double invError = 0;
00079 const double *x = fObjFunc->Data().GetPoint(i,y,invError);
00080 double fval = fFumili->EvalTFN(g,const_cast<double *>( x));
00081 fFumili->Derivatives(g, const_cast<double *>( x));
00082
00083 if ( fObjFunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood) {
00084 double logPdf = y * ROOT::Math::Util::EvalLog( fval) - fval;
00085 for (unsigned int k = 0; k < npar; ++k) {
00086 g[k] *= ( y/fval - 1.) ;
00087 }
00088
00089
00090
00091
00092
00093
00094 return logPdf;
00095 }
00096 else if (fObjFunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare ) {
00097 double resVal = (y-fval)*invError;
00098 for (unsigned int k = 0; k < npar; ++k) {
00099 g[k] *= -invError;
00100 }
00101 return resVal;
00102 }
00103
00104 return 0;
00105 }
00106
00107
00108 private:
00109
00110 double DoEval(const double *x ) const {
00111 return (*fObjFunc)(x);
00112 }
00113
00114 TFumili * fFumili;
00115 const MethodFunc * fObjFunc;
00116 TF1 * fModFunc;
00117
00118 };
00119 #else
00120 bool gUseFumiliFunction = false;
00121 #endif
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 ROOT::Math::FitMethodFunction * TFumiliMinimizer::fgFunc = 0;
00135 ROOT::Math::FitMethodGradFunction * TFumiliMinimizer::fgGradFunc = 0;
00136 TFumili * TFumiliMinimizer::fgFumili = 0;
00137
00138
00139 ClassImp(TFumiliMinimizer)
00140
00141
00142 TFumiliMinimizer::TFumiliMinimizer(int ) :
00143 fDim(0),
00144 fNFree(0),
00145 fMinVal(0),
00146 fEdm(-1),
00147 fFumili(0)
00148 {
00149
00150
00151
00152 #ifdef USE_STATIC_TMINUIT
00153
00154 if (fgFumili == 0) fgFumili = new TFumili(0);
00155 fFumili = fgFumili;
00156 #else
00157 if (fFumili) delete fFumili;
00158 fFumili = new TFumili(0);
00159 fgFumili = fFumili;
00160 #endif
00161
00162 }
00163
00164
00165 TFumiliMinimizer::~TFumiliMinimizer()
00166 {
00167
00168 if (fFumili) delete fFumili;
00169 }
00170
00171 TFumiliMinimizer::TFumiliMinimizer(const TFumiliMinimizer &) :
00172 Minimizer()
00173 {
00174
00175 }
00176
00177 TFumiliMinimizer & TFumiliMinimizer::operator = (const TFumiliMinimizer &rhs)
00178 {
00179
00180 if (this == &rhs) return *this;
00181 return *this;
00182 }
00183
00184
00185
00186 void TFumiliMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func) {
00187
00188
00189
00190
00191
00192
00193 fDim = func.NDim();
00194 fFumili->SetParNumber(fDim);
00195
00196
00197 const ROOT::Math::FitMethodFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
00198 if (!fcnfunc) {
00199 Error("SetFunction","Wrong Fit method function type used for Fumili");
00200 return;
00201 }
00202
00203 fgFunc = const_cast<ROOT::Math::FitMethodFunction *>(fcnfunc);
00204 fgGradFunc = 0;
00205 fFumili->SetFCN(&TFumiliMinimizer::Fcn);
00206
00207 #ifdef USE_FUMILI_FUNCTION
00208 if (gUseFumiliFunction) {
00209 if (fcnfunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood)
00210 fgFunc = new FumiliFunction<ROOT::Fit::PoissonLikelihoodFCN<ROOT::Math::FitMethodFunction::BaseFunction> >(fFumili,fcnfunc);
00211 else if (fcnfunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare)
00212 fgFunc = new FumiliFunction<ROOT::Fit::Chi2FCN<ROOT::Math::FitMethodFunction::BaseFunction> >(fFumili,fcnfunc);
00213 }
00214 #endif
00215
00216 }
00217
00218 void TFumiliMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func) {
00219
00220
00221
00222
00223 fDim = func.NDim();
00224 fFumili->SetParNumber(fDim);
00225
00226
00227 const ROOT::Math::FitMethodGradFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(&func);
00228 if (!fcnfunc) {
00229 Error("SetFunction","Wrong Fit method function type used for Fumili");
00230 return;
00231 }
00232
00233 fgFunc = 0;
00234 fgGradFunc = const_cast<ROOT::Math::FitMethodGradFunction *>(fcnfunc);
00235 fFumili->SetFCN(&TFumiliMinimizer::Fcn);
00236
00237 }
00238
00239 void TFumiliMinimizer::Fcn( int & , double * g , double & f, double * x , int ) {
00240
00241
00242 f = TFumiliMinimizer::EvaluateFCN(const_cast<double*>(x),g);
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 double TFumiliMinimizer::EvaluateFCN(const double * x, double * grad) {
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 double sum = 0;
00273 unsigned int ndata = 0;
00274 unsigned int npar = 0;
00275 if (fgFunc) {
00276 ndata = fgFunc->NPoints();
00277 npar = fgFunc->NDim();
00278 fgFunc->UpdateNCalls();
00279 }
00280 else if (fgGradFunc) {
00281 ndata = fgGradFunc->NPoints();
00282 npar = fgGradFunc->NDim();
00283 fgGradFunc->UpdateNCalls();
00284 }
00285
00286
00287 std::vector<double> gf(npar);
00288 std::vector<double> hess(npar*(npar+1)/2);
00289
00290
00291 for (unsigned int ipar = 0; ipar < npar; ++ipar)
00292 grad[ipar] = 0;
00293
00294
00295
00296
00297 #ifdef DEBUG
00298 std::cout << "=============================================";
00299 std::cout << "par = ";
00300 for (unsigned int ipar = 0; ipar < npar; ++ipar)
00301 std::cout << x[ipar] << "\t";
00302 std::cout << std::endl;
00303 if (fgFunc) std::cout << "type " << fgFunc->Type() << std::endl;
00304 #endif
00305
00306
00307
00308
00309 if ( (fgFunc && fgFunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare) ||
00310 (fgGradFunc && fgGradFunc->Type() == ROOT::Math::FitMethodGradFunction::kLeastSquare) ) {
00311
00312 double fval = 0;
00313 for (unsigned int i = 0; i < ndata; ++i) {
00314
00315
00316 if (gUseFumiliFunction) {
00317 fval = fgFunc->DataElement( x, i, &gf[0]);
00318 }
00319 else {
00320 if (fgFunc != 0)
00321 fval = fgFunc->DataElement(x, i, &gf[0]);
00322 else
00323 fval = fgGradFunc->DataElement(x, i, &gf[0]);
00324 }
00325
00326
00327 sum += fval*fval;
00328
00329
00330
00331 for (unsigned int j = 0; j < npar; ++j) {
00332 grad[j] += fval * gf[j];
00333 for (unsigned int k = j; k < npar; ++ k) {
00334 int idx = j + k*(k+1)/2;
00335 hess[idx] += gf[j] * gf[k];
00336 }
00337 }
00338 }
00339 }
00340 else if ( (fgFunc && fgFunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood) ||
00341 (fgGradFunc && fgGradFunc->Type() == ROOT::Math::FitMethodGradFunction::kLogLikelihood) ) {
00342
00343
00344
00345 double fval = 0;
00346
00347
00348
00349 for (unsigned int i = 0; i < ndata; ++i) {
00350
00351 if (gUseFumiliFunction) {
00352 fval = fgFunc->DataElement( x, i, &gf[0]);
00353 }
00354 else {
00355
00356 if (fgFunc != 0)
00357 fval = fgFunc->DataElement(x, i, &gf[0]);
00358 else
00359 fval = fgGradFunc->DataElement(x, i, &gf[0]);
00360 }
00361
00362
00363
00364
00365 sum -= fval;
00366
00367 for (unsigned int j = 0; j < npar; ++j) {
00368 double gfj = gf[j];
00369 grad[j] -= gfj;
00370 for (unsigned int k = j; k < npar; ++ k) {
00371 int idx = j + k*(k+1)/2;
00372 hess[idx] += gfj * gf[k];
00373 }
00374 }
00375 }
00376 }
00377 else {
00378 Error("EvaluateFCN"," type of fit method is not supported, it must be chi2 or log-likelihood");
00379 }
00380
00381
00382
00383 double * zmatrix = fgFumili->GetZ();
00384 double * pl0 = fgFumili->GetPL0();
00385 assert(zmatrix != 0);
00386 assert(pl0 != 0);
00387 unsigned int k = 0;
00388 unsigned int l = 0;
00389 for (unsigned int i = 0; i < npar; ++i) {
00390 for (unsigned int j = 0; j <= i; ++j) {
00391 if (pl0[i] > 0 && pl0[j] > 0) {
00392 zmatrix[l++] = hess[k];
00393 }
00394 k++;
00395 }
00396 }
00397
00398 #ifdef DEBUG
00399 std::cout << "FCN value " << sum << " grad ";
00400 for (unsigned int ipar = 0; ipar < npar; ++ipar)
00401 std::cout << grad[ipar] << "\t";
00402 std::cout << std::endl << std::endl;
00403 #endif
00404
00405
00406 return 0.5*sum;
00407
00408 }
00409
00410
00411
00412 bool TFumiliMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) {
00413
00414 if (fFumili == 0) {
00415 Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00416 return false;
00417 }
00418 #ifdef DEBUG
00419 std::cout << "set variable " << ivar << " " << name << " value " << val << " step " << step << std::endl;
00420 #endif
00421
00422 int ierr = fFumili->SetParameter(ivar , name.c_str(), val, step, 0., 0. );
00423 if (ierr) {
00424 Error("SetVariable","Error for parameter %d ",ivar);
00425 return false;
00426 }
00427 return true;
00428 }
00429
00430 bool TFumiliMinimizer::SetLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower, double upper) {
00431
00432 if (fFumili == 0) {
00433 Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00434 return false;
00435 }
00436 #ifdef DEBUG
00437 std::cout << "set limited variable " << ivar << " " << name << " value " << val << " step " << step << std::endl;
00438 #endif
00439 int ierr = fFumili->SetParameter(ivar, name.c_str(), val, step, lower, upper );
00440 if (ierr) {
00441 Error("SetLimitedVariable","Error for parameter %d ",ivar);
00442 return false;
00443 }
00444 return true;
00445 }
00446 #ifdef LATER
00447 bool Fumili2Minimizer::SetLowerLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower ) {
00448
00449 double s = val-lower;
00450 double upper = s*1.0E15;
00451 if (s != 0) upper = 1.0E15;
00452 return SetLimitedVariable(ivar, name, val, step, lower,upper);
00453 }
00454 #endif
00455
00456
00457 bool TFumiliMinimizer::SetFixedVariable(unsigned int ivar, const std::string & name, double val) {
00458
00459 if (fFumili == 0) {
00460 Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00461 return false;
00462 }
00463
00464
00465 int ierr = fFumili->SetParameter(ivar, name.c_str(), val, 0., val, val );
00466 fFumili->FixParameter(ivar);
00467
00468 #ifdef DEBUG
00469 std::cout << "Fix variable " << ivar << " " << name << " value " << std::endl;
00470 #endif
00471
00472 if (ierr) {
00473 Error("SetFixedVariable","Error for parameter %d ",ivar);
00474 return false;
00475 }
00476 return true;
00477 }
00478
00479 bool TFumiliMinimizer::SetVariableValue(unsigned int ivar, double val) {
00480
00481 if (fFumili == 0) {
00482 Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00483 return false;
00484 }
00485 TString name = fFumili->GetParName(ivar);
00486 double oldval, verr, vlow, vhigh = 0;
00487 int ierr = fFumili->GetParameter( ivar, &name[0], oldval, verr, vlow, vhigh);
00488 if (ierr) {
00489 Error("SetVariableValue","Error for parameter %d ",ivar);
00490 return false;
00491 }
00492 #ifdef DEBUG
00493 std::cout << "set variable " << ivar << " " << name << " value "
00494 << val << " step " << verr << std::endl;
00495 #endif
00496
00497 ierr = fFumili->SetParameter(ivar , name , val, verr, vlow, vhigh );
00498 if (ierr) {
00499 Error("SetVariableValue","Error for parameter %d ",ivar);
00500 return false;
00501 }
00502 return true;
00503 }
00504
00505 bool TFumiliMinimizer::Minimize() {
00506
00507
00508
00509
00510
00511 if (fFumili == 0) {
00512 Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00513 return false;
00514 }
00515
00516
00517 fgFumili = fFumili;
00518
00519
00520 double arglist[10];
00521
00522
00523
00524
00525
00526 int printlevel = PrintLevel();
00527
00528
00529
00530
00531
00532 if (printlevel == 0) fFumili->ExecuteCommand("SET NOW",arglist,0);
00533 else fFumili->ExecuteCommand("SET WAR",arglist,0);
00534
00535
00536
00537
00538 arglist[0] = MaxFunctionCalls();
00539 arglist[1] = Tolerance();
00540
00541 if (printlevel > 0)
00542 std::cout << "Minimize using TFumili with tolerance = " << Tolerance()
00543 << " max calls " << MaxFunctionCalls() << std::endl;
00544
00545 int iret = fFumili->ExecuteCommand("MIGRAD",arglist,2);
00546 fStatus = iret;
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 int ntot;
00561 int nfree;
00562 double errdef = 0;
00563 fFumili->GetStats(fMinVal,fEdm,errdef,nfree,ntot);
00564
00565 if (printlevel > 0)
00566 fFumili->PrintResults(printlevel,fMinVal);
00567
00568
00569 assert (static_cast<unsigned int>(ntot) == fDim);
00570 assert( nfree == fFumili->GetNumberFreeParameters() );
00571 fNFree = nfree;
00572
00573
00574
00575
00576 fParams.resize( fDim);
00577 fErrors.resize( fDim);
00578 fCovar.resize(fDim*fDim);
00579 const double * cv = fFumili->GetCovarianceMatrix();
00580 unsigned int l = 0;
00581 for (unsigned int i = 0; i < fDim; ++i) {
00582 fParams[i] = fFumili->GetParameter( i );
00583 fErrors[i] = fFumili->GetParError( i );
00584
00585 if ( !fFumili->IsFixed(i) ) {
00586 for (unsigned int j = 0; j <=i ; ++j) {
00587 if ( !fFumili->IsFixed(j) ) {
00588 fCovar[i*fDim + j] = cv[l];
00589 fCovar[j*fDim + i] = fCovar[i*fDim + j];
00590 l++;
00591 }
00592 }
00593 }
00594 }
00595
00596 return (iret==0) ? true : false;
00597 }
00598
00599
00600
00601
00602
00603