00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "TFumiliFCN.h"
00011 #include "TChi2FCN.h"
00012 #include "TBinLikelihoodFCN.h"
00013 #include "TChi2FitData.h"
00014 #include "FitterUtil.h"
00015
00016 #include "TF1.h"
00017 #include "TVirtualFitter.h"
00018
00019
00020
00021
00022 #ifdef DEBUG
00023 #include <iostream>
00024 #endif
00025
00026 #include <cmath>
00027
00028 static const double kPrecision = 1.E-16;
00029 static const double kEpsilon = 1.E-300;
00030
00031
00032
00033
00034 TFumiliFCN::TFumiliFCN( const TVirtualFitter & fitter, double up, int strategy, bool skipEmptyBins) :
00035 FumiliFCNBase()
00036 {
00037
00038
00039
00040
00041 fUp = up;
00042 fFunc = dynamic_cast<TF1 *> ( fitter.GetUserFunc() );
00043 assert(fFunc != 0);
00044
00045 fData = new TChi2FitData(fitter, skipEmptyBins);
00046
00047
00048
00049 fFunc->SetNumberFitPoints(fData->Size());
00050
00051 fStrategy = strategy;
00052
00053
00054 }
00055
00056
00057 TFumiliFCN::~TFumiliFCN() {
00058
00059
00060 if (fData) {
00061
00062 delete fData;
00063 }
00064 }
00065
00066
00067 void TFumiliFCN::Initialize(unsigned int nPar) {
00068
00069
00070
00071 fParamCache = std::vector<double>(nPar);
00072 fFunctionGradient = std::vector<double>( nPar );
00073
00074 InitAndReset(nPar);
00075 }
00076
00077
00078 void TFumiliFCN::EvaluateAll( const std::vector<double> & p) {
00079
00080 Calculate_gradient_and_hessian(p);
00081 }
00082
00083
00084 void TFumiliFCN::Calculate_gradient_and_hessian(const std::vector<double> & p) {
00085
00086
00087 unsigned int npar = p.size();
00088 if (npar != Dimension() ) {
00089
00090
00091 Initialize(npar);
00092 }
00093
00094 const FumiliFitData & points = *fData;
00095
00096
00097
00098 fFunc->SetParameters( &p.front() );
00099 fParamCache = p;
00100
00101 std::vector<double> & grad = Gradient();
00102 std::vector<double> & hess = Hessian();
00103
00104
00105 unsigned int nhdim = static_cast<int>( 0.5*npar*(npar + 1) );
00106 assert( npar == fFunctionGradient.size() );
00107 assert( npar == grad.size() );
00108 assert( nhdim == hess.size() );
00109
00110 grad.assign( npar, 0.0);
00111 hess.assign( nhdim, 0.0);
00112
00113 double sum = 0;
00114
00115
00116
00117 unsigned int nMeasurements = points.Size();
00118 unsigned int nRejected = 0;
00119 for (unsigned int i = 0; i < nMeasurements; ++i) {
00120
00121 fFunc->RejectPoint(false);
00122
00123 const std::vector<double> & x = points.Coords(i);
00124 fFunc->InitArgs( &x.front(), &fParamCache.front() );
00125
00126
00127 double fval;
00128 if ( fData->UseIntegral()) {
00129 const std::vector<double> & x2 = fData->Coords(i+1);
00130
00131 fval = FitterUtil::EvalIntegral(fFunc,x,x2,fParamCache);
00132 if (fFunc->RejectedPoint() ) {
00133 nRejected++;
00134 continue;
00135 }
00136 Calculate_numerical_gradient_of_integral( x, x2, fval);
00137
00138 }
00139 else {
00140
00141 fval = fFunc->EvalPar(&x.front(), &fParamCache.front() );
00142 if (fFunc->RejectedPoint() ) {
00143 nRejected++;
00144 continue;
00145 }
00146 Calculate_numerical_gradient( x, fval);
00147 }
00148
00149
00150
00151
00152 Calculate_element(i, points, fval, sum, grad, hess);
00153
00154
00155
00156
00157
00158 }
00159
00160 #ifdef DEBUG
00161 std::cout << "Calculated Gradient and hessian " << std::endl;
00162 for (unsigned int i = 0; i < npar; ++i)
00163 std::cout << " par " << i << " = " << fParamCache[i] << " grad = " << grad[i] << std::endl;
00164 for (unsigned int i = 0; i < npar; ++i) {
00165 for (unsigned int j = 0; j < npar; ++j)
00166 std::cout << hess[i*npar+j];
00167
00168 std::cout << std::endl;
00169 }
00170 #endif
00171
00172
00173 SetFCNValue(sum);
00174
00175
00176 if (nRejected != 0) fFunc->SetNumberFitPoints(nMeasurements-nRejected);
00177
00178
00179 }
00180
00181
00182 void TFumiliFCN::Calculate_numerical_gradient( const std::vector<double> & x, double f0) {
00183
00184
00185
00186
00187
00188 int n = fParamCache.size();
00189
00190 for (int ipar = 0; ipar < n ; ++ipar) {
00191 double p0 = fParamCache[ipar];
00192
00193 double h = std::max( 0.001* std::fabs(p0), 8.0*kPrecision*(std::fabs(p0) + kPrecision) );
00194 fParamCache[ipar] = p0 + h;
00195 double f2 = fFunc->EvalPar( &x.front(), &fParamCache.front() );
00196
00197
00198 if (fStrategy == 2) {
00199
00200 fParamCache[ipar] = p0 - h;
00201 double f1 = fFunc->EvalPar( &x.front(), &fParamCache.front() );
00202 fParamCache[ipar] = p0 + h/2;
00203 double g1 = fFunc->EvalPar( &x.front(), &fParamCache.front() );
00204 fParamCache[ipar] = p0 - h/2;
00205 double g2 = fFunc->EvalPar( &x.front(), &fParamCache.front() );
00206
00207 double h2 = 1/(2.*h);
00208 double d0 = f1 - f2;
00209 double d2 = 2*(g1 - g2);
00210
00211
00212 fFunctionGradient[ipar] = h2*(4*d2 - d0)/3.;
00213
00214 }
00215 else {
00216
00217 fFunctionGradient[ipar] = (f2 - f0)/h;
00218 }
00219
00220
00221 fParamCache[ipar] = p0;
00222
00223 }
00224
00225 }
00226
00227
00228 void TFumiliFCN::Calculate_numerical_gradient_of_integral( const std::vector<double> & x1, const std::vector<double> & x2, double f0) {
00229
00230
00231
00232
00233 int n = fParamCache.size();
00234
00235 for (int ipar = 0; ipar < n ; ++ipar) {
00236 double p0 = fParamCache[ipar];
00237
00238 double h = std::max( 0.001* std::fabs(p0), 8.0*kPrecision*(std::fabs(p0) + kPrecision) );
00239 fParamCache[ipar] = p0 + h;
00240 double f2 = FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00241
00242
00243 if (fStrategy == 2) {
00244
00245 fParamCache[ipar] = p0 - h;
00246 double f1 = FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00247 fParamCache[ipar] = p0 + h/2;
00248 double g1 = FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00249 fParamCache[ipar] = p0 - h/2;
00250 double g2 = FitterUtil::EvalIntegral(fFunc,x1,x2,fParamCache);
00251
00252 double h2 = 1/(2.*h);
00253 double d0 = f1 - f2;
00254 double d2 = 2*(g1 - g2);
00255
00256
00257 fFunctionGradient[ipar] = h2*(4*d2 - d0)/3.;
00258
00259 }
00260 else {
00261
00262 fFunctionGradient[ipar] = (f2 - f0)/h;
00263 }
00264
00265
00266 fParamCache[ipar] = p0;
00267
00268 }
00269
00270 }
00271
00272
00273
00274 void TFumiliChi2FCN::Calculate_element(int i, const FumiliFitData & points, double fval, double & chi2, std::vector<double> & grad, std::vector<double> & hess ) {
00275
00276
00277 double invError = points.InvError(i);
00278 double value = points.Value(i);
00279 double element = invError*( fval - value );
00280 unsigned int npar = grad.size();
00281
00282 chi2 += element*element;
00283
00284 for (unsigned int j = 0; j < npar; ++j) {
00285
00286 double fj = invError * fFunctionGradient[j];
00287 grad[j] += 2.0 * element * fj;
00288
00289
00290
00291 for (unsigned int k = j; k < npar; ++ k) {
00292 int idx = j + k*(k+1)/2;
00293 hess[idx] += 2.0 * fj * invError * fFunctionGradient[k];
00294 }
00295 }
00296
00297
00298 }
00299
00300
00301 void TFumiliBinLikelihoodFCN::Calculate_element(int i, const FumiliFitData & points, double fval, double & logLike, std::vector<double> & grad, std::vector<double> & hess ) {
00302
00303
00304 unsigned int npar = grad.size();
00305
00306
00307 double logtmp, invFval;
00308 if(fval<=kEpsilon) {
00309 logtmp = fval/kEpsilon + std::log(kEpsilon) - 1;
00310 invFval = 1.0/kEpsilon;
00311 } else {
00312 logtmp = std::log(fval);
00313 invFval = 1.0/fval;
00314 }
00315
00316 double value = points.Value(i);
00317 logLike += 2.*( fval - value*logtmp );
00318
00319
00320 for (unsigned int j = 0; j < npar; ++j) {
00321
00322 double fj;
00323 if ( fval < kPrecision && std::fabs(fFunctionGradient[j]) < kPrecision )
00324 fj = 2.0;
00325 else
00326 fj = 2.* fFunctionGradient[j] * ( 1.0 - value*invFval);
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 grad[j] += fj;
00337
00338 for (unsigned int k = j; k < npar; ++ k) {
00339 int idx = j + k*(k+1)/2;
00340 double fk;
00341 if ( fval < kPrecision && std::fabs(fFunctionGradient[k]) < kPrecision )
00342 fk = 1.0;
00343 else
00344 fk = fFunctionGradient[k]* ( 1.0 - value*invFval);
00345
00346
00347 hess[idx] += fj * fk;
00348 }
00349 }
00350
00351 }
00352
00353
00354 void TFumiliUnbinLikelihoodFCN::Calculate_element(int , const FumiliFitData &, double fval, double & logLike, std::vector<double> & grad, std::vector<double> & hess ) {
00355
00356
00357 unsigned int npar = grad.size();
00358
00359
00360
00361
00362 double logtmp, invFval;
00363 if(fval<=kEpsilon) {
00364 logtmp = fval/kEpsilon + std::log(kEpsilon) - 1;
00365 invFval = 1.0/kEpsilon;
00366 } else {
00367 logtmp = std::log(fval);
00368 invFval = 1.0/fval;
00369 }
00370
00371 logLike += logtmp;
00372 for (unsigned int j = 0; j < npar; ++j) {
00373
00374 double fj;
00375 if ( fval < kPrecision && std::fabs(fFunctionGradient[j]) < kPrecision )
00376 fj = 2.0;
00377 else
00378 fj = 2.* invFval * fFunctionGradient[j];
00379
00380 grad[j] -= fj;
00381
00382 for (unsigned int k = j; k < npar; ++ k) {
00383 int idx = j + k*(k+1)/2;
00384 double fk;
00385 if ( fval < kPrecision && std::fabs(fFunctionGradient[k]) < kPrecision )
00386 fk = 1.0;
00387 else
00388 fk = invFval * fFunctionGradient[k];
00389
00390
00391 hess[idx] += fj * fk;
00392 }
00393 }
00394 }
00395
00396
00397
00398 double TFumiliChi2FCN::operator()(const std::vector<double>& par) const {
00399
00400 assert(fData != 0);
00401 assert(fFunc != 0);
00402
00403 TChi2FCN fcn(fData,fFunc);
00404 return fcn(par);
00405 }
00406
00407
00408 double TFumiliBinLikelihoodFCN::operator()(const std::vector<double>& par) const {
00409
00410 assert(fData != 0);
00411 assert(fFunc != 0);
00412
00413 TBinLikelihoodFCN fcn(fData,fFunc);
00414 return fcn(par);
00415 }
00416
00417 double TFumiliBinLikelihoodFCN::Chi2(const std::vector<double>& par) const {
00418
00419 TChi2FCN chi2Fcn(fData,fFunc);
00420 return chi2Fcn(par);
00421 }
00422
00423
00424 double TFumiliUnbinLikelihoodFCN::operator()(const std::vector<double>& ) const {
00425
00426 assert(fData != 0);
00427 assert(fFunc != 0);
00428
00429
00430
00431
00432 return 0;
00433 }