00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "Fit/FitUtil.h"
00014
00015 #include "Fit/BinData.h"
00016 #include "Fit/UnBinData.h"
00017
00018
00019 #include "Math/IParamFunction.h"
00020 #include "Math/Integrator.h"
00021 #include "Math/IntegratorMultiDim.h"
00022 #include "Math/WrappedFunction.h"
00023 #include "Math/OneDimFunctionAdapter.h"
00024 #include "Math/RichardsonDerivator.h"
00025
00026 #include "Math/Error.h"
00027 #include "Math/Util.h"
00028
00029 #include <limits>
00030 #include <cmath>
00031 #include <cassert>
00032
00033
00034
00035 #ifdef DEBUG
00036 #define NSAMPLE 10
00037 #include <iostream>
00038 #endif
00039
00040
00041
00042
00043
00044 namespace ROOT {
00045
00046 namespace Fit {
00047
00048 namespace FitUtil {
00049
00050
00051
00052
00053
00054
00055
00056 template <class ParamFunc = ROOT::Math::IParamMultiFunction>
00057 class IntegralEvaluator {
00058
00059 public:
00060
00061 IntegralEvaluator(const ParamFunc & func, const double * p, bool useIntegral = true) :
00062 fDim(0),
00063 fParams(0),
00064 fFunc(0),
00065 fIg1Dim(0),
00066 fIgNDim(0),
00067 fFunc1Dim(0),
00068 fFuncNDim(0)
00069 {
00070 if (useIntegral) {
00071 SetFunction(func, p);
00072 }
00073 }
00074
00075 void SetFunction(const ParamFunc & func, const double * p = 0) {
00076
00077
00078 fParams = p;
00079 fDim = func.NDim();
00080
00081
00082 fFunc = &func;
00083 assert(fFunc != 0);
00084
00085
00086 if (fDim == 1) {
00087 fFunc1Dim = new ROOT::Math::WrappedMemFunction< IntegralEvaluator, double (IntegralEvaluator::*)(double ) const > (*this, &IntegralEvaluator::F1);
00088 fIg1Dim = new ROOT::Math::IntegratorOneDim();
00089
00090 fIg1Dim->SetFunction( static_cast<const ROOT::Math::IGenFunction &>(*fFunc1Dim) );
00091 }
00092 else if (fDim > 1) {
00093 fFuncNDim = new ROOT::Math::WrappedMemMultiFunction< IntegralEvaluator, double (IntegralEvaluator::*)(const double *) const > (*this, &IntegralEvaluator::FN, fDim);
00094 fIgNDim = new ROOT::Math::IntegratorMultiDim();
00095 fIgNDim->SetFunction(*fFuncNDim);
00096 }
00097 else
00098 assert(fDim > 0);
00099 }
00100
00101 void SetParameters(const double *p) {
00102
00103 fParams = p;
00104 }
00105
00106 ~IntegralEvaluator() {
00107 if (fIg1Dim) delete fIg1Dim;
00108 if (fIgNDim) delete fIgNDim;
00109 if (fFunc1Dim) delete fFunc1Dim;
00110 if (fFuncNDim) delete fFuncNDim;
00111
00112 }
00113
00114
00115 double F1 (double x) const {
00116 double xx[1]; xx[0] = x;
00117 return (*fFunc)( xx, fParams);
00118 }
00119
00120 double FN(const double * x) const {
00121 return (*fFunc)( x, fParams);
00122 }
00123
00124 double operator()(const double *x1, const double * x2) {
00125
00126 if (fIg1Dim) {
00127 double dV = *x2 - *x1;
00128 return fIg1Dim->Integral( *x1, *x2)/dV;
00129 }
00130 else if (fIgNDim) {
00131 double dV = 1;
00132 for (unsigned int i = 0; i < fDim; ++i)
00133 dV *= ( x2[i] - x1[i] );
00134 return fIgNDim->Integral( x1, x2)/dV;
00135
00136
00137 }
00138 else
00139 assert(1.);
00140 return 0;
00141 }
00142
00143 private:
00144
00145 unsigned int fDim;
00146 const double * fParams;
00147
00148 const ParamFunc * fFunc;
00149 ROOT::Math::IntegratorOneDim * fIg1Dim;
00150 ROOT::Math::IntegratorMultiDim * fIgNDim;
00151 ROOT::Math::IGenFunction * fFunc1Dim;
00152 ROOT::Math::IMultiGenFunction * fFuncNDim;
00153 };
00154
00155
00156
00157 template<class GradFunc = IGradModelFunction>
00158 struct ParamDerivFunc {
00159 ParamDerivFunc(const GradFunc & f) : fFunc(f), fIpar(0) {}
00160 void SetDerivComponent(unsigned int ipar) { fIpar = ipar; }
00161 double operator() (const double *x, const double *p) const {
00162 return fFunc.ParameterDerivative( x, p, fIpar );
00163 }
00164 unsigned int NDim() const { return fFunc.NDim(); }
00165 const GradFunc & fFunc;
00166 unsigned int fIpar;
00167 };
00168
00169
00170
00171 class SimpleGradientCalculator {
00172
00173 public:
00174
00175
00176
00177
00178
00179
00180
00181 SimpleGradientCalculator(int gdim, const IModelFunction & func,double eps = 2.E-8, int istrat = 1) :
00182 fEps(eps),
00183 fPrecision(1.E-8 ),
00184 fStrategy(istrat),
00185 fN(gdim ),
00186 fFunc(func),
00187 fVec(std::vector<double>(gdim) )
00188 {}
00189
00190
00191
00192 double DoParameterDerivative(const double *x, const double *p, double f0, int k) const {
00193 double p0 = p[k];
00194 double h = std::max( fEps* std::abs(p0), 8.0*fPrecision*(std::abs(p0) + fPrecision) );
00195 fVec[k] += h;
00196 double deriv = 0;
00197
00198
00199 double f1 = fFunc(x, &fVec.front() );
00200 if (fStrategy > 1) {
00201 fVec[k] = p0 - h;
00202 double f2 = fFunc(x, &fVec.front() );
00203 deriv = 0.5 * ( f2 - f1 )/h;
00204 }
00205 else
00206 deriv = ( f1 - f0 )/h;
00207
00208 fVec[k] = p[k];
00209 return deriv;
00210 }
00211
00212 unsigned int NDim() const {
00213 return fFunc.NDim();
00214 }
00215
00216 unsigned int NPar() const {
00217 return fFunc.NPar();
00218 }
00219
00220 double ParameterDerivative(const double *x, const double *p, int ipar) const {
00221
00222 std::copy(p, p+fN, fVec.begin());
00223 double f0 = fFunc(x, p);
00224 return DoParameterDerivative(x,p,f0,ipar);
00225 }
00226
00227
00228 void ParameterGradient(const double * x, const double * p, double f0, double * g) {
00229
00230 std::copy(p, p+fN, fVec.begin());
00231 for (unsigned int k = 0; k < fN; ++k) {
00232 g[k] = DoParameterDerivative(x,p,f0,k);
00233 }
00234 }
00235
00236
00237 void Gradient(const double * x, const double * p, double f0, double * g) {
00238
00239 std::copy(x, x+fN, fVec.begin());
00240 for (unsigned int k = 0; k < fN; ++k) {
00241 double x0 = x[k];
00242 double h = std::max( fEps* std::abs(x0), 8.0*fPrecision*(std::abs(x0) + fPrecision) );
00243 fVec[k] += h;
00244
00245
00246 double f1 = fFunc( &fVec.front(), p );
00247 if (fStrategy > 1) {
00248 fVec[k] = x0 - h;
00249 double f2 = fFunc( &fVec.front(), p );
00250 g[k] = 0.5 * ( f2 - f1 )/h;
00251 }
00252 else
00253 g[k] = ( f1 - f0 )/h;
00254
00255 fVec[k] = x[k];
00256 }
00257 }
00258
00259 private:
00260
00261 double fEps;
00262 double fPrecision;
00263 int fStrategy;
00264 unsigned int fN;
00265 const IModelFunction & fFunc;
00266 mutable std::vector<double> fVec;
00267 };
00268
00269
00270
00271 double CorrectValue(double rval) {
00272
00273 if (rval > - std::numeric_limits<double>::max() && rval < std::numeric_limits<double>::max() )
00274 return rval;
00275 else if (rval < 0)
00276
00277 return -std::numeric_limits<double>::max();
00278 else
00279
00280 return + std::numeric_limits<double>::max();
00281 }
00282 bool CheckValue(double & rval) {
00283 if (rval > - std::numeric_limits<double>::max() && rval < std::numeric_limits<double>::max() )
00284 return true;
00285 else if (rval < 0) {
00286
00287 rval = -std::numeric_limits<double>::max();
00288 return false;
00289 }
00290 else {
00291
00292 rval = + std::numeric_limits<double>::max();
00293 return false;
00294 }
00295 }
00296
00297
00298
00299
00300
00301 template <class GFunc>
00302 void CalculateGradientIntegral(const GFunc & gfunc,
00303 const double *x1, const double * x2, const double * p, double *g) {
00304
00305
00306 ParamDerivFunc<GFunc> pfunc( gfunc);
00307 IntegralEvaluator<ParamDerivFunc<GFunc> > igDerEval( pfunc, p, true);
00308
00309 unsigned int npar = gfunc.NPar();
00310 for (unsigned int k = 0; k < npar; ++k ) {
00311 pfunc.SetDerivComponent(k);
00312 g[k] = igDerEval( x1, x2 );
00313 }
00314 }
00315
00316
00317
00318 }
00319
00320
00321
00322
00323
00324
00325
00326 double FitUtil::EvaluateChi2(const IModelFunction & func, const BinData & data, const double * p, unsigned int & nPoints) {
00327
00328
00329
00330
00331
00332 unsigned int n = data.Size();
00333
00334
00335 #ifdef DEBUG
00336 std::cout << "\n\nFit data size = " << n << std::endl;
00337 std::cout << "evaluate chi2 using function " << &func << " " << p << std::endl;
00338 #endif
00339
00340
00341 double chi2 = 0;
00342
00343
00344
00345
00346
00347
00348
00349 const DataOptions & fitOpt = data.Opt();
00350 bool useBinIntegral = fitOpt.fIntegral && data.HasBinEdges();
00351 bool useBinVolume = (fitOpt.fBinVolume && data.HasBinEdges());
00352
00353 IntegralEvaluator<> igEval( func, p, useBinIntegral);
00354
00355 double maxResValue = std::numeric_limits<double>::max() /n;
00356 double wrefVolume = 1.0;
00357 std::vector<double> xc;
00358 if (useBinVolume) {
00359 wrefVolume /= data.RefVolume();
00360 xc.resize(data.NDim() );
00361 }
00362
00363 for (unsigned int i = 0; i < n; ++ i) {
00364
00365
00366 double y, invError;
00367
00368 const double * x1 = data.GetPoint(i,y, invError);
00369
00370 double fval = 0;
00371
00372 double binVolume = 1.0;
00373 if (useBinVolume) {
00374 unsigned int ndim = data.NDim();
00375 const double * x2 = data.BinUpEdge(i);
00376 for (unsigned int j = 0; j < ndim; ++j) {
00377 binVolume *= std::abs( x2[j]-x1[j] );
00378 xc[j] = 0.5*(x2[j]+ x1[j]);
00379 }
00380
00381 binVolume *= wrefVolume;
00382 }
00383
00384 const double * x = (useBinVolume) ? &xc.front() : x1;
00385
00386 if (!useBinIntegral) {
00387 fval = func ( x, p );
00388 }
00389 else {
00390
00391
00392 fval = igEval( x1, data.BinUpEdge(i)) ;
00393 }
00394
00395 if (useBinVolume) fval *= binVolume;
00396
00397
00398 #ifdef DEBUG
00399 std::cout << x[0] << " " << y << " " << 1./invError << " params : ";
00400 for (unsigned int ipar = 0; ipar < func.NPar(); ++ipar)
00401 std::cout << p[ipar] << "\t";
00402 std::cout << "\tfval = " << fval << " bin volume " << binVolume << " ref " << wrefVolume << std::endl;
00403 #endif
00404
00405
00406
00407 double tmp = ( y -fval )* invError;
00408 double resval = tmp * tmp;
00409
00410
00411
00412 if ( resval < maxResValue )
00413 chi2 += resval;
00414 else {
00415
00416 chi2 += maxResValue;
00417 }
00418
00419
00420 }
00421
00422
00423 nPoints = n;
00424
00425
00426 #ifdef DEBUG
00427 std::cout << "chi2 = " << chi2 << " n = " << nPoints << std::endl;
00428 #endif
00429
00430
00431 return chi2;
00432 }
00433
00434
00435
00436
00437 double FitUtil::EvaluateChi2Effective(const IModelFunction & func, const BinData & data, const double * p, unsigned int & nPoints) {
00438
00439
00440
00441
00442
00443 unsigned int n = data.Size();
00444
00445 #ifdef DEBUG
00446 std::cout << "\n\nFit data size = " << n << std::endl;
00447 std::cout << "evaluate effective chi2 using function " << &func << " " << p << std::endl;
00448 #endif
00449
00450 assert(data.HaveCoordErrors() );
00451
00452 double chi2 = 0;
00453
00454
00455
00456
00457
00458 unsigned int ndim = func.NDim();
00459
00460
00461 ROOT::Math::RichardsonDerivator derivator;
00462
00463 double maxResValue = std::numeric_limits<double>::max() /n;
00464
00465
00466
00467 for (unsigned int i = 0; i < n; ++ i) {
00468
00469
00470 double y = 0;
00471 const double * x = data.GetPoint(i,y);
00472
00473 double fval = func( x, p );
00474
00475 double delta_y_func = y - fval;
00476
00477
00478 double ey = 0;
00479 const double * ex = 0;
00480 if (!data.HaveAsymErrors() )
00481 ex = data.GetPointError(i, ey);
00482 else {
00483 double eylow, eyhigh = 0;
00484 ex = data.GetPointError(i, eylow, eyhigh);
00485 if ( delta_y_func < 0)
00486 ey = eyhigh;
00487 else
00488 ey = eylow;
00489 }
00490 double e2 = ey * ey;
00491
00492 unsigned int j = 0;
00493 while ( j < ndim && ex[j] == 0.) { j++; }
00494
00495 if (j < ndim) {
00496
00497 ROOT::Math::OneDimMultiFunctionAdapter<const IModelFunction &> f1D(func,x,0,p);
00498
00499 double kEps = 0.001;
00500 double kPrecision = 1.E-8;
00501 for (unsigned int icoord = 0; icoord < ndim; ++icoord) {
00502
00503 if (ex[icoord] > 0) {
00504
00505 f1D.SetCoord(icoord);
00506
00507 double x0= x[icoord];
00508 double h = std::max( kEps* std::abs(x0), 8.0*kPrecision*(std::abs(x0) + kPrecision) );
00509 double deriv = derivator.Derivative1(f1D, x[icoord], h);
00510 double edx = ex[icoord] * deriv;
00511 e2 += edx * edx;
00512 }
00513 }
00514 }
00515 double w2 = (e2 > 0) ? 1.0/e2 : 0;
00516 double resval = w2 * ( y - fval ) * ( y - fval);
00517
00518 #ifdef DEBUG
00519 std::cout << x[0] << " " << y << " ex " << e2 << " ey " << ey << " params : ";
00520 for (unsigned int ipar = 0; ipar < func.NPar(); ++ipar)
00521 std::cout << p[ipar] << "\t";
00522 std::cout << "\tfval = " << fval << "\tresval = " << resval << std::endl;
00523 #endif
00524
00525
00526
00527 if ( resval < maxResValue )
00528 chi2 += resval;
00529 else
00530 chi2 += maxResValue;
00531
00532
00533 }
00534
00535
00536 nPoints = n;
00537
00538
00539 #ifdef DEBUG
00540 std::cout << "chi2 = " << chi2 << " n = " << nPoints << << std::endl;
00541 #endif
00542
00543 return chi2;
00544
00545 }
00546
00547
00548
00549 double FitUtil::EvaluateChi2Residual(const IModelFunction & func, const BinData & data, const double * p, unsigned int i, double * g) {
00550
00551
00552
00553
00554
00555
00556 if (data.GetErrorType() == BinData::kCoordError && data.Opt().fCoordErrors ) {
00557 MATH_ERROR_MSG("FitUtil::EvaluateChi2Residual","Error on the coordinates are not used in calculating Chi2 residual");
00558 return 0;
00559 }
00560
00561
00562
00563
00564 double y, invError = 0;
00565
00566 const DataOptions & fitOpt = data.Opt();
00567 bool useBinIntegral = fitOpt.fIntegral && data.HasBinEdges();
00568 bool useBinVolume = (fitOpt.fBinVolume && data.HasBinEdges());
00569
00570 const double * x1 = data.GetPoint(i,y, invError);
00571
00572 IntegralEvaluator<> igEval( func, p, useBinIntegral);
00573 double fval = 0;
00574 unsigned int ndim = data.NDim();
00575 double binVolume = 1.0;
00576 const double * x2 = 0;
00577 if (useBinVolume || useBinIntegral) x2 = data.BinUpEdge(i);
00578
00579 double * xc = 0;
00580
00581 if (useBinVolume) {
00582 xc = new double[ndim];
00583 for (unsigned int j = 0; j < ndim; ++j) {
00584 binVolume *= std::abs( x2[j]-x1[j] );
00585 xc[j] = 0.5*(x2[j]+ x1[j]);
00586 }
00587
00588 binVolume /= data.RefVolume();
00589 }
00590
00591 const double * x = (useBinVolume) ? xc : x1;
00592
00593 if (!useBinIntegral) {
00594 fval = func ( x, p );
00595 }
00596 else {
00597
00598
00599 fval = igEval( x1, x2) ;
00600 }
00601
00602 if (useBinVolume) fval *= binVolume;
00603
00604 double resval = ( y -fval )* invError;
00605
00606
00607 resval = CorrectValue(resval);
00608
00609
00610 if (g != 0) {
00611
00612 unsigned int npar = func.NPar();
00613 const IGradModelFunction * gfunc = dynamic_cast<const IGradModelFunction *>( &func);
00614
00615 if (gfunc != 0) {
00616
00617 if (!useBinIntegral ) {
00618 gfunc->ParameterGradient( x , p, g );
00619 }
00620 else {
00621
00622 CalculateGradientIntegral( *gfunc, x1, x2, p, g);
00623 }
00624 }
00625 else {
00626 SimpleGradientCalculator gc( npar, func);
00627 if (!useBinIntegral )
00628 gc.ParameterGradient(x, p, fval, g);
00629 else {
00630
00631 CalculateGradientIntegral( gc, x1, x2, p, g);
00632 }
00633 }
00634
00635 for (unsigned int k = 0; k < npar; ++k) {
00636 g[k] *= - invError;
00637 if (useBinVolume) g[k] *= binVolume;
00638 }
00639 }
00640
00641 if (useBinVolume) delete [] xc;
00642
00643 return resval;
00644
00645 }
00646
00647 void FitUtil::EvaluateChi2Gradient(const IModelFunction & f, const BinData & data, const double * p, double * grad, unsigned int & nPoints) {
00648
00649
00650
00651
00652
00653
00654 if ( data.HaveCoordErrors() ) {
00655 MATH_ERROR_MSG("FitUtil::EvaluateChi2Residual","Error on the coordinates are not used in calculating Chi2 gradient"); return;
00656 }
00657
00658 unsigned int nRejected = 0;
00659
00660 const IGradModelFunction * fg = dynamic_cast<const IGradModelFunction *>( &f);
00661 assert (fg != 0);
00662
00663 const IGradModelFunction & func = *fg;
00664 unsigned int n = data.Size();
00665
00666
00667 #ifdef DEBUG
00668 std::cout << "\n\nFit data size = " << n << std::endl;
00669 std::cout << "evaluate chi2 using function gradient " << &func << " " << p << std::endl;
00670 #endif
00671
00672 const DataOptions & fitOpt = data.Opt();
00673 bool useBinIntegral = fitOpt.fIntegral && data.HasBinEdges();
00674 bool useBinVolume = (fitOpt.fBinVolume && data.HasBinEdges());
00675
00676 double wrefVolume = 1.0;
00677 std::vector<double> xc;
00678 if (useBinVolume) {
00679 wrefVolume /= data.RefVolume();
00680 xc.resize(data.NDim() );
00681 }
00682
00683 IntegralEvaluator<> igEval( func, p, useBinIntegral);
00684
00685
00686
00687
00688 unsigned int npar = func.NPar();
00689
00690 std::vector<double> gradFunc( npar );
00691
00692 std::vector<double> g( npar);
00693
00694 for (unsigned int i = 0; i < n; ++ i) {
00695
00696
00697 double y, invError = 0;
00698 const double * x1 = data.GetPoint(i,y, invError);
00699
00700 double fval = 0;
00701 const double * x2 = 0;
00702
00703 double binVolume = 1;
00704 if (useBinVolume) {
00705 unsigned int ndim = data.NDim();
00706 x2 = data.BinUpEdge(i);
00707 for (unsigned int j = 0; j < ndim; ++j) {
00708 binVolume *= std::abs( x2[j]-x1[j] );
00709 xc[j] = 0.5*(x2[j]+ x1[j]);
00710 }
00711
00712 binVolume *= wrefVolume;
00713 }
00714
00715 const double * x = (useBinVolume) ? &xc.front() : x1;
00716
00717 if (!useBinIntegral ) {
00718 fval = func ( x, p );
00719 func.ParameterGradient( x , p, &gradFunc[0] );
00720 }
00721 else {
00722 x2 = data.BinUpEdge(i);
00723
00724
00725 fval = igEval( x1, x2 ) ;
00726 CalculateGradientIntegral( func, x1, x2, p, &gradFunc[0]);
00727 }
00728 if (useBinVolume) fval *= binVolume;
00729
00730 #ifdef DEBUG
00731 std::cout << x[0] << " " << y << " " << 1./invError << " params : ";
00732 for (unsigned int ipar = 0; ipar < npar; ++ipar)
00733 std::cout << p[ipar] << "\t";
00734 std::cout << "\tfval = " << fval << std::endl;
00735 #endif
00736 if ( !CheckValue(fval) ) {
00737 nRejected++;
00738 continue;
00739 }
00740
00741
00742 unsigned int ipar = 0;
00743 for ( ; ipar < npar ; ++ipar) {
00744
00745
00746 if (useBinVolume) gradFunc[ipar] *= binVolume;
00747
00748
00749
00750 double dfval = gradFunc[ipar];
00751 if ( !CheckValue(dfval) ) {
00752 break;
00753 }
00754
00755
00756 double tmp = - 2.0 * ( y -fval )* invError * invError * gradFunc[ipar];
00757 g[ipar] += tmp;
00758
00759 }
00760
00761 if ( ipar < npar ) {
00762
00763 nRejected++;
00764 continue;
00765 }
00766
00767
00768 }
00769
00770
00771 nPoints = n;
00772 if (nRejected != 0) {
00773 assert(nRejected <= n);
00774 nPoints = n - nRejected;
00775 if (nPoints < npar) MATH_ERROR_MSG("FitUtil::EvaluateChi2Gradient","Error - too many points rejected for overflow in gradient calculation");
00776 }
00777
00778
00779 std::copy(g.begin(), g.end(), grad);
00780
00781 }
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 double FitUtil::EvaluatePdf(const IModelFunction & func, const UnBinData & data, const double * p, unsigned int i, double * g) {
00793
00794
00795
00796
00797
00798
00799 const double * x = data.Coords(i);
00800 double fval = func ( x, p );
00801 double logPdf = ROOT::Math::Util::EvalLog(fval);
00802
00803 if (g == 0) return logPdf;
00804
00805 const IGradModelFunction * gfunc = dynamic_cast<const IGradModelFunction *>( &func);
00806
00807
00808 if (gfunc != 0) {
00809
00810 gfunc->ParameterGradient( x , p, g );
00811 }
00812 else {
00813
00814
00815 SimpleGradientCalculator gc(func.NPar(), func);
00816 gc.ParameterGradient(x, p, fval, g );
00817 }
00818
00819 for (unsigned int ipar = 0; ipar < func.NPar(); ++ipar) {
00820 g[ipar] /= fval;
00821 }
00822
00823 #ifdef DEBUG
00824 std::cout << x[i] << "\t";
00825 std::cout << "\tpar = [ " << func.NPar() << " ] = ";
00826 for (unsigned int ipar = 0; ipar < func.NPar(); ++ipar)
00827 std::cout << p[ipar] << "\t";
00828 std::cout << "\tfval = " << fval;
00829 std::cout << "\tgrad = [ ";
00830 for (unsigned int ipar = 0; ipar < func.NPar(); ++ipar)
00831 std::cout << g[ipar] << "\t";
00832 std::cout << " ] " << std::endl;
00833 #endif
00834
00835
00836 return logPdf;
00837 }
00838
00839 double FitUtil::EvaluateLogL(const IModelFunction & func, const UnBinData & data, const double * p, unsigned int &nPoints) {
00840
00841
00842 unsigned int n = data.Size();
00843
00844 #ifdef DEBUG
00845 std::cout << "\n\nFit data size = " << n << std::endl;
00846 std::cout << "func pointer is " << typeid(func).name() << std::endl;
00847 #endif
00848
00849 double logl = 0;
00850
00851
00852 for (unsigned int i = 0; i < n; ++ i) {
00853 const double * x = data.Coords(i);
00854 double fval = func ( x, p );
00855
00856 #ifdef DEBUG
00857 std::cout << "x [ " << data.PointSize() << " ] = ";
00858 for (unsigned int j = 0; j < data.PointSize(); ++j)
00859 std::cout << x[j] << "\t";
00860 std::cout << "\tpar = [ " << func.NPar() << " ] = ";
00861 for (unsigned int ipar = 0; ipar < func.NPar(); ++ipar)
00862 std::cout << p[ipar] << "\t";
00863 std::cout << "\tfval = " << fval << std::endl;
00864 #endif
00865
00866 logl += ROOT::Math::Util::EvalLog( fval);
00867 }
00868
00869
00870 nPoints = n;
00871
00872
00873
00874
00875
00876
00877
00878
00879 #ifdef DEBUG
00880 std::cout << "Logl = " << logl << " np = " << nPoints << std::endl;
00881 #endif
00882
00883 return -logl;
00884 }
00885
00886 void FitUtil::EvaluateLogLGradient(const IModelFunction & f, const UnBinData & data, const double * p, double * grad, unsigned int & ) {
00887
00888
00889 const IGradModelFunction * fg = dynamic_cast<const IGradModelFunction *>( &f);
00890 assert (fg != 0);
00891 const IGradModelFunction & func = *fg;
00892
00893 unsigned int n = data.Size();
00894
00895
00896 unsigned int npar = func.NPar();
00897 std::vector<double> gradFunc( npar );
00898 std::vector<double> g( npar);
00899
00900 for (unsigned int i = 0; i < n; ++ i) {
00901 const double * x = data.Coords(i);
00902 double fval = func ( x , p);
00903 func.ParameterGradient( x, p, &gradFunc[0] );
00904 for (unsigned int kpar = 0; kpar < npar; ++ kpar) {
00905 if (fval > 0)
00906 g[kpar] -= 1./fval * gradFunc[ kpar ];
00907 else if (gradFunc [ kpar] != 0) {
00908 const double kdmax1 = std::sqrt( std::numeric_limits<double>::max() );
00909 const double kdmax2 = std::numeric_limits<double>::max() / (4*n);
00910 double gg = kdmax1 * gradFunc[ kpar ];
00911 if ( gg > 0) gg = std::min( gg, kdmax2);
00912 else gg = std::max(gg, - kdmax2);
00913 g[kpar] -= gg;
00914 }
00915
00916 }
00917
00918
00919 std::copy(g.begin(), g.end(), grad);
00920 }
00921 }
00922
00923
00924
00925 double FitUtil::EvaluatePoissonBinPdf(const IModelFunction & func, const BinData & data, const double * p, unsigned int i, double * g ) {
00926
00927
00928
00929
00930 double y = 0;
00931 const double * x1 = data.GetPoint(i,y);
00932
00933 const DataOptions & fitOpt = data.Opt();
00934 bool useBinIntegral = fitOpt.fIntegral && data.HasBinEdges();
00935 bool useBinVolume = (fitOpt.fBinVolume && data.HasBinEdges());
00936
00937 IntegralEvaluator<> igEval( func, p, useBinIntegral);
00938 double fval = 0;
00939 const double * x2 = 0;
00940
00941 double binVolume = 1;
00942 std::vector<double> xc;
00943 if (useBinVolume) {
00944 unsigned int ndim = data.NDim();
00945 xc.resize(ndim);
00946 x2 = data.BinUpEdge(i);
00947 for (unsigned int j = 0; j < ndim; ++j) {
00948 binVolume *= std::abs( x2[j]-x1[j] );
00949 xc[j] = 0.5*(x2[j]+ x1[j]);
00950 }
00951
00952 binVolume /= data.RefVolume();
00953 }
00954
00955 const double * x = (useBinVolume) ? &xc.front() : x1;
00956
00957 if (!useBinIntegral ) {
00958 fval = func ( x, p );
00959 }
00960 else {
00961
00962 x2 = data.BinUpEdge(i);
00963 fval = igEval( x1, x2 ) ;
00964 }
00965 if (useBinVolume) fval *= binVolume;
00966
00967
00968 fval = std::max(fval, 0.0);
00969 double logPdf = y * ROOT::Math::Util::EvalLog( fval) - fval;
00970
00971
00972
00973
00974
00975 if (g == 0) return logPdf;
00976
00977 unsigned int npar = func.NPar();
00978 const IGradModelFunction * gfunc = dynamic_cast<const IGradModelFunction *>( &func);
00979
00980
00981 if (gfunc != 0) {
00982
00983 if (!useBinIntegral )
00984 gfunc->ParameterGradient( x , p, g );
00985 else {
00986
00987 CalculateGradientIntegral( *gfunc, x1, x2, p, g);
00988 }
00989
00990 }
00991 else {
00992 SimpleGradientCalculator gc(func.NPar(), func);
00993 if (!useBinIntegral )
00994 gc.ParameterGradient(x, p, fval, g);
00995 else {
00996
00997 CalculateGradientIntegral( gc, x1, x2, p, g);
00998 }
00999 }
01000
01001 for (unsigned int k = 0; k < npar; ++k) {
01002
01003 if (useBinVolume) g[k] *= binVolume;
01004
01005
01006 if ( fval > 0)
01007 g[k] *= ( y/fval - 1.) ;
01008 else if (y > 0) {
01009 const double kdmax1 = std::sqrt( std::numeric_limits<double>::max() );
01010 g[k] *= kdmax1;
01011 }
01012 else
01013 g[k] *= -1;
01014 }
01015
01016
01017 #ifdef DEBUG
01018 std::cout << "x = " << x[0] << " logPdf = " << logPdf << " grad";
01019 for (unsigned int ipar = 0; ipar < npar; ++ipar)
01020 std::cout << g[ipar] << "\t";
01021 std::cout << std::endl;
01022 #endif
01023
01024
01025 return logPdf;
01026 }
01027
01028 double FitUtil::EvaluatePoissonLogL(const IModelFunction & func, const BinData & data, const double * p, unsigned int & nPoints ) {
01029
01030
01031
01032
01033 unsigned int n = data.Size();
01034 #ifdef DEBUG
01035 std::cout << "Evaluate PoissonLogL for params = [ ";
01036 for (unsigned int j=0; j < func.NPar(); ++j) std::cout << p[j] << " , ";
01037 std::cout << "] - data size = " << n << std::endl;
01038 #endif
01039
01040 double loglike = 0;
01041
01042
01043
01044 const DataOptions & fitOpt = data.Opt();
01045 bool useBinIntegral = fitOpt.fIntegral && data.HasBinEdges();
01046 bool useBinVolume = (fitOpt.fBinVolume && data.HasBinEdges());
01047
01048 double wrefVolume = 1.0;
01049 std::vector<double> xc;
01050 if (useBinVolume) {
01051 wrefVolume /= data.RefVolume();
01052 xc.resize(data.NDim() );
01053 }
01054
01055 IntegralEvaluator<> igEval( func, p, fitOpt.fIntegral);
01056
01057 for (unsigned int i = 0; i < n; ++ i) {
01058 const double * x1 = data.Coords(i);
01059 double y = data.Value(i);
01060
01061 double fval = 0;
01062 double binVolume = 1.0;
01063
01064 if (useBinVolume) {
01065 unsigned int ndim = data.NDim();
01066 const double * x2 = data.BinUpEdge(i);
01067 for (unsigned int j = 0; j < ndim; ++j) {
01068 binVolume *= std::abs( x2[j]-x1[j] );
01069 xc[j] = 0.5*(x2[j]+ x1[j]);
01070 }
01071
01072 binVolume *= wrefVolume;
01073 }
01074
01075 const double * x = (useBinVolume) ? &xc.front() : x1;
01076
01077 if (!useBinIntegral) {
01078 fval = func ( x, p );
01079 }
01080 else {
01081
01082
01083 fval = igEval( x1, data.BinUpEdge(i)) ;
01084 }
01085 if (useBinVolume) fval *= binVolume;
01086
01087
01088 #ifdef DEBUG
01089 int NSAMPLE = 100;
01090 if (i%NSAMPLE == 0) {
01091 std::cout << "evt " << i << " x1 = [ ";
01092 for (unsigned int j=0; j < func.NDim(); ++j) std::cout << x[j] << " , ";
01093 std::cout << "] ";
01094 if (fitOpt.fIntegral) {
01095 std::cout << "x2 = [ ";
01096 for (unsigned int j=0; j < func.NDim(); ++j) std::cout << data.BinUpEdge(i)[j] << " , ";
01097 std::cout << "] ";
01098 }
01099 std::cout << " y = " << y << " fval = " << fval << std::endl;
01100 }
01101 #endif
01102
01103
01104
01105
01106 fval = std::max(fval, 0.0);
01107 loglike += fval - y * ROOT::Math::Util::EvalLog( fval);
01108
01109 }
01110
01111
01112 nPoints = n;
01113
01114
01115 #ifdef DEBUG
01116 std::cout << "Loglikelihood = " << loglike << std::endl;
01117 #endif
01118
01119 return loglike;
01120 }
01121
01122 void FitUtil::EvaluatePoissonLogLGradient(const IModelFunction & f, const BinData & data, const double * p, double * grad ) {
01123
01124
01125 const IGradModelFunction * fg = dynamic_cast<const IGradModelFunction *>( &f);
01126 assert (fg != 0);
01127 const IGradModelFunction & func = *fg;
01128
01129 unsigned int n = data.Size();
01130
01131 const DataOptions & fitOpt = data.Opt();
01132 bool useBinIntegral = fitOpt.fIntegral && data.HasBinEdges();
01133 bool useBinVolume = (fitOpt.fBinVolume && data.HasBinEdges());
01134
01135 double wrefVolume = 1.0;
01136 std::vector<double> xc;
01137 if (useBinVolume) {
01138 wrefVolume /= data.RefVolume();
01139 xc.resize(data.NDim() );
01140 }
01141
01142 IntegralEvaluator<> igEval( func, p, useBinIntegral);
01143
01144 unsigned int npar = func.NPar();
01145 std::vector<double> gradFunc( npar );
01146 std::vector<double> g( npar);
01147
01148 for (unsigned int i = 0; i < n; ++ i) {
01149 const double * x1 = data.Coords(i);
01150 double y = data.Value(i);
01151 double fval = 0;
01152 const double * x2 = 0;
01153
01154 double binVolume = 1.0;
01155 if (useBinVolume) {
01156 x2 = data.BinUpEdge(i);
01157 unsigned int ndim = data.NDim();
01158 for (unsigned int j = 0; j < ndim; ++j) {
01159 binVolume *= std::abs( x2[j]-x1[j] );
01160 xc[j] = 0.5*(x2[j]+ x1[j]);
01161 }
01162
01163 binVolume *= wrefVolume;
01164 }
01165
01166 const double * x = (useBinVolume) ? &xc.front() : x1;
01167
01168 if (!useBinIntegral) {
01169 fval = func ( x, p );
01170 func.ParameterGradient( x , p, &gradFunc[0] );
01171 }
01172 else {
01173
01174
01175 x2 = data.BinUpEdge(i);
01176 fval = igEval( x1, x2) ;
01177 CalculateGradientIntegral( func, x1, x2, p, &gradFunc[0]);
01178 }
01179 if (useBinVolume) fval *= binVolume;
01180
01181
01182 for (unsigned int kpar = 0; kpar < npar; ++ kpar) {
01183
01184
01185 if (useBinVolume) gradFunc[kpar] *= binVolume;
01186
01187
01188 if (fval > 0)
01189 g[kpar] += gradFunc[ kpar ] * ( 1. - y/fval );
01190 else if (gradFunc [ kpar] != 0) {
01191 const double kdmax1 = std::sqrt( std::numeric_limits<double>::max() );
01192 const double kdmax2 = std::numeric_limits<double>::max() / (4*n);
01193 double gg = kdmax1 * gradFunc[ kpar ];
01194 if ( gg > 0) gg = std::min( gg, kdmax2);
01195 else gg = std::max(gg, - kdmax2);
01196 g[kpar] -= gg;
01197 }
01198 }
01199
01200
01201 std::copy(g.begin(), g.end(), grad);
01202 }
01203 }
01204
01205 }
01206
01207 }
01208