Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

NCFitter.cxx

Go to the documentation of this file.
00001 
00002 // $Id: NCFitter.cxx,v 1.17 2009/06/18 18:12:22 bckhouse Exp $
00003 //
00004 // Collection of functions and classes for fitting and contour finding.
00005 //
00006 // C. Backhouse 11/2007
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   CoordInt ConvertCoord(const CoordNDim& c, std::vector<NCParameter> ps)
00046   {
00047     assert(c.size() == ps.size());
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     // TODO - this loses the ret information
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     // If the point is outside the physical region - move it to the boundary
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     // If we had to move the point then apply a quadratic penalty term.
00095     // The factor of 1000 is fairly arbitrary.
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     // If the point is outside the physical region - move it to the boundary
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     // If we had to move the point then apply a quadratic penalty term.
00123     // The factor of 1000 is fairly arbitrary.
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     //  const unsigned int maxCacheSize = int(1e7); // on the order of 10meg
00150     //  if(cache.size() > maxCacheSize) fCache.clear();
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     //  const unsigned int maxCacheSize = int(1e7); // on the order of 10meg
00185     //  if(cache.size() > maxCacheSize) cache.clear();
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   vector<CoordInt> FuncCacheInt::GetHistory()
00208   {
00209     vector<CoordInt> ret;
00210     map<CoordInt, double>::iterator it;
00211     for(it = cache.begin(); it != cache.end(); ++it) ret.push_back(it->first);
00212     return ret;
00213   }
00214   */
00215 
00216 
00217   //------------------------- MinFinderSimple ------------------------------
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     // Start with `this` as a template to copy the minimizers from
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         // If we find we're fitting a parameter we ought to be partitioning
00290         if(fParams[i].ShortName() == sfPartNames[n]){
00291           // Take every minimizer that already exists and split it into
00292           // two, one for each side of the partition
00293           const unsigned int M = minimizers.size();
00294           for(unsigned int m = 0; m < M; ++m){
00295             // The parameter ranges inform the fitter where to begin
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             // Constrain the ranges in [-infinity, partition point]
00302             // and [partition point, +infinity]
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           } // end for m
00319           // The first M of the minimizers are the ones before we split them
00320           // in half. We don't need them anymore.
00321           for(unsigned int m = 0; m < M; ++m){
00322             if(minimizers[m] != this) delete minimizers[m];
00323             minimizers.erase(minimizers.begin());
00324           } // end for m
00325         } // end if matches
00326       } // end for i
00327     } // end for n
00328 
00329     // Minimize using all the minimizers and pick the best result. Ensure
00330     // that ret is filled properly too. We pass true for ignorePartitions
00331     // otherwise we'd end up here again instead of actually minimizing.
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       // Don't need it anymore
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     if(curHeight > 9e5 && !fPrevBest.empty()){   // Appear to have started inside some kind of penalty zone
00364       fPrevBest.clear();    // So, forget where we were before
00365       // and try again.
00366       curPos = BeginSearchPos();
00367       curHeight = func->EvalAt(curPos);
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       // Try the previous direction first
00388       for(int tryLast = true; tryLast >= false; --tryLast){
00389         // What direction to look in
00390         for(unsigned int dir = 0; dir < curPos.size(); ++dir){
00391           // In what sense
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             //      if(fRespectParameterLimits && (newPos[dir] < fParams[dir].Min() || newPos[dir] > fParams[dir].Max()))
00399             //continue;
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               //              cout << "Moved to ";
00420               //              for (unsigned int n = 0; n < fParams.size(); ++n)
00421               //                cout << fParams[n].ShortName() << "=" << curPos[n] << " ";
00422               //              cout << endl;
00423 
00424               goto scaleTop; // Repeat all these loops with the same value of scale.
00425             } // end if better
00426           } // end for s
00427         } //end for d
00428       } // end for tryLast
00429     } // end for scale
00430 
00431     //    if(curHeight < 9e5)
00432     fPrevBest = curPos;
00433 
00434     if(curEx.empty()) ret = curPos; else ret = curEx;
00435 
00436     return curHeight;
00437   }
00438 
00439 
00440   //------------------------- MinFinderSimpleInt ------------------------------
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         //      ret.push_back((fParams[n].Min()+fParams[n].Max())/2);
00449         //      ret.push_back(fParams[n].Min()+.25*(fParams[n].Max()-fParams[n].Min()));
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     // We need this because eg we move one way and
00500     // then immediately test where we just were.
00501     FuncCacheInt f(fFunc);
00502 
00503     if(ret) ret->resize(fParams.size());
00504 
00505     // One extra for chisq value
00506     if(min_graphs) min_graphs->resize(1+fParams.size());
00507 
00508     CoordInt curPos = BeginSearchPos();
00509     double curHeight = f.EvalAt(curPos);
00510 
00511     // Appear to have started inside some kind of penalty zone
00512     if(curHeight > 9e5 && !fPrevBest.empty()){
00513       fPrevBest.clear();    // So, forget where we were before
00514       // and try again.
00515       curPos = BeginSearchPos();
00516       curHeight = f.EvalAt(curPos);
00517     }
00518 
00519     CoordInt scale = BeginScale();
00520 
00521     // What way did we last move?
00522     unsigned int lastDir = 0;
00523     int lastSign = 0;
00524 
00525     // How many times in a row we have moved in this direction, at this scale
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       // Try the previous direction first
00534       for(int tryLast = true; tryLast >= false; --tryLast){
00535         // What direction to look in
00536         for(unsigned int dir = 0; dir < curPos.size(); ++dir){
00537           // In what sense
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             // TODO - wrong
00545             //      if(fRespectParameterLimits && (newPos[dir] < fParams[dir].Min() || newPos[dir] > fParams[dir].Max()))
00546             //        continue;
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               // As soon as we move twice in a direction,
00569               // then double the scale that way.
00570               // The tryLast stuff will make sure we try again
00571               // in this direction first.
00572               if(numGoodMoves[dir] == 2){
00573                 numGoodMoves[dir] = 0;
00574                 scale[dir] *= 2;
00575               }
00576               goto loopTop; // Try again from this new position
00577             } // end if better
00578           } // end for s
00579         } //end for d
00580       } // end for tryLast
00581 
00582       // If we got here then no direction was an improvement.
00583       // If we are at the minimum scale then quit.
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       // Otherwise reduce the scale in every direction we can.
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     } // end infinite loop
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); // Shut Minuit up.
00615     minu->Command("set strategy 2"); // Be careful, instead of fast.
00616 
00617     for(int n = 0; n < int(params.size()); ++n)
00618       // NB - no parameter limits imposed.
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     // Minuit tries to return a lot of parameters we don't want to keep.
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       // Things are going wrong, we should let the user see.
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;    // first == left, second == top
00671 
00672     std::map<Box, bool> results;   // Is this box already in the result set?
00673     std::vector<Box> todo;         // Boxes to investigate
00674     // Boxes whose topleft corner has already been evaluated, used as cache.
00675     std::map<Box, double> heights;
00676 
00677     // Top left corner of the box containing the best fit.
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     // Walk to the left
00683     for(int x = bfxi; ; --x){
00684       // As soon as we exceed the contour
00685       MSG("NCFitter", Msg::kVerbose) << "Contour: at " << x << endl;
00686       CoordNDim bestfit;
00687       if(func->EvalAtEx(Coord(x*dx, bfyi*dy), bestfit) > height){
00688         // Create enough graphs to save our marginalisation progress
00689         //(2 extra to save the two variables actually in the contour)
00690         if(marg_graphs)
00691           for(unsigned int n = 0; n < 4*bestfit.size(); ++n)
00692             marg_graphs->push_back(TGraph());
00693 
00694         // make it the first element in the todo list
00695         todo.push_back(Box(x, bfyi));
00696         // and stop going left.
00697         break;
00698       }
00699     }
00700 
00701     // NB - for some reason while writing this I decided
00702     // that increasing y is downward.
00703 
00704     std::vector<Coord> contour;
00705 
00706     TStopwatch sw; // starts automatically
00707 
00708     int gxi = -1; // position on the x axis of the marg graphs.
00709 
00710     while(!todo.empty()){
00711       Box now = todo.back();
00712       todo.pop_back();
00713 
00714       ++gxi;
00715 
00716       // We end up evaluating the function multiple times at each point, so are
00717       // relying heavily on the cacheing done in GetChiSqrFromDerived()
00718 
00719       MSG("NCFitter", Msg::kVerbose) << "Contour: at "
00720                                      << now.first << ","
00721                                      << now.second << endl;
00722 
00723       // Set by the loop below.
00724       double topleft, topright, bottomleft, bottomright;
00725 
00726       // Evaluate the function at all the corners.
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             /* TODO - hacked out marg graphs because they are broken somehow. FIX!
00738             if(marg_graphs){
00739               const int dn = cx+2*cy;
00740 
00741               for(unsigned int n = 0; n < bestfit.size(); ++n){
00742                 marg_graphs->at(4*n+dn).SetPoint(marg_graphs->at(4*n+dn).
00743                                                  GetN(), gxi, bestfit[n]);
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       // For each side of the box: see if one corner is high and the other low.
00774       // If so, and if the box adjacent on this side isn't already part of the
00775       // results, then append the adjacent box to the todo list and linearly
00776       // interpolate to find where to put the contour point on that edge.
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]); // Close the loop.
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     // First, do the 2nd derivatives in one variable
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     // Now do all the off-diagonal derivatives
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     // Put a cache in front of ourselves
00908     FuncCacheInt* func = new FuncCacheInt(func_org);
00909 
00910     std::map<CoordInt, bool> results; // Is this box already in the result set?
00911     std::vector<CoordInt> todo;       // Boxes to investigate
00912 
00913     MSG("NCFitter", Msg::kVerbose) << "Contour: walking left" << endl;
00914     // Walk to the left
00915     for(int x = minCoord.x(); ; --x){
00916       // As soon as we exceed the contour
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         // Create enough graphs to save our marginalisation progress
00922         //(2 extra to save the two variables actually in the contour)
00923         if(marg_graphs)
00924           for(unsigned int n = 0; n < 2+bestfit.size(); ++n)
00925             marg_graphs->push_back(TGraph());
00926 
00927         // make it the first element in the todo list
00928         todo.push_back(evalAt);
00929         // and stop going left.
00930         break;
00931       }
00932     }
00933 
00934     std::vector<CoordNDim> contour;
00935 
00936     TStopwatch sw; // starts automatically
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       // For each side of the box: see if one corner is high and the other low.
00951       // If so, and if the box adjacent on this side isn't already part of the
00952       // results, then append the adjacent box to the todo list and linearly
00953       // interpolate to find where to put the contour point on that edge.
00954 
00955       for(int dx = -1; dx <= 1; ++dx){
00956         for(int dy = -1; dy <= 1; ++dy){
00957           // no diagonals, don't stay stationary
00958           if(abs(dx+dy) != 1) continue;
00959 
00960           // where we're trying to go
00961           const CoordInt newpos(now.x()+dx, now.y()+dy);
00962 
00963           // offset to the first corner of the box we're considering
00964           const int cx = int(dx > 0);
00965           const int cy = int(dy > 0);
00966 
00967           // vector to the second corner we're considering
00968           const int ix = abs(dy);
00969           const int iy = abs(dx);
00970 
00971           // The values at said corners. Reevaluating them is fine,
00972           // because 'func' is cached.
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             } // end if marg_graphs
00997           }
00998         } // end for dy
00999       } // end for dx
01000     } // end while todo
01001 
01002     if(!contour.empty()) contour.push_back(contour[0]); // Close the loop.
01003 
01004     delete func; // our cache
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     // +.5 makes us round to nearest int instead of toward zero.
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; // starts automatically
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         // If it's our first time through we need to create the graphs too.
01135         //      if(nx == 0) marg_graphs.push_back(TGraph());
01136         // TODO Something is broken with the marg graphs, but I'm too lazy
01137         // to fix it, so for now just do this.
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       //      x.push_back(xhere);
01155       //      y.push_back(upVal);
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       for(unsigned int n = 0; n < bestfit.size(); ++n){
01165         // If it's our first time through we need to create the graphs too.
01166         if(nx == 0) marg_graphs.push_back(TGraph());
01167         marg_graphs[n].Set(marg_graphs[n].GetN()+1);
01168         marg_graphs[n].SetPoint(marg_graphs[n].GetN()-1, xhere, bestfit[n]);
01169       }
01170       */
01171     }
01172 #endif
01173 
01174     bool needLeftErr = true;
01175     bool needRightErr = true;
01176 
01177     // Initialize right error for downward sloping projections.
01178     // .5 is to be consistent with binning elsewhere.
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; // starts automatically
01212 
01213     double minproj = 1e10;
01214 
01215     for(int x = minstep; x <= maxstep; ++x){
01216       ReportProgress(double(x-minstep)/(maxstep-minstep), sw);
01217 
01218       //      CoordInt bestfit;
01219       CoordInt pos; pos.push_back(x);
01220       const double upVal = func->EvalAt(pos);//, bestfit);
01221       xs.push_back(x);
01222       ys.push_back(upVal);
01223 
01224       if(upVal < minproj) minproj = upVal;
01225       /*
01226       for(unsigned int n = 0; n < bestfit.size(); ++n){
01227         // If it's our first time through we need to create the graphs too.
01228         if(nx == 0) marg_graphs.push_back(TGraph());
01229         marg_graphs[n].Set(marg_graphs[n].GetN()+1);
01230         marg_graphs[n].SetPoint(marg_graphs[n].GetN()-1, xhere, bestfit[n]);
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     // Find the intersections using a linear interpolation
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         //      rightErr = minstep+x;
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         //      leftErr = minstep+x;
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       // +.5 makes us round to nearest int instead of toward zero.
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; // starts automatically
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       } // end for nx
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         // +.5 makes us round to nearest int instead of toward zero.
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; // starts automatically
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           } // end for ny
01354         } // end for nx
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     // For every parameter in the list of what we are to vary - substitute
01375     // in, in order, from the parameters we were passed.
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     // For every parameter in the list of what we are to vary - substitute
01394     // in, in order, from the parameters we were passed.
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       // TODO - there should be some scaling based on the width,
01409       // but we happen to know all these variables are approx 0-1
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 /*npar*/,
01504                                 Double_t* /*grad*/,
01505                                 Double_t& fval,
01506                                 Double_t* par,
01507                                 Int_t flag)
01508   {
01509     // If we are being asked to do something that isn't just
01510     // calculate the function then we don't know how...
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     // Recycling the old Minuit instance each time is a possible cause of
01537     // getting stuck in the wrong minimum.
01538     /*
01539     pminu = new MinuitForCallable(fFunc, fParams.size());
01540 
01541     pminu->SetPrintLevel(-1);
01542     //  minu.Command("set strategy 2"); // Be careful, instead of fast.
01543 
01544     for(int n = 0; n < int(fParams.size()); ++n){
01545       pminu->DefineParameter(n, fParams[n].ShortName().c_str(),
01546                              (fParams[n].min+fParams[n].Max())/2,
01547                              (fParams[n].Max()-fParams[n].Min())/4, 0, 0);
01548     }
01549     */
01550     fLastMinPos.resize(fParams.size());
01551   }
01552 
01553 
01554   // ---------------------------------------------------------------------
01555   double MarginalizeHybrid::EvalAtEx(const Coord& r, CoordNDim& ret) const
01556   {
01557     //assert(pminu);
01558 
01559     double valAtMin;
01560     //    if(fTestMinimum && AlreadyAtMinimum(r, valAtMin)) return valAtMin;
01561 
01562     MinuitForCallable* pminu = new MinuitForCallable(fFunc, fParams.size());
01563 
01564     pminu->SetPrintLevel(-1);
01565     //    pminu->Command("set strategy 2"); // Be careful, instead of fast.
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     // Minuit tries to return parameters we don't want to keep.
01574     double junkd; int junki;
01575 
01576     // Add one to the index because of ridiculous fortran numbering scheme.
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       // The parameters all got renumbered when we fixed x.
01587       pminu->mnfixp(fYpos-1, junki);
01588     }
01589 
01590     // Simplex seems to be much faster than Migrad.
01591     // I think Migrad can fail when put in a bad place, and spends
01592     // a long time doing it.
01593     // However - I have had bad results using Simplex, so stick with Migrad.
01594     //  minu.mnsimp();
01595     if(pminu->Migrad()){
01596       //return FLT_MAX; // this messes up the contours...
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     // Free all the parameters, we will refix them next time round.
01618     pminu->mnfree(0);
01619 
01620     delete pminu;
01621 
01622     return valAtMin;
01623   }
01624 
01625 
01626   // Is the function higher one step size in each of the minimized-over
01627   // directions. If so, return true, and place the value of the old function
01628   // at the old position in these coordinates in valAtMin.
01629   bool MarginalizeHybrid::AlreadyAtMinimum(const Coord& r, double& valAtMin) const
01630   {
01631     CoordNDim p = fLastMinPos;   // Last place we were
01632     // Move to where we are now on one axis of the contour
01633     p[fXpos] = r.x;
01634     if(fYpos > 0) p[fYpos] = r.y; // If we have a second axis move there too.
01635 
01636     CoordNDim junk;
01637     valAtMin = fFunc->EvalAtEx(p, &junk);
01638 
01639     // What direction to take a step in.
01640     for(int n = 0; n < int(fParams.size()); ++n){
01641       // Not in the contour axis directions.
01642       if(n == fXpos || n == fYpos) continue;
01643       CoordNDim q = p;
01644       q[n] += fParams[n].Precision();   // Move one step positive in this axis
01645       if(fFunc->EvalAtEx(q, &junk) < valAtMin) return false;
01646       q[n] -= 2*fParams[n].Precision(); // Also try one step negative.
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 }} // end namespaces

Generated on Mon Feb 15 11:07:04 2010 for loon by  doxygen 1.3.9.1