00001 #include "../interface/CascadeMinimizer.h"
00002 #include "../interface/ProfiledLikelihoodRatioTestStatExt.h"
00003 #include "../interface/ProfileLikelihood.h"
00004 #include "../interface/CloseCoutSentry.h"
00005 #include "../interface/utils.h"
00006
00007 #include <Math/MinimizerOptions.h>
00008 #include <RooCategory.h>
00009 #include <RooNumIntConfig.h>
00010
00011
00012 boost::program_options::options_description CascadeMinimizer::options_("Cascade Minimizer options");
00013 std::vector<CascadeMinimizer::Algo> CascadeMinimizer::fallbacks_;
00014 bool CascadeMinimizer::preScan_;
00015 bool CascadeMinimizer::poiOnlyFit_;
00016 bool CascadeMinimizer::singleNuisFit_;
00017 bool CascadeMinimizer::setZeroPoint_ = true;
00018 bool CascadeMinimizer::oldFallback_ = true;
00019
00020 CascadeMinimizer::CascadeMinimizer(RooAbsReal &nll, Mode mode, RooRealVar *poi, int initialStrategy) :
00021 nll_(nll),
00022 minimizer_(nll_),
00023 mode_(mode),
00024 strategy_(initialStrategy),
00025 poi_(poi)
00026 {
00027 }
00028
00029 bool CascadeMinimizer::improve(int verbose, bool cascade)
00030 {
00031 minimizer_.setPrintLevel(verbose-2);
00032 minimizer_.setStrategy(strategy_);
00033 bool outcome = improveOnce(verbose-2);
00034 if (cascade && !outcome && !fallbacks_.empty()) {
00035 std::string nominalType(ROOT::Math::MinimizerOptions::DefaultMinimizerType());
00036 std::string nominalAlgo(ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo());
00037 float nominalTol(ROOT::Math::MinimizerOptions::DefaultTolerance());
00038 int nominalStrat(strategy_);
00039 if (verbose > 0) std::cerr << "Failed minimization with " << nominalType << "," << nominalAlgo << " and tolerance " << nominalTol << std::endl;
00040 for (std::vector<Algo>::const_iterator it = fallbacks_.begin(), ed = fallbacks_.end(); it != ed; ++it) {
00041 ProfileLikelihood::MinimizerSentry minimizerConfig(it->algo, it->tolerance != Algo::default_tolerance() ? it->tolerance : nominalTol);
00042 int myStrategy = it->strategy; if (myStrategy == Algo::default_strategy()) myStrategy = nominalStrat;
00043 if (nominalType != ROOT::Math::MinimizerOptions::DefaultMinimizerType() ||
00044 nominalAlgo != ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo() ||
00045 nominalTol != ROOT::Math::MinimizerOptions::DefaultTolerance() ||
00046 myStrategy != nominalStrat) {
00047 if (verbose > 0) std::cerr << "Will fallback to minimization using " << it->algo << ", strategy " << myStrategy << " and tolerance " << it->tolerance << std::endl;
00048 minimizer_.setStrategy(myStrategy);
00049 outcome = improveOnce(verbose-2);
00050 if (outcome) break;
00051 }
00052 }
00053 }
00054 if (setZeroPoint_) {
00055 cacheutils::CachingSimNLL *simnll = dynamic_cast<cacheutils::CachingSimNLL *>(&nll_);
00056 if (simnll) simnll->clearZeroPoint();
00057 }
00058 return outcome;
00059 }
00060
00061 bool CascadeMinimizer::improveOnce(int verbose)
00062 {
00063 std::string myType(ROOT::Math::MinimizerOptions::DefaultMinimizerType());
00064 std::string myAlgo(ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo());
00065 if (setZeroPoint_) {
00066 cacheutils::CachingSimNLL *simnll = dynamic_cast<cacheutils::CachingSimNLL *>(&nll_);
00067 if (simnll) {
00068 simnll->setZeroPoint();
00069 }
00070 }
00071 bool outcome = false;
00072 if (oldFallback_){
00073 outcome = nllutils::robustMinimize(nll_, minimizer_, verbose);
00074 } else {
00075 int status = minimizer_.minimize(myType.c_str(), myAlgo.c_str());
00076 outcome = (status == 0);
00077 }
00078 if (setZeroPoint_) {
00079 cacheutils::CachingSimNLL *simnll = dynamic_cast<cacheutils::CachingSimNLL *>(&nll_);
00080 if (simnll) simnll->clearZeroPoint();
00081 }
00082 return outcome;
00083 }
00084
00085 bool CascadeMinimizer::minimize(int verbose, bool cascade)
00086 {
00087 minimizer_.setPrintLevel(verbose-2);
00088 minimizer_.setStrategy(strategy_);
00089 if (preScan_) minimizer_.minimize("Minuit2","Scan");
00090
00091 if (mode_ == Unconstrained && poiOnlyFit_) {
00092 trivialMinimize(nll_, *poi_, 200);
00093 }
00094 return improve(verbose, cascade);
00095 }
00096
00097
00098 void CascadeMinimizer::initOptions()
00099 {
00100 options_.add_options()
00101 ("cminPoiOnlyFit", "Do first a fit floating only the parameter of interest")
00102 ("cminPreScan", "Do a scan before first minimization")
00103 ("cminSingleNuisFit", "Do first a minimization of each nuisance parameter individually")
00104 ("cminFallbackAlgo", boost::program_options::value<std::vector<std::string> >(), "Fallback algorithms if the default minimizer fails (can use multiple ones). Syntax is algo[,subalgo][,strategy][:tolerance]")
00105 ("cminSetZeroPoint", boost::program_options::value<bool>(&setZeroPoint_)->default_value(setZeroPoint_), "Change the reference point of the NLL to be zero during minimization")
00106 ("cminOldRobustMinimize", boost::program_options::value<bool>(&oldFallback_)->default_value(oldFallback_), "Use the old 'robustMinimize' logic in addition to the cascade")
00107
00108
00109
00110
00111
00112
00113
00114
00115 ;
00116 }
00117
00118 void CascadeMinimizer::applyOptions(const boost::program_options::variables_map &vm)
00119 {
00120 using namespace std;
00121
00122 preScan_ = vm.count("cminPreScan");
00123 poiOnlyFit_ = vm.count("cminPoiOnlyFit");
00124 singleNuisFit_ = vm.count("cminSingleNuisFit");
00125 setZeroPoint_ = vm.count("cminSetZeroPoint");
00126 if (vm.count("cminFallbackAlgo")) {
00127 vector<string> falls(vm["cminFallbackAlgo"].as<vector<string> >());
00128 for (vector<string>::const_iterator it = falls.begin(), ed = falls.end(); it != ed; ++it) {
00129 std::string algo = *it;
00130 float tolerance = Algo::default_tolerance();
00131 int strategy = Algo::default_strategy();
00132 string::size_type idx = std::min(algo.find(";"), algo.find(":"));
00133 if (idx != string::npos && idx < algo.length()) {
00134 tolerance = atof(algo.substr(idx+1).c_str());
00135 algo = algo.substr(0,idx);
00136 }
00137 idx = algo.find(",");
00138 if (idx != string::npos && idx < algo.length()) {
00139
00140 if ( '0' <= algo[idx+1] && algo[idx+1] <= '9' ) {
00141 strategy = atoi(algo.substr(idx+1).c_str());
00142 algo = algo.substr(0,idx);
00143 } else {
00144
00145 idx = algo.find(",",idx+1);
00146 if (idx != string::npos && idx < algo.length()) {
00147 strategy = atoi(algo.substr(idx+1).c_str());
00148 algo = algo.substr(0,idx);
00149 }
00150 }
00151 }
00152 fallbacks_.push_back(Algo(algo, tolerance, strategy));
00153 std::cout << "Configured fallback algorithm " << fallbacks_.back().algo <<
00154 ", strategy " << fallbacks_.back().strategy <<
00155 ", tolerance " << fallbacks_.back().tolerance << std::endl;
00156 }
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 void CascadeMinimizer::trivialMinimize(const RooAbsReal &nll, RooRealVar &r, int points) const {
00184 double rMin = r.getMin(), rMax = r.getMax(), rStep = (rMax-rMin)/(points-1);
00185 int iMin = -1; double minnll = 0;
00186 for (int i = 0; i < points; ++i) {
00187 double x = rMin + (i+0.5)*rStep;
00188 r.setVal(x);
00189 double y = nll.getVal();
00190 if (iMin == -1 || y < minnll) { minnll = y; iMin = i; }
00191 }
00192 r.setVal( rMin + (iMin+0.5)*rStep );
00193 }