00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "Minuit2/MnFunctionCross.h"
00011 #include "Minuit2/FunctionMinimum.h"
00012 #include "Minuit2/MnMigrad.h"
00013 #include "Minuit2/FCNBase.h"
00014 #include "Minuit2/MnParabola.h"
00015 #include "Minuit2/MnParabolaPoint.h"
00016 #include "Minuit2/MnParabolaFactory.h"
00017 #include "Minuit2/MnCross.h"
00018 #include "Minuit2/MnMachinePrecision.h"
00019
00020
00021
00022 #if defined(DEBUG) || defined(WARNINGMSG)
00023 #include "Minuit2/MnPrint.h"
00024 #endif
00025
00026
00027 namespace ROOT {
00028
00029 namespace Minuit2 {
00030
00031
00032
00033 MnCross MnFunctionCross::operator()(const std::vector<unsigned int>& par, const std::vector<double>& pmid,
00034 const std::vector<double>& pdir, double tlr, unsigned int maxcalls) const {
00035
00036
00037
00038
00039
00040
00041
00042 unsigned int npar = par.size();
00043 unsigned int nfcn = 0;
00044 const MnMachinePrecision& prec = fState.Precision();
00045
00046
00047
00048 double up = fFCN.Up();
00049 double tlf = tlr*up;
00050
00051 double mgr_tlr = 0.05 * up;
00052 double tla = tlr;
00053 unsigned int maxitr = 15;
00054 unsigned int ipt = 0;
00055 double aminsv = fFval;
00056 double aim = aminsv + up;
00057
00058 double aopt = 0.;
00059 bool limset = false;
00060 std::vector<double> alsb(3, 0.), flsb(3, 0.);
00061
00062 #ifdef DEBUG
00063 std::cout<<"MnFunctionCross for parameter "<<par.front()<< "fmin = " << aminsv
00064 << " contur value aim = (fmin + up) = " << aim << std::endl;
00065 #endif
00066
00067
00068
00069
00070 double aulim = 100.;
00071 for(unsigned int i = 0; i < par.size(); i++) {
00072 unsigned int kex = par[i];
00073 if(fState.Parameter(kex).HasLimits()) {
00074 double zmid = pmid[i];
00075 double zdir = pdir[i];
00076 if(fabs(zdir) < fState.Precision().Eps()) continue;
00077
00078 if(zdir > 0. && fState.Parameter(kex).HasUpperLimit()) {
00079 double zlim = fState.Parameter(kex).UpperLimit();
00080 aulim = std::min(aulim, (zlim-zmid)/zdir);
00081 }
00082 else if(zdir < 0. && fState.Parameter(kex).HasLowerLimit()) {
00083 double zlim = fState.Parameter(kex).LowerLimit();
00084 aulim = std::min(aulim, (zlim-zmid)/zdir);
00085 }
00086 }
00087 }
00088
00089 #ifdef DEBUG
00090 std::cout<<"Largest allowed aulim "<< aulim << std::endl;
00091 #endif
00092
00093 if(aulim < aopt+tla) limset = true;
00094
00095
00096 MnMigrad migrad(fFCN, fState, MnStrategy(std::max(0, int(fStrategy.Strategy()-1))));
00097
00098 for(unsigned int i = 0; i < npar; i++) {
00099 #ifdef DEBUG
00100 std::cout << "MnFunctionCross: Set value for " << par[i] << " to " << pmid[i] << std::endl;
00101 #endif
00102 migrad.SetValue(par[i], pmid[i]);
00103 }
00104
00105
00106 FunctionMinimum min0 = migrad(maxcalls, mgr_tlr);
00107 nfcn += min0.NFcn();
00108
00109 #ifdef DEBUG
00110 std::cout << "MnFunctionCross: after Migrad on n-1 minimum is " << min0 << std::endl;
00111 #endif
00112
00113 if(min0.HasReachedCallLimit())
00114 return MnCross(min0.UserState(), nfcn, MnCross::CrossFcnLimit());
00115 if(!min0.IsValid()) return MnCross(fState, nfcn);
00116 if(limset == true && min0.Fval() < aim)
00117 return MnCross(min0.UserState(), nfcn, MnCross::CrossParLimit());
00118
00119 ipt++;
00120 alsb[0] = 0.;
00121 flsb[0] = min0.Fval();
00122 flsb[0] = std::max(flsb[0], aminsv + 0.1*up);
00123 aopt = sqrt(up/(flsb[0]-aminsv)) - 1.;
00124 if(fabs(flsb[0] - aim) < tlf) return MnCross(aopt, min0.UserState(), nfcn);
00125
00126 if(aopt > 1.) aopt = 1.;
00127 if(aopt < -0.5) aopt = -0.5;
00128 limset = false;
00129 if(aopt > aulim) {
00130 aopt = aulim;
00131 limset = true;
00132 }
00133 #ifdef DEBUG
00134 std::cout << "MnFunctionCross: flsb[0] = " << flsb[0] << " aopt = " << aopt << std::endl;
00135 #endif
00136
00137 for(unsigned int i = 0; i < npar; i++) {
00138 #ifdef DEBUG
00139 std::cout << "MnFunctionCross: Set new value for " << par[i] << " from " << pmid[i] << " to " << pmid[i] + (aopt)*pdir[i] << " aopt = " << aopt << std::endl;
00140 #endif
00141 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
00142 }
00143
00144 FunctionMinimum min1 = migrad(maxcalls, mgr_tlr);
00145 nfcn += min1.NFcn();
00146
00147 #ifdef DEBUG
00148 std::cout << "MnFunctionCross: after Migrad on n-1 minimum is " << min1 << std::endl;
00149 #endif
00150
00151 if(min1.HasReachedCallLimit())
00152 return MnCross(min1.UserState(), nfcn, MnCross::CrossFcnLimit());
00153 if(!min1.IsValid()) return MnCross(fState, nfcn);
00154 if(limset == true && min1.Fval() < aim)
00155 return MnCross(min1.UserState(), nfcn, MnCross::CrossParLimit());
00156
00157 ipt++;
00158 alsb[1] = aopt;
00159 flsb[1] = min1.Fval();
00160 double dfda = (flsb[1] - flsb[0])/(alsb[1] - alsb[0]);
00161
00162 #ifdef DEBUG
00163 std::cout << "aopt = " << aopt << " min1Val = " << flsb[1] << " dfda = " << dfda << std::endl;
00164 #endif
00165
00166
00167 L300:
00168 if(dfda < 0.) {
00169
00170 #ifdef DEBUG
00171 std::cout << "MnFunctionCross: dfda < 0 - iterate from " << ipt << " to max of " << maxitr << std::endl;
00172 #endif
00173
00174
00175 unsigned int maxlk = maxitr - ipt;
00176 for(unsigned int it = 0; it < maxlk; it++) {
00177 alsb[0] = alsb[1];
00178 flsb[0] = flsb[1];
00179
00180 aopt = alsb[0] + 0.2*(it+1);
00181 limset = false;
00182 if(aopt > aulim) {
00183 aopt = aulim;
00184 limset = true;
00185 }
00186 for(unsigned int i = 0; i < npar; i++) {
00187 #ifdef DEBUG
00188 std::cout << "MnFunctionCross: Set new value for " << par[i] << " to " << pmid[i] + (aopt)*pdir[i] << " aopt = " << aopt << std::endl;
00189 #endif
00190 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
00191 }
00192 min1 = migrad(maxcalls, mgr_tlr);
00193 nfcn += min1.NFcn();
00194
00195 #ifdef DEBUG
00196 std::cout << "MnFunctionCross: after Migrad on n-1 minimum is " << min1 << std::endl;
00197 std::cout << "nfcn = " << nfcn << std::endl;
00198 #endif
00199
00200 if(min1.HasReachedCallLimit())
00201 return MnCross(min1.UserState(), nfcn, MnCross::CrossFcnLimit());
00202 if(!min1.IsValid()) return MnCross(fState, nfcn);
00203 if(limset == true && min1.Fval() < aim)
00204 return MnCross(min1.UserState(), nfcn, MnCross::CrossParLimit());
00205 ipt++;
00206 alsb[1] = aopt;
00207 flsb[1] = min1.Fval();
00208 dfda = (flsb[1] - flsb[0])/(alsb[1] - alsb[0]);
00209
00210
00211 #ifdef DEBUG
00212 std::cout << "aopt = " << aopt << " min1Val = " << flsb[1] << " dfda = " << dfda << std::endl;
00213 #endif
00214
00215 if(dfda > 0.) break;
00216 }
00217 if(ipt > maxitr) return MnCross(fState, nfcn);
00218 }
00219
00220 L460:
00221
00222
00223
00224 aopt = alsb[1] + (aim-flsb[1])/dfda;
00225
00226 #ifdef DEBUG
00227 std::cout << "MnFunctionCross: dfda > 0 : aopt = " << aopt << std::endl;
00228 #endif
00229
00230 double fdist = std::min(fabs(aim - flsb[0]), fabs(aim - flsb[1]));
00231 double adist = std::min(fabs(aopt - alsb[0]), fabs(aopt - alsb[1]));
00232 tla = tlr;
00233 if(fabs(aopt) > 1.) tla = tlr*fabs(aopt);
00234 if(adist < tla && fdist < tlf) return MnCross(aopt, min1.UserState(), nfcn);
00235 if(ipt > maxitr) return MnCross(fState, nfcn);
00236 double bmin = std::min(alsb[0], alsb[1]) - 1.;
00237 if(aopt < bmin) aopt = bmin;
00238 double bmax = std::max(alsb[0], alsb[1]) + 1.;
00239 if(aopt > bmax) aopt = bmax;
00240
00241 limset = false;
00242 if(aopt > aulim) {
00243 aopt = aulim;
00244 limset = true;
00245 }
00246
00247 for(unsigned int i = 0; i < npar; i++) {
00248 #ifdef DEBUG
00249 std::cout << "MnFunctionCross: Set new value for " << par[i] << " from " << pmid[i] << " to " << pmid[i] + (aopt)*pdir[i] << " aopt = " << aopt << std::endl;
00250 #endif
00251 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
00252 }
00253 FunctionMinimum min2 = migrad(maxcalls, mgr_tlr);
00254 nfcn += min2.NFcn();
00255
00256 #ifdef DEBUG
00257 std::cout << "MnFunctionCross: after Migrad on n-1 minimum is " << min2 << std::endl;
00258 std::cout << "nfcn = " << nfcn << std::endl;
00259 #endif
00260
00261 if(min2.HasReachedCallLimit())
00262 return MnCross(min2.UserState(), nfcn, MnCross::CrossFcnLimit());
00263 if(!min2.IsValid()) return MnCross(fState, nfcn);
00264 if(limset == true && min2.Fval() < aim)
00265 return MnCross(min2.UserState(), nfcn, MnCross::CrossParLimit());
00266
00267 ipt++;
00268 alsb[2] = aopt;
00269 flsb[2] = min2.Fval();
00270
00271
00272
00273 double ecarmn = fabs(flsb[2] - aim);
00274 double ecarmx = 0.;
00275 unsigned int ibest = 2;
00276 unsigned int iworst = 0;
00277 unsigned int noless = 0;
00278
00279 for(unsigned int i = 0; i < 3; i++) {
00280 double ecart = fabs(flsb[i] - aim);
00281 if(ecart > ecarmx) {
00282 ecarmx = ecart;
00283 iworst = i;
00284 }
00285 if(ecart < ecarmn) {
00286 ecarmn = ecart;
00287 ibest = i;
00288 }
00289 if(flsb[i] < aim) noless++;
00290 }
00291
00292 #ifdef DEBUG
00293 std::cout << "MnFunctionCross: have three points : nless < aim = " << noless << " ibest = " << ibest << " iworst = " << iworst << std::endl;
00294 #endif
00295
00296
00297
00298
00299 if(noless == 1 || noless == 2) goto L500;
00300
00301 if(noless == 0 && ibest != 2) return MnCross(fState, nfcn);
00302
00303
00304 if(noless == 3 && ibest != 2) {
00305 alsb[1] = alsb[2];
00306 flsb[1] = flsb[2];
00307 #ifdef DEBUG
00308 std::cout << "MnFunctionCross: all three points below - look again fir positive slope " << std::endl;
00309 #endif
00310 goto L300;
00311 }
00312
00313
00314
00315 flsb[iworst] = flsb[2];
00316 alsb[iworst] = alsb[2];
00317 dfda = (flsb[1] - flsb[0])/(alsb[1] - alsb[0]);
00318 #ifdef DEBUG
00319 std::cout << "MnFunctionCross: new straight line using point 1-2 - dfda = " << dfda << std::endl;
00320 #endif
00321 goto L460;
00322
00323 L500:
00324
00325 do {
00326
00327 MnParabola parbol = MnParabolaFactory()(MnParabolaPoint(alsb[0], flsb[0]), MnParabolaPoint(alsb[1], flsb[1]), MnParabolaPoint(alsb[2], flsb[2]));
00328
00329
00330
00331
00332 #ifdef DEBUG
00333 std::cout << "MnFunctionCross: parabola fit: iteration " << ipt << std::endl;
00334 #endif
00335
00336 double coeff1 = parbol.C();
00337 double coeff2 = parbol.B();
00338 double coeff3 = parbol.A();
00339 double determ = coeff2*coeff2 - 4.*coeff3*(coeff1 - aim);
00340
00341 #ifdef DEBUG
00342 std::cout << "MnFunctionCross: parabola fit: a = " << coeff3 << " b = "
00343 << coeff2 << " c = " << coeff1 << " determ = " << determ << std::endl;
00344 #endif
00345
00346 if(determ < prec.Eps()) return MnCross(fState, nfcn);
00347 double rt = sqrt(determ);
00348 double x1 = (-coeff2 + rt)/(2.*coeff3);
00349 double x2 = (-coeff2 - rt)/(2.*coeff3);
00350 double s1 = coeff2 + 2.*x1*coeff3;
00351 double s2 = coeff2 + 2.*x2*coeff3;
00352
00353 #ifdef DEBUG
00354 std::cout << "MnFunctionCross: parabola fit: x1 = " << x1 << " x2 = "
00355 << x2 << " s1 = " << s1 << " s2 = " << s2 << std::endl;
00356 #endif
00357
00358 #ifdef WARNINGMSG
00359 if(s1*s2 > 0.) MN_INFO_MSG("MnFunctionCross problem 1");
00360 #endif
00361
00362 aopt = x1;
00363 double slope = s1;
00364 if(s2 > 0.) {
00365 aopt = x2;
00366 slope = s2;
00367 }
00368 #ifdef DEBUG
00369 std::cout << "MnFunctionCross: parabola fit: aopt = " << aopt << " slope = "
00370 << slope << std::endl;
00371 #endif
00372
00373
00374 tla = tlr;
00375 if(fabs(aopt) > 1.) tla = tlr*fabs(aopt);
00376
00377 #ifdef DEBUG
00378 std::cout << "MnFunctionCross: Delta(aopt) = " << fabs(aopt - alsb[ibest]) << " tla = "
00379 << tla << "Delta(F) = " << fabs(flsb[ibest] - aim) << " tlf = " << tlf << std::endl;
00380 #endif
00381
00382
00383 if(fabs(aopt - alsb[ibest]) < tla && fabs(flsb[ibest] - aim) < tlf)
00384 return MnCross(aopt, min2.UserState(), nfcn);
00385
00386
00387
00388
00389
00390
00391 unsigned int ileft = 3;
00392 unsigned int iright = 3;
00393 unsigned int iout = 3;
00394 ibest = 0;
00395 ecarmx = 0.;
00396 ecarmn = fabs(aim-flsb[0]);
00397 for(unsigned int i = 0; i < 3; i++) {
00398 double ecart = fabs(flsb[i] - aim);
00399 if(ecart < ecarmn) {
00400 ecarmn = ecart;
00401 ibest = i;
00402 }
00403 if(ecart > ecarmx) ecarmx = ecart;
00404 if(flsb[i] > aim) {
00405 if(iright == 3) iright = i;
00406 else if(flsb[i] > flsb[iright]) iout = i;
00407 else {
00408 iout = iright;
00409 iright = i;
00410 }
00411 } else if(ileft == 3) ileft = i;
00412 else if(flsb[i] < flsb[ileft]) iout = i;
00413 else {
00414 iout = ileft;
00415 ileft = i;
00416 }
00417 }
00418
00419 #ifdef DEBUG
00420 std::cout << "MnFunctionCross: ileft = " << ileft << " iright = "
00421 << iright << " iout = " << iout << " ibest = " << ibest << std::endl;
00422 #endif
00423
00424
00425
00426 if(ecarmx > 10.*fabs(flsb[iout] - aim))
00427 aopt = 0.5*(aopt + 0.5*(alsb[iright] + alsb[ileft]));
00428
00429
00430 double smalla = 0.1*tla;
00431 if(slope*smalla > tlf) smalla = tlf/slope;
00432 double aleft = alsb[ileft] + smalla;
00433 double aright = alsb[iright] - smalla;
00434
00435
00436 if(aopt < aleft) aopt = aleft;
00437 if(aopt > aright) aopt = aright;
00438 if(aleft > aright) aopt = 0.5*(aleft + aright);
00439
00440
00441 limset = false;
00442 if(aopt > aulim) {
00443 aopt = aulim;
00444 limset = true;
00445 }
00446
00447
00448 for(unsigned int i = 0; i < npar; i++) {
00449 #ifdef DEBUG
00450 std::cout << "MnFunctionCross: Set new value for " << par[i] << " from " << pmid[i] << " to " << pmid[i] + (aopt)*pdir[i] << " aopt = " << aopt << std::endl;
00451 #endif
00452 migrad.SetValue(par[i], pmid[i] + (aopt)*pdir[i]);
00453 }
00454 min2 = migrad(maxcalls, mgr_tlr);
00455 nfcn += min2.NFcn();
00456 #ifdef DEBUG
00457 std::cout << "MnFunctionCross: after Migrad on n-1 minimum is " << min2 << std::endl;
00458 std::cout << "nfcn = " << nfcn << std::endl;
00459 #endif
00460
00461 if(min2.HasReachedCallLimit())
00462 return MnCross(min2.UserState(), nfcn, MnCross::CrossFcnLimit());
00463 if(!min2.IsValid()) return MnCross(fState, nfcn);
00464 if(limset == true && min2.Fval() < aim)
00465 return MnCross(min2.UserState(), nfcn, MnCross::CrossParLimit());
00466
00467 ipt++;
00468
00469 alsb[iout] = aopt;
00470 flsb[iout] = min2.Fval();
00471 ibest = iout;
00472 } while(ipt < maxitr);
00473
00474
00475
00476 return MnCross(fState, nfcn);
00477 }
00478
00479 }
00480
00481 }