00001
00002
00003
00004
00005
00006
00008
00009 #ifndef STANDALONE
00010
00011 #include "NCUtils/Fitter/NCFitter.h"
00012
00013 #include "NCUtils/NCUtility.h"
00014 using NC::Utility::SQR;
00015 using NC::Utility::ReportProgress;
00016 #include "MessageService/MsgService.h"
00017
00018 #else
00019
00020 #include "NCFitter.h"
00021
00022 #include <iostream>
00023 using namespace std;
00024 #define MSG(x,y) cout << "NCCont: "
00025 #define CVSID(x) ;
00026 template<class T> inline const T SQR(const T a) {return a*a;}
00027
00028 #endif // standalone
00029
00030 #include "TStopwatch.h"
00031 #include "TMath.h"
00032
00033 #include <cassert>
00034 #include <cmath>
00035 #include <sstream>
00036
00037 CVSID("$Id: NCFitter.cxx,v 1.17 2009/06/18 18:12:22 bckhouse Exp $");
00038
00039
00040
00041 namespace NC{
00042 namespace Fitter{
00043
00044
00045
00046
00047
00048
00049
00050
00051 CoordNDim ConvertCoord(const CoordInt& c, std::vector<NCParameter> ps)
00052 {
00053 assert(c.size() == ps.size());
00054
00055 CoordNDim ret(c.size());
00056 for(unsigned int n = 0; n < c.size(); ++n)
00057 ret[n] = ps[n].ValFromStep(c[n]);
00058
00059 return ret;
00060 }
00061
00063 CoordNDim ConvertContourCoord(const CoordNDim& c, vector<NCParameter> ps)
00064 {
00065 assert(c.size() == ps.size());
00066
00067 CoordNDim ret(c.size());
00068 for(unsigned int n = 0; n < c.size(); ++n)
00069 ret[n] = ps[n].ValFromStep(c[n]);
00070
00071 return ret;
00072 }
00073
00074
00075 double Discretizer::EvalAt(const CoordInt& r) const
00076 {
00077
00078 return fFunc->EvalAtEx(ConvertCoord(r, fParams), 0);
00079 }
00080
00081
00082 double Penalizer::EvalAtEx(const CoordNDim& r, CoordNDim* retCoord) const
00083 {
00084 CoordNDim reval = r;
00085
00086
00087 for(unsigned int n = 0; n < fParams.size(); ++n){
00088 if(r[n] < fParams[n].Min()) reval[n] = fParams[n].Min();
00089 if(r[n] > fParams[n].Max()) reval[n] = fParams[n].Max();
00090 }
00091
00092 double ret = fFunc->EvalAtEx(reval, retCoord);
00093
00094
00095
00096 const double amplitude = 1e3;
00097 for(unsigned int n = 0; n < fParams.size(); ++n){
00098 const double wsqr = SQR(fParams[n].Min()-fParams[n].Max());
00099 assert(wsqr);
00100 if(r[n] < fParams[n].Min())
00101 ret += amplitude*SQR(fParams[n].Min()-r[n])/wsqr;
00102 if(r[n] > fParams[n].Max())
00103 ret += amplitude*SQR(r[n]-fParams[n].Max())/wsqr;
00104 }
00105
00106 return ret;
00107 }
00108
00109
00110 double PenalizerInt::EvalAt(const CoordInt& r) const
00111 {
00112 CoordInt reval = r;
00113
00114
00115 for(unsigned int n = 0; n < fParams.size(); ++n){
00116 if(r[n] < 0) reval[n] = 0;
00117 if(r[n] > fParams[n].Steps()) reval[n] = fParams[n].Steps();
00118 }
00119
00120 double ret = fFunc->EvalAt(reval);
00121
00122
00123
00124 const double amplitude = 1e3;
00125 for(unsigned int n = 0; n < fParams.size(); ++n){
00126 const double wsqr = SQR(fParams[n].Steps());
00127 assert(wsqr);
00128 if(r[n] < 0)
00129 ret += amplitude*SQR(r[n])/wsqr;
00130 if(r[n] > fParams[n].Steps())
00131 ret += amplitude*SQR(r[n]-fParams[n].Steps())/wsqr;
00132 }
00133
00134 return ret;
00135 }
00136
00137
00138 double FuncCache::EvalAtEx(const CoordNDim& r, CoordNDim* retCoord) const
00139 {
00140 const std::map<CoordNDim, double>::const_iterator it = fCache.find(r);
00141 if(it != fCache.end()){
00142 ++fNhit;
00143 if(retCoord) *retCoord = fCacheRetCoord[r];
00144 return it->second;
00145 }
00146
00147 ++fNmiss;
00148
00149
00150
00151
00152 CoordNDim myRetCoord;
00153 const double ret = fFunc->EvalAtEx(r, &myRetCoord);
00154
00155 fCache[r] = ret;
00156 fCacheRetCoord[r] = myRetCoord;
00157
00158 if(retCoord) *retCoord = myRetCoord;
00159 return ret;
00160 }
00161
00162 ostream& operator<<(ostream& os, const FuncCache& c)
00163 {
00164 os << "FuncCache for callable at " << c.fFunc
00165 << " with " << c.fNhit+c.fNmiss << " calls "
00166 << "of which " << c.fNhit << " hit and "
00167 << c.fNmiss << " missed." << endl;
00168 return os;
00169 }
00170
00171
00172 double FuncCacheInt::EvalAtEx(const CoordInt& r, CoordInt* ret) const
00173 {
00174 const std::map<CoordInt, double>::const_iterator it = fCache.find(r);
00175
00176 if(it != fCache.end()){
00177 ++fNhit;
00178 if(ret) *ret = fRetCache[r];
00179 return it->second;
00180 }
00181
00182 ++fNmiss;
00183
00184
00185
00186
00187 CoordInt myret;
00188 const double val = fFunc->EvalAtEx(r, &myret);
00189 if(ret) *ret = myret;
00190
00191 fCache[r] = val;
00192 fRetCache[r] = myret;
00193
00194 return val;
00195 }
00196
00197 ostream& operator<<(ostream& os, const FuncCacheInt& c)
00198 {
00199 os << "FuncCacheInt for callable at " << c.fFunc
00200 << " with " << c.fNhit+c.fNmiss << " calls "
00201 << "of which " << c.fNhit << " hit and "
00202 << c.fNmiss << " missed." << endl;
00203 return os;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 vector<string> MinFinderSimple::sfPartNames;
00220 vector<double> MinFinderSimple::sfPartPositions;
00221
00222 MinFinderSimple::MinFinderSimple(const std::vector<NCParameter>& ps,
00223 const bool limits,
00224 const bool reuse,
00225 const ICallableND* f)
00226 :fParams(ps),
00227 fRespectParameterLimits(limits),
00228 reuseOld(reuse),
00229 fFunc(f)
00230 {
00231 }
00232
00233
00234 CoordNDim MinFinderSimple::BeginSearchPos() const
00235 {
00236 assert(fPrevBest.size() == fParams.size() || fPrevBest.size() == 0);
00237
00238 if(!reuseOld || fPrevBest.empty()){
00239 CoordNDim ret;
00240 for(unsigned int n = 0; n < fParams.size(); ++n){
00241 ret.push_back((fParams[n].Min()+fParams[n].Max())/2);
00242 }
00243 return ret;
00244 }
00245
00246 return fPrevBest;
00247 }
00248
00249
00250 int MinFinderSimple::BeginScale() const
00251 {
00252 int initScale = 1;
00253 if(!reuseOld || fPrevBest.empty()){
00254 bool bigEnough = false;
00255 while(!bigEnough){
00256 initScale *= 2;
00257 bigEnough = true;
00258 for(unsigned int n = 0; n < fParams.size(); ++n){
00259 if(initScale*fParams[n].Precision() <
00260 (fParams[n].Max()-fParams[n].Min())/4)
00261 bigEnough = false;
00262 }
00263 }
00264 }
00265 return initScale;
00266 }
00267
00268 void MinFinderSimple::SetSpacePartitions(vector<string> names,
00269 vector<double> poss)
00270 {
00271 assert(names.size() == poss.size());
00272 sfPartNames = names;
00273 sfPartPositions = poss;
00274 }
00275
00276
00277 double MinFinderSimple::FindMinPartitions(CoordNDim& ret,
00278 bool progress) const
00279 {
00280 assert(sfPartNames.size() == sfPartPositions.size());
00281 assert(!sfPartNames.empty());
00282
00283
00284 vector<const MinFinderSimple*> minimizers;
00285 minimizers.push_back(this);
00286
00287 for(unsigned int n = 0; n < sfPartNames.size(); ++n){
00288 for(unsigned int i = 0; i < fParams.size(); ++i){
00289
00290 if(fParams[i].ShortName() == sfPartNames[n]){
00291
00292
00293 const unsigned int M = minimizers.size();
00294 for(unsigned int m = 0; m < M; ++m){
00295
00296 vector<NCParameter> ps1 = fParams;
00297 ps1[i].SetRange(fParams[i].Min(), sfPartPositions[n]);
00298 vector<NCParameter> ps2 = fParams;
00299 ps2[i].SetRange(sfPartPositions[n], fParams[i].Max());
00300
00301
00302
00303 ICallableND* f1 = new ConstrainRange(minimizers[m]->fFunc, i,
00304 -1e50, sfPartPositions[n]);
00305 ICallableND* f2 = new ConstrainRange(minimizers[m]->fFunc, i,
00306 sfPartPositions[n], +1e50);
00307
00308 MinFinderSimple* m1 = new MinFinderSimple(ps1,
00309 fRespectParameterLimits,
00310 reuseOld,
00311 f1);
00312 MinFinderSimple* m2 = new MinFinderSimple(ps2,
00313 fRespectParameterLimits,
00314 reuseOld,
00315 f2);
00316 minimizers.push_back(m1);
00317 minimizers.push_back(m2);
00318 }
00319
00320
00321 for(unsigned int m = 0; m < M; ++m){
00322 if(minimizers[m] != this) delete minimizers[m];
00323 minimizers.erase(minimizers.begin());
00324 }
00325 }
00326 }
00327 }
00328
00329
00330
00331
00332 double lowest = 1e50;
00333 for(unsigned int m = 0; m < minimizers.size(); ++m){
00334 CoordNDim thisRet;
00335 const double height = minimizers[m]->FindMin(thisRet, progress, true);
00336 if(height < lowest){
00337 lowest = height;
00338 ret = thisRet;
00339 }
00340
00341 if(minimizers[m] != this) delete minimizers[m];
00342 }
00343
00344 return lowest;
00345 }
00346
00347
00348 double MinFinderSimple::FindMin(CoordNDim& ret,
00349 bool progress,
00350 bool ignorePartitions) const
00351 {
00352 if(!sfPartNames.empty() && !ignorePartitions)
00353 return FindMinPartitions(ret, progress);
00354
00355 ret.resize(fParams.size());
00356
00357 CoordNDim curPos = BeginSearchPos();
00358 assert(curPos.size() == fParams.size());
00359
00360 CoordNDim junk;
00361 double curHeight = fFunc->EvalAtEx(curPos, &junk);
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 std::vector<int> curIntPos(curPos.size(), 0);
00372
00373 int initScale = BeginScale();
00374
00375 std::map<std::vector<int>, bool> alreadyBeen;
00376 unsigned int lastDir = 0;
00377
00378 CoordNDim curEx;
00379
00380 TStopwatch sw;
00381
00382 for(int scale = initScale; scale >= 1; scale /= 2){
00383 if(progress) ReportProgress(1-log((float)scale)/log((float)initScale), sw);
00384 scaleTop:
00385 MSG("NCFitter", Msg::kVerbose) << "MinSimple: at "
00386 << curPos << endl;
00387
00388 for(int tryLast = true; tryLast >= false; --tryLast){
00389
00390 for(unsigned int dir = 0; dir < curPos.size(); ++dir){
00391
00392 for(int sign = -1; sign <= +1; sign += 2){
00393 if(tryLast && dir != lastDir) continue;
00394
00395 CoordNDim newPos = curPos;
00396 newPos[dir] += sign*fParams[dir].Precision()*scale;
00397
00398
00399
00400
00401 std::vector<int> newIntPos = curIntPos;
00402 newIntPos[dir] += sign*scale;
00403
00404 if(alreadyBeen[newIntPos]) continue;
00405
00406 alreadyBeen[newIntPos] = true;
00407
00408 CoordNDim ex;
00409
00410 double heightHere = fFunc->EvalAtEx(newPos, &ex);
00411
00412 if(heightHere < curHeight){
00413 curHeight = heightHere;
00414 curPos = newPos;
00415 curIntPos = newIntPos;
00416 curEx = ex;
00417 lastDir = dir;
00418
00419
00420
00421
00422
00423
00424 goto scaleTop;
00425 }
00426 }
00427 }
00428 }
00429 }
00430
00431
00432 fPrevBest = curPos;
00433
00434 if(curEx.empty()) ret = curPos; else ret = curEx;
00435
00436 return curHeight;
00437 }
00438
00439
00440
00441 CoordInt MinFinderSimpleInt::BeginSearchPos() const
00442 {
00443 assert(fPrevBest.size() == fParams.size() || fPrevBest.empty());
00444
00445 if(fPrevBest.empty()){
00446 CoordInt ret;
00447 for(unsigned int n = 0; n < fParams.size(); ++n){
00448
00449
00450 ret.push_back(int((fParams[n].Max()-fParams[n].Min())/
00451 fParams[n].Precision())/2);
00452 }
00453 return ret;
00454 }
00455
00456 return fPrevBest;
00457 }
00458
00459
00468 CoordInt MinFinderSimpleInt::BeginScale() const
00469 {
00470 CoordInt ret(fParams.size());
00471 for(unsigned int n = 0; n < ret.size(); ++n) ret[n] = 1;
00472
00473 if(!fPrevBest.empty()) return ret;
00474
00475 for(unsigned int n = 0; n < fParams.size(); ++n){
00476 bool bigEnough = false;
00477 while(!bigEnough){
00478 ret[n] *= 2;
00479 bigEnough = ret[n] > .25*fParams[n].Steps();
00480 }
00481 }
00482
00483 return ret;
00484 }
00485
00486
00487
00496 double MinFinderSimpleInt::FindMin(CoordInt* ret,
00497 vector<TGraph>* min_graphs) const
00498 {
00499
00500
00501 FuncCacheInt f(fFunc);
00502
00503 if(ret) ret->resize(fParams.size());
00504
00505
00506 if(min_graphs) min_graphs->resize(1+fParams.size());
00507
00508 CoordInt curPos = BeginSearchPos();
00509 double curHeight = f.EvalAt(curPos);
00510
00511
00512 if(curHeight > 9e5 && !fPrevBest.empty()){
00513 fPrevBest.clear();
00514
00515 curPos = BeginSearchPos();
00516 curHeight = f.EvalAt(curPos);
00517 }
00518
00519 CoordInt scale = BeginScale();
00520
00521
00522 unsigned int lastDir = 0;
00523 int lastSign = 0;
00524
00525
00526 vector<int> numGoodMoves(fParams.size(), 0);
00527
00528 while(true){
00529 loopTop:
00530 MSG("NCFitter", Msg::kVerbose) << "MinSimpleInt: at "
00531 << curPos << endl;
00532
00533
00534 for(int tryLast = true; tryLast >= false; --tryLast){
00535
00536 for(unsigned int dir = 0; dir < curPos.size(); ++dir){
00537
00538 for(int sign = -1; sign <= +1; sign += 2){
00539 if(tryLast && (dir != lastDir || sign != lastSign)) continue;
00540
00541 CoordInt newPos = curPos;
00542 newPos[dir] += sign*scale[dir];
00543
00544
00545
00546
00547
00548 const double heightHere = f.EvalAt(newPos);
00549
00550 if(heightHere < curHeight){
00551 if(min_graphs){
00552 min_graphs->at(0).SetPoint(min_graphs->at(0).GetN(),
00553 min_graphs->at(0).GetN(),
00554 heightHere);
00555
00556 for(unsigned int n = 0; n < newPos.size(); ++n)
00557 min_graphs->at(n+1).SetPoint(min_graphs->at(n+1).GetN(),
00558 min_graphs->at(n+1).GetN(),
00559 newPos[n]);
00560 }
00561
00562 curHeight = heightHere;
00563 curPos = newPos;
00564 lastDir = dir;
00565 lastSign = sign;
00566
00567 ++numGoodMoves[dir];
00568
00569
00570
00571
00572 if(numGoodMoves[dir] == 2){
00573 numGoodMoves[dir] = 0;
00574 scale[dir] *= 2;
00575 }
00576 goto loopTop;
00577 }
00578 }
00579 }
00580 }
00581
00582
00583
00584 bool quit = true;
00585 for(unsigned int n = 0; n < scale.size(); ++n) if(scale[n] != 1) quit = false;
00586 if(quit) break;
00587
00588
00589 for(unsigned int n = 0; n < scale.size(); ++n){
00590 if(scale[n] > 1){
00591 scale[n] /= 2;
00592 numGoodMoves[n] = 0;
00593 }
00594 }
00595
00596 }
00597
00598 if(curHeight < 9e5) fPrevBest = curPos;
00599 if(ret) *ret = curPos;
00600
00601 return curHeight;
00602 }
00603
00604 #ifndef STANDALONE
00605
00606 double MinFinderMinuit(const ICallableND* chiSqrFunc,
00607 const std::vector<NCParameter> params,
00608 CoordNDim& ret,
00609 TMinuit** ppMinu)
00610 {
00611 ret.resize(params.size());
00612
00613 TMinuit* minu = new MinuitForCallable(chiSqrFunc, params.size());
00614 minu->SetPrintLevel(-1);
00615 minu->Command("set strategy 2");
00616
00617 for(int n = 0; n < int(params.size()); ++n)
00618
00619 minu->DefineParameter(n, params[n].ShortName().c_str(),
00620 (params[n].Min()+params[n].Max())/2,
00621 (params[n].Max()-params[n].Min())/4,
00622 0, 0);
00623
00624
00625 double junkd; int junki; TString junks;
00626
00627 if(minu->Migrad()){
00628 MSG("NCFitter", Msg::kWarning) << "Migrad failed, "
00629 << "falling back to Simplex.\n";
00630
00631 minu->SetPrintLevel(0);
00632 minu->mnsimp();
00633 minu->Migrad();
00634 }
00635
00636 double minChiSqr;
00637 minu->mnstat(minChiSqr, junkd, junkd, junki, junki, junki);
00638
00639 for(unsigned int n = 0; n < params.size(); ++n)
00640 minu->GetParameter(n, ret[n], junkd);
00641
00642 if(ppMinu)
00643 *ppMinu = minu;
00644 else
00645 delete minu;
00646
00647 return minChiSqr;
00648 }
00649 #endif
00650
00651
00652
00658 std::vector<Coord> FindContour(const ICallable2D* func,
00659 const Coord& minCoord,
00660 const double height,
00661 const Coord& precision,
00662 std::vector<TGraph>* marg_graphs)
00663 {
00664 assert(!marg_graphs || marg_graphs->empty());
00665
00666 const double dx = precision.x;
00667 const double dy = precision.y;
00668 assert(dx > 0); assert(dy > 0);
00669
00670 typedef pair<int, int> Box;
00671
00672 std::map<Box, bool> results;
00673 std::vector<Box> todo;
00674
00675 std::map<Box, double> heights;
00676
00677
00678 const int bfxi = int(minCoord.x/dx);
00679 const int bfyi = int(minCoord.y/dy);
00680
00681 MSG("NCFitter", Msg::kVerbose) << "Contour: walking left" << endl;
00682
00683 for(int x = bfxi; ; --x){
00684
00685 MSG("NCFitter", Msg::kVerbose) << "Contour: at " << x << endl;
00686 CoordNDim bestfit;
00687 if(func->EvalAtEx(Coord(x*dx, bfyi*dy), bestfit) > height){
00688
00689
00690 if(marg_graphs)
00691 for(unsigned int n = 0; n < 4*bestfit.size(); ++n)
00692 marg_graphs->push_back(TGraph());
00693
00694
00695 todo.push_back(Box(x, bfyi));
00696
00697 break;
00698 }
00699 }
00700
00701
00702
00703
00704 std::vector<Coord> contour;
00705
00706 TStopwatch sw;
00707
00708 int gxi = -1;
00709
00710 while(!todo.empty()){
00711 Box now = todo.back();
00712 todo.pop_back();
00713
00714 ++gxi;
00715
00716
00717
00718
00719 MSG("NCFitter", Msg::kVerbose) << "Contour: at "
00720 << now.first << ","
00721 << now.second << endl;
00722
00723
00724 double topleft, topright, bottomleft, bottomright;
00725
00726
00727 for(int cx = 0; cx <= 1; ++cx){
00728 for(int cy = 0; cy <= 1; ++cy){
00729 Box corner(now.first+cx, now.second+cy);
00730 const std::map<Box, double>::const_iterator it = heights.find(corner);
00731 double heightHere;
00732 if(it == heights.end()){
00733 CoordNDim bestfit;
00734 heightHere = func->EvalAtEx(Coord((now.first+cx)*dx,
00735 (now.second+cy)*dy), bestfit);
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748 heights[corner] = heightHere;
00749 }
00750 else{
00751 heightHere = heights[corner];
00752 }
00753 if(cx == 0 && cy == 0) topleft = heightHere;
00754 if(cx == 1 && cy == 0) topright = heightHere;
00755 if(cx == 0 && cy == 1) bottomleft = heightHere;
00756 if(cx == 1 && cy == 1) bottomright = heightHere;
00757 }
00758 }
00759
00760 MSG("NCFitter", Msg::kVerbose) << "Contour: tl,tr,bl,br="
00761 << topleft << " "
00762 << topright << " "
00763 << bottomleft << " "
00764 << bottomright << endl;
00765
00766 if(now.first-bfxi){
00767 const double est_frac = (M_PI+atan2(now.second-bfyi-.01,
00768 double(now.first-bfxi)))/(2*M_PI);
00769 ReportProgress(est_frac, sw);
00770 }
00771
00772
00773
00774
00775
00776
00777
00778 if((topright-height)*(bottomright-height) <= 0){
00779 Box right(now.first+1, now.second);
00780 if(!results[right]){
00781 MSG("NCFitter", Msg::kVerbose) << "Contour: went right" << endl;
00782 todo.push_back(right);
00783 results[right] = true;
00784 const double rightdiff = (bottomright-topright) ?
00785 bottomright-topright : 1;
00786 contour.push_back(Coord((now.first+1)*dx,
00787 (now.second+(height-topright)/rightdiff)*dy));
00788 }
00789 }
00790 if( (topleft-height)*(bottomleft-height) <= 0){
00791 Box left(now.first-1, now.second);
00792 if(!results[left]){
00793 MSG("NCFitter", Msg::kVerbose) << "Contour: went left" << endl;
00794 todo.push_back(left);
00795 results[left] = true;
00796 const double leftdiff = (bottomleft-topleft)
00797 ? bottomleft-topleft : 1;
00798 contour.push_back(Coord(now.first*dx,
00799 (now.second+(height-topleft)/leftdiff)*dy));
00800 }
00801 }
00802 if( (bottomleft-height)*(bottomright-height) <= 0){
00803 Box down(now.first, now.second+1);
00804 if(!results[down]){
00805 MSG("NCFitter", Msg::kVerbose) << "Contour: went down" << endl;
00806 todo.push_back(down);
00807 results[down] = true;
00808 const double bottomdiff = (bottomright-bottomleft) ?
00809 bottomright-bottomleft : 1;
00810 contour.push_back(Coord((now.first+
00811 (height-bottomleft)/(bottomdiff))*dx,
00812 (now.second+1)*dy));
00813 }
00814 }
00815 if( (topleft-height)*(topright-height) <= 0 ){
00816 Box up(now.first, now.second-1);
00817 if(!results[up]){
00818 MSG("NCFitter", Msg::kVerbose) << "Contour: went up" << endl;
00819 todo.push_back(up);
00820 results[up] = true;
00821 const double topdiff = (topright-topleft) ? topright-topleft : 1;
00822 contour.push_back(Coord((now.first+(height-topleft)/topdiff)*dx,
00823 now.second*dy));
00824 }
00825 }
00826 }
00827
00828 ReportProgress(1, sw);
00829
00830 if(contour.size()) contour.push_back(contour[0]);
00831 return contour;
00832 }
00833
00834
00835
00836 TMatrix FindCovarianceMatrix(const ICallableND* func,
00837 const CoordNDim& minCoord,
00838 const std::vector<NCParameter> params)
00839 {
00840 assert(params.size() == minCoord.size());
00841
00842 TMatrix ret(params.size(), params.size());
00843
00844 CoordNDim junk;
00845 const double bestFitVal = func->EvalAtEx(minCoord, &junk);
00846
00847
00848 for(unsigned int i = 0; i < params.size(); ++i){
00849 const double step = params[i].Precision();
00850 CoordNDim plus = minCoord;
00851 plus[i] += step;
00852 CoordNDim minus = minCoord;
00853 minus[i] -= step;
00854 const double dii = (func->EvalAtEx(plus, &junk)+
00855 func->EvalAtEx(minus, &junk)-
00856 2*bestFitVal)/(step*step);
00857 ret(i, i) = dii;
00858 }
00859
00860
00861 for(unsigned int i = 0; i < params.size()-1; ++i){
00862 for(unsigned int j = i+1; j < params.size(); ++j){
00863 const double di = params[i].Precision();
00864 const double dj = params[j].Precision();
00865
00866 CoordNDim pp = minCoord;
00867 pp[i] += di; pp[j] += dj;
00868 CoordNDim pi = minCoord;
00869 pi[i] += di;
00870 CoordNDim pj = minCoord;
00871 pj[j] += dj;
00872
00873 const double dij = (func->EvalAtEx(pp, &junk)+bestFitVal-
00874 func->EvalAtEx(pi, &junk)-
00875 func->EvalAtEx(pj, &junk))/(di*dj);
00876 ret(i, j) = dij;
00877 ret(j, i) = dij;
00878 }
00879 }
00880
00881 ret.Invert();
00882 return ret;
00883 }
00884
00885 bool Interpolate(double val1, double val2, double target, double& ret)
00886 {
00887 if( (val1-target)*(val2-target) > 0) return false;
00888 const double diff = (val2-val1) ? val2-val1 : 1;
00889 ret = (target-val1)/diff;
00890 return true;
00891 }
00892
00893
00899 std::vector<CoordNDim> FindContourInt(const ICallableInt* func_org,
00900 const CoordInt& minCoord,
00901 const double height,
00902 std::vector<TGraph>* marg_graphs)
00903 {
00904 assert(!marg_graphs || marg_graphs->empty());
00905 assert(minCoord.size() == 2);
00906
00907
00908 FuncCacheInt* func = new FuncCacheInt(func_org);
00909
00910 std::map<CoordInt, bool> results;
00911 std::vector<CoordInt> todo;
00912
00913 MSG("NCFitter", Msg::kVerbose) << "Contour: walking left" << endl;
00914
00915 for(int x = minCoord.x(); ; --x){
00916
00917 MSG("NCFitter", Msg::kVerbose) << "Contour: at " << x << endl;
00918 CoordInt evalAt(x, minCoord.y());
00919 CoordInt bestfit;
00920 if(func->EvalAtEx(evalAt, &bestfit) > height){
00921
00922
00923 if(marg_graphs)
00924 for(unsigned int n = 0; n < 2+bestfit.size(); ++n)
00925 marg_graphs->push_back(TGraph());
00926
00927
00928 todo.push_back(evalAt);
00929
00930 break;
00931 }
00932 }
00933
00934 std::vector<CoordNDim> contour;
00935
00936 TStopwatch sw;
00937
00938 while(!todo.empty()){
00939 CoordInt now = todo.back();
00940 todo.pop_back();
00941
00942 MSG("NCFitter", Msg::kVerbose) << "Contour: at " << now << endl;
00943
00944 const double est_frac = (M_PI+
00945 atan2(-double(now.y()-minCoord.y()-.01),
00946 double(now.x()-minCoord.x())))/(2*M_PI);
00947 ReportProgress(est_frac, sw);
00948
00949
00950
00951
00952
00953
00954
00955 for(int dx = -1; dx <= 1; ++dx){
00956 for(int dy = -1; dy <= 1; ++dy){
00957
00958 if(abs(dx+dy) != 1) continue;
00959
00960
00961 const CoordInt newpos(now.x()+dx, now.y()+dy);
00962
00963
00964 const int cx = int(dx > 0);
00965 const int cy = int(dy > 0);
00966
00967
00968 const int ix = abs(dy);
00969 const int iy = abs(dx);
00970
00971
00972
00973 CoordInt bf1, bf2;
00974 const double h1 = func->EvalAtEx(CoordInt(now.x()+cx,
00975 now.y()+cy), &bf1);
00976 const double h2 = func->EvalAtEx(CoordInt(now.x()+cx+ix,
00977 now.y()+cy+iy), &bf2);
00978
00979 double interp;
00980 if(!results[newpos] && Interpolate(h1, h2, height, interp)){
00981 todo.push_back(newpos);
00982 results[newpos] = true;
00983 contour.push_back(CoordNDim(now.x()+cx+ix*interp,
00984 now.y()+cy+iy*interp));
00985
00986 if(marg_graphs){
00987 marg_graphs->at(0).SetPoint(marg_graphs->at(0).GetN(),
00988 marg_graphs->at(0).GetN(), now.x());
00989 marg_graphs->at(1).SetPoint(marg_graphs->at(1).GetN(),
00990 marg_graphs->at(1).GetN(), now.y());
00991 for(unsigned int n = 0; n < bf1.size(); ++n){
00992 const double bf = bf1[n]+interp*(bf2[n]-bf1[n]);
00993 marg_graphs->at(2+n).SetPoint(marg_graphs->at(2+n).GetN(),
00994 marg_graphs->at(2+n).GetN(), bf);
00995 }
00996 }
00997 }
00998 }
00999 }
01000 }
01001
01002 if(!contour.empty()) contour.push_back(contour[0]);
01003
01004 delete func;
01005
01006 return contour;
01007 }
01008
01009
01010
01011 TH2D* GetLowResGrid(const ICallable2D* func,
01012 const Coord min,
01013 const Coord max,
01014 const Coord prec)
01015 {
01016 const int Nx = int((max.x-min.x)/prec.x+.5);
01017 const int Ny = int((max.y-min.y)/prec.y+.5);
01018
01019 TH2D* ret = new TH2D("foo", "bar", Nx, min.x, max.x, Ny, min.y, max.y);
01020
01021 for(int nx = 0; nx < Nx ; ++nx){
01022 for(int ny = 0; ny < Ny; ++ny){
01023 const double x = min.x+(max.x-min.x)/double(Nx)*(nx+.5);
01024 const double y = min.y+(max.y-min.y)/double(Ny)*(ny+.5);
01025 CoordNDim bestfit;
01026 const double f = func->EvalAtEx(Coord(x, y), bestfit);
01027 MSG("NCFitter", Msg::kVerbose) << "GetLowResGrid: "
01028 << nx << "," << ny
01029 << " (" << x << "," << y << ") "
01030 << "-> " << f << endl;
01031 ret->Fill(x, y, f);
01032 }
01033 }
01034 return ret;
01035 }
01036
01037
01038
01039 TH2D* GridSearchInt(const ICallableInt* func,
01040 const CoordInt min,
01041 const CoordInt max)
01042 {
01043 assert(min.size() == 2 && max.size() == 2);
01044
01045 TStopwatch sw;
01046
01047 TH2D* ret = new TH2D("", "", max.x()-min.x(), min.x(), max.x(),
01048 max.y()-min.y(), min.y(), max.y());
01049
01050 for(int ny = min.y(); ny < max.y(); ++ny){
01051 for(int nx = min.x(); nx < max.x() ; ++nx){
01052 const double f = func->EvalAt(CoordInt(nx, ny));
01053 ret->Fill(nx, ny, f);
01054 }
01055 ReportProgress(double(ny)/(max.y()-min.y()), sw);
01056 }
01057
01058 return ret;
01059 }
01060
01061
01062
01063 TH2D* ConvertGrid(const TH2D* intgrid,
01064 const NCParameter& xp,
01065 const NCParameter& yp)
01066 {
01067 const int nx = intgrid->GetNbinsX();
01068 const int ny = intgrid->GetNbinsY();
01069
01070 double* xb = new double[nx+1];
01071 double* yb = new double[ny+1];
01072
01073 for(int x = 0; x <= nx; ++x) xb[x] = xp.ValFromStep(x);
01074 for(int y = 0; y <= ny; ++y) yb[y] = yp.ValFromStep(y);
01075
01076 TH2D* ret = new TH2D("", TString::Format(";%s;%s;",
01077 xp.LatexName().c_str(),
01078 yp.LatexName().c_str()).Data(),
01079 nx, xb, ny, yb);
01080
01081 delete[] xb;
01082 delete[] yb;
01083
01084 for(int x = 0; x <= nx; ++x)
01085 for(int y = 0; y <= ny; ++y)
01086 ret->SetBinContent(x, y, intgrid->GetBinContent(x, y));
01087
01088 return ret;
01089 }
01090
01091
01092
01093 TGraph* CreateOneDimProjection(const ICallable2D* func,
01094 const NCParameter param,
01095 const double minVal,
01096 double& leftErr,
01097 double& rightErr,
01098 std::vector<TGraph>& marg_graphs)
01099 {
01100
01101 assert(param.Precision());
01102 const int steps = int(.5+(param.Max()-param.Min())/param.Precision());
01103 assert(steps);
01104
01105 vector<double> x, y;
01106
01107 TStopwatch sw;
01108
01109 double minproj = 1e10;
01110
01111 for(int nx = 0; nx <= steps; ++nx){
01112 const double xhere = param.Min()+nx*param.Precision();
01113
01114 ReportProgress(double(nx)/steps, sw);
01115
01116 CoordNDim bestfit;
01117 double upVal = func->EvalAtEx(Coord(xhere, -999), bestfit);
01118 x.push_back(xhere);
01119 y.push_back(upVal);
01120
01121 std::stringstream op;
01122 op << "CreateOneDimProjection: "
01123 << param.ShortName() << " = " << xhere << " chisq = " << upVal
01124 << " other variables: ";
01125 for(unsigned int n = 0; n < bestfit.size(); ++n)
01126 op << " " << bestfit[n];
01127 op << endl;
01128 MSG("NCFitter", Msg::kVerbose) << op.str();
01129
01130
01131 if(upVal < minproj) minproj = upVal;
01132
01133 for(unsigned int n = 0; n < bestfit.size(); ++n){
01134
01135
01136
01137
01138 if(marg_graphs.size() == n) marg_graphs.push_back(TGraph());
01139 marg_graphs[n].Set(marg_graphs[n].GetN()+1);
01140 marg_graphs[n].SetPoint(marg_graphs[n].GetN()-1, xhere, bestfit[n]);
01141 }
01142 }
01143
01144 MSG("NCFitter", Msg::kInfo) << "CreateOneDimProjection: "
01145 << "min chisq = " << minproj
01146 << " cf minimizer's " << minVal << endl;
01147
01148 #if 0
01149 cout << "Beginning backtrack test...\n";
01150 for(int nx = steps; nx >= 0; --nx){
01151 const double xhere = param.Min()+nx*param.Precision();
01152 CoordNDim bestfit;
01153 double upVal = func->EvalAt(Coord(xhere, -999), bestfit);
01154
01155
01156 const double diff = upVal - y[nx];
01157 if(diff < -1e-4){
01158 cout << "WARNING - GOT BETTER RESULT TRACKING BACKWARD, FIXING\n";
01159 y[nx] = upVal;
01160 }
01161
01162 if(upVal < minproj) minproj = upVal;
01163
01164
01165
01166
01167
01168
01169
01170
01171 }
01172 #endif
01173
01174 bool needLeftErr = true;
01175 bool needRightErr = true;
01176
01177
01178
01179 rightErr = param.Max()+.5*param.Precision();
01180
01181 for(int nx = 0; nx <= steps; ++nx){
01182 y[nx] -= minproj;
01183
01184 const double upVal = y[nx];
01185
01186 if(needRightErr && !needLeftErr && upVal > 1){
01187 needRightErr = false;
01188 rightErr = x[nx];
01189 }
01190 if(needLeftErr && upVal < 1){
01191 needLeftErr = false;
01192 leftErr = x[nx]-param.Precision();
01193 }
01194 }
01195
01196 TGraph* ret = new TGraph(steps+1, &x[0], &y[0]);
01197
01198 return ret;
01199 }
01200
01201
01202
01203 TGraph CreateOneDimProjectionInt(const ICallableInt* func,
01204 int minstep,
01205 int maxstep,
01206 double& leftErr,
01207 double& rightErr)
01208 {
01209 vector<double> xs, ys;
01210
01211 TStopwatch sw;
01212
01213 double minproj = 1e10;
01214
01215 for(int x = minstep; x <= maxstep; ++x){
01216 ReportProgress(double(x-minstep)/(maxstep-minstep), sw);
01217
01218
01219 CoordInt pos; pos.push_back(x);
01220 const double upVal = func->EvalAt(pos);
01221 xs.push_back(x);
01222 ys.push_back(upVal);
01223
01224 if(upVal < minproj) minproj = upVal;
01225
01226
01227
01228
01229
01230
01231
01232
01233 }
01234
01235 MSG("NCFitter", Msg::kInfo) << "CreateOneDimProjection: "
01236 << "min chisq = " << minproj << endl;
01237
01238
01239 bool needLeftErr = true;
01240 bool needRightErr = true;
01241
01242
01243 for(int x = 0; x <= maxstep-minstep; ++x){
01244 ys[x] -= minproj;
01245
01246 const double upVal = ys[x];
01247
01248 if(needRightErr && !needLeftErr && upVal > 1){
01249 needRightErr = false;
01250
01251
01252 rightErr = (minstep+x-1)+(1-ys[x-1])/(ys[x]-ys[x-1]);
01253 }
01254 if(needLeftErr && upVal < 1){
01255 needLeftErr = false;
01256
01257
01258 if(x == 0)
01259 leftErr = minstep;
01260 else
01261 leftErr = (minstep+x-1)+(1-ys[x-1])/(ys[x]-ys[x-1]);
01262 }
01263 }
01264
01265 if(needRightErr) rightErr = maxstep;
01266
01267 TGraph ret(maxstep-minstep, &xs[0], &ys[0]);
01268 return ret;
01269 }
01270
01271
01272 vector<TGraph> MakeSlices(const ICallableND* func,
01273 const vector<NCParameter>& ps,
01274 const CoordNDim& minpos)
01275 {
01276 vector<TGraph> ret;
01277 for(unsigned int p = 0; p < ps.size(); ++p){
01278 MSG("NCFitter", Msg::kInfo) << "Taking slice in "
01279 << ps[p].ShortName()
01280 << "..." << endl;
01281
01282
01283 assert(ps[p].Precision());
01284 const int steps = int(.5+(ps[p].Max()-ps[p].Min())/ps[p].Precision());
01285 assert(steps);
01286
01287 vector<double> x, y;
01288
01289 TStopwatch sw;
01290
01291 for(int nx = 0; nx <= steps; ++nx){
01292 const double xhere = ps[p].Min()+nx*ps[p].Precision();
01293
01294 ReportProgress(double(nx)/steps, sw);
01295
01296 CoordNDim evalAt = minpos;
01297 evalAt[p] = xhere;
01298 CoordNDim junk;
01299 double upVal = func->EvalAtEx(evalAt, &junk);
01300 x.push_back(xhere);
01301 y.push_back(upVal);
01302 }
01303
01304 MSG("NCFitter", Msg::kInfo) << endl;
01305
01306 TGraph g = TGraph(steps+1, &x[0], &y[0]);
01307 g.SetName(TString::Format("slice_%s", ps[p].ShortName().c_str()));
01308 g.SetTitle(TString::Format("Slice;%s;#chi^{2}",
01309 ps[p].LatexName().c_str()));
01310 ret.push_back(g);
01311 }
01312
01313 return ret;
01314 }
01315
01316
01317 vector<TH2D*> Make2DSlices(const ICallableND* func,
01318 const vector<NCParameter>& ps,
01319 const CoordNDim& minpos)
01320 {
01321 vector<TH2D*> ret;
01322 for(unsigned int p = 0; p < ps.size(); ++p){
01323 for(unsigned int q = 0; q < p; ++q){
01324
01325 assert(ps[p].Precision());
01326 assert(ps[q].Precision());
01327
01328 NCParameter px=ps[p];
01329 NCParameter py=ps[q];
01330
01331 const int Nx = int((px.Max()-px.Min())/px.Precision()+.5);
01332 const int Ny = int((py.Max()-py.Min())/py.Precision()+.5);
01333
01334 TH2D* h = new TH2D("foo", "bar", Nx, px.Min(), px.Max(),
01335 Ny, py.Min(), py.Max());
01336 h->SetName(TString::Format("2dslice_%s_%s", px.ShortName().c_str(),
01337 py.ShortName().c_str() ));
01338
01339 h->GetXaxis()->SetTitle(px.LatexName().c_str());
01340 h->GetYaxis()->SetTitle(py.LatexName().c_str());
01341
01342 TStopwatch sw;
01343
01344 for(int nx = 1; nx <= Nx; ++nx){
01345 ReportProgress(double(nx)/Nx, sw);
01346 const double xhere = px.Min()+nx*px.Precision();
01347 for(int ny = 1; ny <= Ny; ++ny){
01348 const double yhere = py.Min()+ny*py.Precision();
01349 CoordNDim evalAt = minpos;
01350 evalAt[p] = xhere; evalAt[q] = yhere;
01351 CoordNDim junk;
01352 h->SetBinContent(nx, ny, func->EvalAtEx(evalAt, &junk));
01353 }
01354 }
01355
01356 ret.push_back(h);
01357 }
01358 }
01359
01360 return ret;
01361 }
01362
01363
01364
01365 FixVars::FixVars(const ICallableND* fun,
01366 const CoordNDim& fix,
01367 const std::vector<int>& vary)
01368 :fFunc(fun), fFixed(fix), fToVary(vary){}
01369
01370
01371 double FixVars::EvalAtEx(const CoordNDim& r, CoordNDim* ret) const
01372 {
01373 assert(fToVary.size() == r.size());
01374
01375
01376 CoordNDim fixed = fFixed;
01377 for(unsigned int n = 0; n < fToVary.size(); ++n)
01378 fixed[fToVary[n]] = r[n];
01379 return fFunc->EvalAtEx(fixed, ret);
01380 }
01381
01382
01383
01384 FixVarsInt::FixVarsInt(const ICallableInt* fun,
01385 const CoordInt& fix,
01386 const std::vector<int>& vary)
01387 :fFunc(fun), fFixed(fix), fToVary(vary){}
01388
01389
01390 double FixVarsInt::EvalAt(const CoordInt& r) const
01391 {
01392 assert(fToVary.size() == r.size());
01393
01394
01395 CoordInt fixed = fFixed;
01396 for(unsigned int n = 0; n < fToVary.size(); ++n)
01397 fixed[fToVary[n]] = r[n];
01398 return fFunc->EvalAt(fixed);
01399 }
01400
01401
01402
01403 double ConstrainRange::EvalAtEx(const CoordNDim& r, CoordNDim* ret) const
01404 {
01405 CoordNDim r2 = r;
01406 double pen = 0;
01407 if(r2[fParamNum] > fMax){
01408
01409
01410 pen += 1e3*(r2[fParamNum]-fMax)*(r2[fParamNum]-fMax);
01411 r2[fParamNum] = fMax;
01412 }
01413 if(r2[fParamNum] < fMin){
01414 pen += 1e3*(r2[fParamNum]-fMin)*(r2[fParamNum]-fMin);
01415 r2[fParamNum] = fMin;
01416 }
01417 return fFunc->EvalAtEx(r2, ret)+pen;
01418 }
01419
01420
01421
01422 MarginalizeSimple::MarginalizeSimple(const ICallableND* f,
01423 const std::vector<NCParameter>& p,
01424 const bool reuseOld,
01425 const int xcoord,
01426 const int ycoord)
01427 :fParams(p), fXpos(xcoord), fYpos(ycoord)
01428 {
01429 assert(fXpos < int(fParams.size()) && fYpos < int(fParams.size()));
01430
01431 vector<NCParameter> shortParams;
01432
01433 for(int n = 0; n < int(fParams.size()); ++n){
01434 if(n != fXpos && n != fYpos){
01435 fVary.push_back(n);
01436 shortParams.push_back(fParams[n]);
01437 }
01438 }
01439
01440 CoordNDim fix;
01441 fix.resize(fParams.size());
01442 f2 = new FixVars(f, fix, fVary);
01443
01444 fMinFinder = new MinFinderSimple(shortParams, true, reuseOld, f2);
01445 }
01446
01447
01448
01449 double MarginalizeSimple::EvalAtEx(const Coord& r, CoordNDim& ret) const
01450 {
01451 CoordNDim fix;
01452 fix.resize(fParams.size());
01453 fix[fXpos] = r.x;
01454 if(fYpos > -1) fix[fYpos] = r.y;
01455 f2->SetFixed(fix);
01456
01457 return fMinFinder->FindMin(ret);
01458 }
01459
01460
01461
01462 MarginalizeSimpleInt::MarginalizeSimpleInt(const ICallableInt* f,
01463 const std::vector<NCParameter>& p,
01464 const int xcoord,
01465 const int ycoord)
01466 :fParams(p), fXpos(xcoord), fYpos(ycoord)
01467 {
01468 assert(fXpos < int(fParams.size()) && fYpos < int(fParams.size()));
01469
01470 for(int n = 0; n < int(fParams.size()); ++n){
01471 if(n != fXpos && n != fYpos){
01472 fVary.push_back(n);
01473 fShortParams.push_back(fParams[n]);
01474 }
01475 }
01476
01477 CoordInt fix;
01478 fix.resize(fParams.size());
01479 f2 = new FixVarsInt(f, fix, fVary);
01480
01481 minFinder = new MinFinderSimpleInt(fShortParams, true, f2);
01482 }
01483
01484
01485
01486 double MarginalizeSimpleInt::EvalAtEx(const CoordInt& r, CoordInt* ret) const
01487 {
01488 CoordInt fix;
01489 fix.resize(fParams.size());
01490 fix[fXpos] = r.x();
01491 if(fYpos > -1) fix[fYpos] = r.y();
01492 f2->SetFixed(fix);
01493
01494 return minFinder->FindMin(ret);
01495 }
01496
01497
01498 #ifndef STANDALONE
01503 Int_t MinuitForCallable::Eval(Int_t ,
01504 Double_t* ,
01505 Double_t& fval,
01506 Double_t* par,
01507 Int_t flag)
01508 {
01509
01510
01511 assert(flag == 4);
01512 CoordNDim r(fNumPar);
01513 for(int n = 0; n < fNumPar; ++n) r[n] = par[n];
01514 CoordNDim junk;
01515 fval = fFunc->EvalAtEx(r, &junk);
01516 return 0;
01517 }
01518
01519
01520
01527 MarginalizeHybrid::MarginalizeHybrid(const ICallableND* f,
01528 const std::vector<NCParameter> p,
01529 const bool testmin,
01530 const int xcoord,
01531 const int ycoord)
01532 :fFunc(f), fParams(p), fTestMinimum(testmin), fXpos(xcoord), fYpos(ycoord)
01533 {
01534 assert(fXpos < int(fParams.size()) && fYpos < int(fParams.size()));
01535 assert(fYpos > fXpos || fYpos == -1);
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550 fLastMinPos.resize(fParams.size());
01551 }
01552
01553
01554
01555 double MarginalizeHybrid::EvalAtEx(const Coord& r, CoordNDim& ret) const
01556 {
01557
01558
01559 double valAtMin;
01560
01561
01562 MinuitForCallable* pminu = new MinuitForCallable(fFunc, fParams.size());
01563
01564 pminu->SetPrintLevel(-1);
01565
01566
01567 for(int n = 0; n < int(fParams.size()); ++n){
01568 pminu->DefineParameter(n, fParams[n].ShortName().c_str(),
01569 (fParams[n].Min()+fParams[n].Max())/2,
01570 (fParams[n].Max()-fParams[n].Min())/4, 0, 0);
01571 }
01572
01573
01574 double junkd; int junki;
01575
01576
01577 double args1[] = {fXpos+1, r.x};
01578 pminu->mnexcm("set param", args1, 2, junki);
01579 if(fYpos > 0){
01580 double args2[] = {fYpos+1, r.y};
01581 pminu->mnexcm("set param", args2, 2, junki);
01582 }
01583
01584 pminu->mnfixp(fXpos, junki);
01585 if(fYpos > 0){
01586
01587 pminu->mnfixp(fYpos-1, junki);
01588 }
01589
01590
01591
01592
01593
01594
01595 if(pminu->Migrad()){
01596
01597 MSG("NCFitter", Msg::kVerbose) << "MinWRT: Migrad didn't converge"
01598 << endl;
01599 }
01600
01601 pminu->mnstat(valAtMin, junkd, junkd, junki, junki, junki);
01602 for(unsigned int n = 0; n < fParams.size(); ++n){
01603 pminu->GetParameter(n, fLastMinPos[n], junkd);
01604 if(int(n) != fXpos && int(n) != fYpos)
01605 ret.push_back(fLastMinPos[n]);
01606 }
01607
01608 TString txt = "MarginalizeHybrid: min at ";
01609 for(unsigned int n = 0; n < fParams.size(); ++n){
01610 txt += fParams[n].ShortName() + "=";
01611 txt += fLastMinPos[n];
01612 txt += +"\t";
01613 }
01614 MSG("NCFitter", Msg::kVerbose) << txt << " chisq = "
01615 << valAtMin << endl;
01616
01617
01618 pminu->mnfree(0);
01619
01620 delete pminu;
01621
01622 return valAtMin;
01623 }
01624
01625
01626
01627
01628
01629 bool MarginalizeHybrid::AlreadyAtMinimum(const Coord& r, double& valAtMin) const
01630 {
01631 CoordNDim p = fLastMinPos;
01632
01633 p[fXpos] = r.x;
01634 if(fYpos > 0) p[fYpos] = r.y;
01635
01636 CoordNDim junk;
01637 valAtMin = fFunc->EvalAtEx(p, &junk);
01638
01639
01640 for(int n = 0; n < int(fParams.size()); ++n){
01641
01642 if(n == fXpos || n == fYpos) continue;
01643 CoordNDim q = p;
01644 q[n] += fParams[n].Precision();
01645 if(fFunc->EvalAtEx(q, &junk) < valAtMin) return false;
01646 q[n] -= 2*fParams[n].Precision();
01647 if(fFunc->EvalAtEx(q, &junk) < valAtMin) return false;
01648 }
01649 MSG("NCFitter", Msg::kVerbose) << "MarginalizeHybrid: "
01650 << "Already at minimum" << endl;
01651 return true;
01652 }
01653
01654 #endif
01655
01656
01657 void PrintGridSearch(const ICallableND* func,
01658 const std::vector<NCParameter>& params,
01659 std::ostream& out)
01660 {
01661 std::vector<NCParameter> lowResParams = params;
01662 for(unsigned int n = 0; n < lowResParams.size(); ++n)
01663 lowResParams[n].SetPrecision(lowResParams[n].Precision()*10);
01664
01665 std::vector<CoordNDim> evalAt;
01666
01667 CoordNDim first;
01668 for(unsigned int n = 0; n < lowResParams.size(); ++n)
01669 first.push_back(lowResParams[n].Min());
01670
01671 evalAt.push_back(first);
01672
01673 for(unsigned int d = 0; d < lowResParams.size(); ++d){
01674 unsigned int maxn = evalAt.size();
01675 for(unsigned int n = 0; n < maxn; ++n){
01676 for(unsigned int nx = 1; ; ++nx){
01677 CoordNDim base = evalAt[n];
01678 base[d] += lowResParams[d].Precision()*nx;
01679 if(base[d] > lowResParams[d].Max()) break;
01680 evalAt.push_back(base);
01681 }
01682 }
01683 }
01684
01685 for(unsigned int d = 0; d < lowResParams.size(); ++d)
01686 out << lowResParams[d].ShortName() << "\t";
01687 out << "chisq" << endl;
01688
01689 for(unsigned int n = 0; n < evalAt.size(); ++n){
01690 for(unsigned int d = 0; d < evalAt[n].size(); ++d){
01691 out << evalAt[n][d]<<"\t";
01692 }
01693 CoordNDim junk;
01694 out << func->EvalAtEx(evalAt[n], &junk) << endl;
01695 }
01696 }
01697
01698
01699 }}