BCIntegrate.cxx
1 /*
2  * Copyright (C) 2007-2018, the BAT core developer team
3  * All rights reserved.
4  *
5  * For the licensing terms see doc/COPYING.
6  * For documentation see http://mpp.mpg.de/bat
7  */
8 
9 // ---------------------------------------------------------
10 #include <config.h>
11 
12 #include "BCIntegrate.h"
13 #include "BCH1D.h"
14 #include "BCH2D.h"
15 #include "BCLog.h"
16 #include "BCMath.h"
17 #include "BCParameter.h"
18 
19 #include <TDecompChol.h>
20 #include <TH1.h>
21 #include <TH2.h>
22 #include <TH3.h>
23 #include <TFile.h>
24 #include <TRandom3.h>
25 #include <TString.h>
26 #include <TTree.h>
27 
28 #ifdef HAVE_CUBA_H
29 #include <cuba.h>
30 #endif
31 
32 #include <algorithm>
33 #include <limits>
34 #include <math.h>
35 
36 using ROOT::Math::Util::ToString;
37 
38 namespace
39 {
40 int PrintLevel()
41 {
42  int printlevel = -1;
44  printlevel = 0;
46  printlevel = 1;
47 
48  return printlevel;
49 }
50 }
51 
52 namespace BCMinimizer
53 {
54 Adapter::Adapter(BCIntegrate& model) :
55  m(&model),
56  par(m->GetNParameters())
57 {}
58 
59 unsigned int Adapter::NDim() const
60 {
61  return m->GetNParameters();
62 }
63 
64 ROOT::Math::IMultiGenFunction* Adapter::Clone() const
65 {
66  return new Adapter(*m);
67 }
68 
69 double Adapter::DoEval (const double* x) const
70 {
71  par.resize(m->GetNParameters());
72  std::copy(x, x + par.size(), par.begin());
73  return -m->LogEval(par);
74 }
75 
76 Wrapper::Wrapper(BCIntegrate& m) :
77  min(ROOT::Minuit::kMigrad),
78  adapt(m)
79 {
80  Init();
81 }
82 
83 void Wrapper::Init()
84 {
85  Init(std::vector<double>(), PrintLevel());
86 }
87 
88 void Wrapper::Init(const std::vector<double>& start, int printlevel)
89 {
90  // use a separate minimizer so multiple instances of BCIntegrate can coexist
91  TMinuitMinimizer::UseStaticMinuit(false);
92 
93  min.Clear();
94 
95  // set target and dimensionality
96  min.SetFunction(adapt);
97 
98  min.SetPrintLevel(printlevel);
99  min.SetErrorDef(0.5);
100 
101  std::vector<double> newstart;
102  if (start.empty())
103  // if empty, set to center, with fixed values fixed
104  newstart = adapt.m->GetParameters().GetRangeCenters();
105  else
106  newstart = start;
107 
108  for (unsigned i = 0; i < adapt.m->GetNParameters(); ++i) {
109  const BCParameter& p = adapt.m->GetParameter(i);
110  if (p.Fixed()) {
111  const bool success = min.SetFixedVariable(i, p.GetName(),
112  newstart.at(i));
113  if (!success) {
114  BCLOG_ERROR(std::string("Cannot add fixed parameter ") + ToString(i) + " to minuit");
115  }
116  } else {
117  const bool success = min.SetLimitedVariable(i, p.GetName(),
118  newstart.at(i),
119  p.GetRangeWidth() / 100.,
120  p.GetLowerLimit(), p.GetUpperLimit());
121  if (!success) {
122  BCLOG_ERROR(std::string("Cannot add parameter ") + ToString(i) + " to minuit");
123  }
124  }
125  }
126 }
127 
128 void Wrapper::Reset(BCIntegrate& m)
129 {
130  adapt = Adapter(m);
131  Init();
132 }
133 }
134 
135 // ---------------------------------------------------------
136 BCIntegrate::BCIntegrate(const std::string& name) :
137  BCEngineMCMC(name),
138  fFlagIgnorePrevOptimization(false),
139  fSAT0(100),
140  fSATmin(0.1),
141  fSANIterations(0),
142  fSATemperature(0),
143  fSALogProb(0),
144  fFlagMarginalized(false),
145  fMinimizer(*this),
146  fOptimizationMethodCurrent(BCIntegrate::kOptDefault),
147  fOptimizationMethodUsed(BCIntegrate::kOptEmpty),
148  fIntegrationMethodCurrent(BCIntegrate::kIntDefault),
149  fIntegrationMethodUsed(BCIntegrate::kIntEmpty),
150  fMarginalizationMethodCurrent(BCIntegrate::kMargDefault),
151  fMarginalizationMethodUsed(BCIntegrate::kMargEmpty),
152  fSASchedule(BCIntegrate::kSACauchy),
153  fNIterationsMin(0),
154  fNIterationsMax(1000000),
155  fNIterationsPrecisionCheck(1000),
156  fNIterations(0),
157  fLogMaximum(-std::numeric_limits<double>::infinity()),
158  fIntegral(-1),
159  fRelativePrecision(1e-2),
160  fAbsolutePrecision(1e-6),
161  fError(-999.),
162  fCubaIntegrationMethod(BCIntegrate::kCubaDefault)
163 {}
164 
165 // ---------------------------------------------------------
166 BCIntegrate::BCIntegrate(const std::string& filename, const std::string& name, bool loadObservables) :
167  BCEngineMCMC(filename, name, loadObservables),
169  fSAT0(100),
170  fSATmin(0.1),
171  fSANIterations(0),
172  fSATemperature(0),
173  fSALogProb(0),
174  fFlagMarginalized(false),
175  fMinimizer(*this),
176  fOptimizationMethodCurrent(BCIntegrate::kOptDefault),
177  fOptimizationMethodUsed(BCIntegrate::kOptEmpty),
178  fIntegrationMethodCurrent(BCIntegrate::kIntDefault),
179  fIntegrationMethodUsed(BCIntegrate::kIntEmpty),
180  fMarginalizationMethodCurrent(BCIntegrate::kMargDefault),
181  fMarginalizationMethodUsed(BCIntegrate::kMargEmpty),
182  fSASchedule(BCIntegrate::kSACauchy),
183  fNIterationsMin(0),
184  fNIterationsMax(1000000),
185  fNIterationsPrecisionCheck(1000),
186  fNIterations(0),
187  fLogMaximum(-std::numeric_limits<double>::infinity()),
188  fIntegral(-1),
189  fRelativePrecision(1e-2),
190  fAbsolutePrecision(1e-6),
191  fError(-999.),
192  fCubaIntegrationMethod(BCIntegrate::kCubaDefault)
193 {}
194 
195 // ---------------------------------------------------------
197  : BCEngineMCMC(other),
199  fSAT0(other.fSAT0),
200  fSATmin(other.fSATmin),
203  fSALogProb(other.fSALogProb),
204  fSAx(other.fSAx),
206  // TMinuitMinimizer is not copyable
207  fMinimizer(*this),
208  fOptimizationMethodCurrent(other.fOptimizationMethodCurrent),
209  fOptimizationMethodUsed(other.fOptimizationMethodUsed),
210  fIntegrationMethodCurrent(other.fIntegrationMethodCurrent),
211  fIntegrationMethodUsed(other.fIntegrationMethodUsed),
212  fMarginalizationMethodCurrent(other.fMarginalizationMethodCurrent),
213  fMarginalizationMethodUsed(other.fMarginalizationMethodUsed),
214  fSASchedule(other.fSASchedule),
215  fNIterationsMin(other.fNIterationsMin),
216  fNIterationsMax(other.fNIterationsMax),
217  fNIterationsPrecisionCheck(other.fNIterationsPrecisionCheck),
218  fNIterations(other.fNIterations),
219  fBestFitParameters(other.fBestFitParameters),
220  fBestFitParameterErrors(other.fBestFitParameterErrors),
221  fLogMaximum(other.fLogMaximum),
222  fIntegral(other.fIntegral),
223  fRelativePrecision(other.fRelativePrecision),
224  fAbsolutePrecision(other.fAbsolutePrecision),
225  fError(other.fError),
226  fCubaIntegrationMethod(other.fCubaIntegrationMethod),
227  fCubaVegasOptions(other.fCubaVegasOptions),
228  fCubaSuaveOptions(other.fCubaSuaveOptions),
229  fCubaDivonneOptions(other.fCubaDivonneOptions),
230  fCubaCuhreOptions(other.fCubaCuhreOptions)
231 {}
232 
234 {
237  fSAT0 = other.fSAT0;
238  fSATmin = other.fSATmin;
241  fSALogProb = other.fSALogProb;
242  fSAx = other.fSAx;
244  // TMinuitMinimizer is not copyable
245  fMinimizer.Reset(*this);
246  fOptimizationMethodCurrent = other.fOptimizationMethodCurrent;
247  fOptimizationMethodUsed = other.fOptimizationMethodUsed;
248  fIntegrationMethodCurrent = other.fIntegrationMethodCurrent;
249  fIntegrationMethodUsed = other.fIntegrationMethodUsed;
250  fMarginalizationMethodCurrent = other.fMarginalizationMethodCurrent;
251  fMarginalizationMethodUsed = other.fMarginalizationMethodUsed;
252  fSASchedule = other.fSASchedule;
253  fNIterationsMin = other.fNIterationsMin;
254  fNIterationsMax = other.fNIterationsMax;
255  fNIterationsPrecisionCheck = other.fNIterationsPrecisionCheck;
256  fNIterations = other.fNIterations;
257  fBestFitParameters = other.fBestFitParameters;
258  fBestFitParameterErrors = other.fBestFitParameterErrors;
259  fLogMaximum = other.fLogMaximum;
260  fIntegral = other.fIntegral;
261  fRelativePrecision = other.fRelativePrecision;
262  fAbsolutePrecision = other.fAbsolutePrecision;
263  fError = other.fError;
264  fCubaIntegrationMethod = other.fCubaIntegrationMethod;
265  fCubaVegasOptions = other.fCubaVegasOptions;
266  fCubaSuaveOptions = other.fCubaSuaveOptions;
267  fCubaDivonneOptions = other.fCubaDivonneOptions;
268  fCubaCuhreOptions = other.fCubaCuhreOptions;
269 
270  return *this;
271 }
272 
273 // ---------------------------------------------------------
274 const std::vector<double>& BCIntegrate::GetBestFitParameters() const
275 {
276  if (fBestFitParameters.empty())
278  return fBestFitParameters;
279 }
280 
281 // ---------------------------------------------------------
282 const std::vector<double>& BCIntegrate::GetBestFitParameterErrors() const
283 {
284  // fall back to MCMC if available
285  if (fBestFitParameterErrors.empty()) {
287  }
288  return fBestFitParameterErrors;
289 }
290 
291 // ---------------------------------------------------------
293 {
295 
296  fBestFitParameterErrors.clear();
297  fBestFitParameters.clear();
298  fLogMaximum = -std::numeric_limits<double>::infinity();
299 
300  // remove marginalized histograms
301  // set marginalization flag
302  fFlagMarginalized = false;
303 }
304 
305 // ---------------------------------------------------------
307 {
308  // check if parameters are defined
309  if (fParameters.Size() < 1) {
310  BCLog::OutError("BCIntegrate::Integrate : No parameters defined. Aborting.");
311  return -1.;
312  }
313 
314  // output
315  if (!(fIntegrationMethodCurrent == BCIntegrate::kIntDefault) && !(fIntegrationMethodCurrent == BCIntegrate::kIntEmpty))
316  BCLog::OutSummary("Integrate using " + DumpCurrentIntegrationMethod());
317 
318  switch (fIntegrationMethodCurrent) {
319 
320  case BCIntegrate::kIntEmpty: {
321  BCLog::OutWarning("BCIntegrate::Integrate : No integration method chosen.");
322  return 0;
323  }
324 
326  std::vector<double> sums (2, 0.0);
327  sums.push_back(GetParameters().Volume());
328  fIntegral = Integrate(kIntMonteCarlo,
332  sums);
333 
334  // set used integration method
335  fIntegrationMethodUsed = BCIntegrate::kIntMonteCarlo;
336 
337  // return integral
338  return fIntegral;
339  }
340 
342  fIntegral = IntegrateCuba();
343 
344  // set used integration method
345  fIntegrationMethodUsed = BCIntegrate::kIntCuba;
346 
347  // return integral
348  return fIntegral;
349 
351  fIntegral = IntegrateSlice();
352 
353  // set used integration method
354  fIntegrationMethodUsed = BCIntegrate::kIntGrid;
355 
356  // return integral
357  return fIntegral;
358 
360  fIntegral = std::exp(IntegrateLaplace());
361  fIntegrationMethodUsed = BCIntegrate::kIntLaplace;
362  return fIntegral;
363 
365 #ifdef HAVE_CUBA_H
367 #else
368  if (GetNFreeParameters() <= 3)
370  else
372 #endif
373  return Integrate();
374  }
375 
376  default:
377  BCLog::OutError(Form("BCIntegrate::Integrate : Invalid integration method: %d", fIntegrationMethodCurrent));
378  break;
379  }
380 
381  return 0;
382 }
383 
384 // ---------------------------------------------------------
386 {
387  // remember original method
388  BCIntegrationMethod method_temp = fIntegrationMethodCurrent;
389 
390  // set method
391  SetIntegrationMethod(intmethod);
392 
393  // run algorithm
394  double integral = Integrate();
395 
396  // re-set original method
397  SetIntegrationMethod(method_temp);
398 
399  // return integral
400  return integral;
401 
402 }
403 
404 // ---------------------------------------------------------
405 void BCIntegrate::SetBestFitParameters(const std::vector<double>& x, const double& new_value, double& old_value)
406 {
407  if (new_value < old_value)
408  return;
409  old_value = new_value;
411 }
412 
413 // ---------------------------------------------------------
414 void BCIntegrate::SetBestFitParameters(const std::vector<double>& x)
415 {
416  fBestFitParameters = x;
417 }
418 
419 // ---------------------------------------------------------
421 {
422 
423  const unsigned NVarNow = GetParameters().GetNFreeParameters();
424 
426 
427  if (GetNParameters() != NVarNow) {
428 
429  level = BCLog::detail;
430  bool printed = false;
431 
432  if (type == kIntCuba) {
433  BCLog::OutDetail(Form("Running %s (%s) integration over %i dimensions out of %i.",
434  DumpIntegrationMethod(type).c_str(),
435  DumpCubaIntegrationMethod(cubatype).c_str(),
436  NVarNow, GetNParameters()));
437  printed = true;
438  }
439 
440  if (not printed)
441  BCLog::OutDetail(Form("Running %s integration over %i dimensions out of %i.",
442  DumpIntegrationMethod(type).c_str(),
443  NVarNow, GetNParameters()));
444 
445  BCLog::OutDetail(" --> Fixed parameters:");
446  for (unsigned i = 0; i < GetNParameters(); i++)
447  if (GetParameter(i).Fixed())
448  BCLog::OutDetail(Form(" %3i : %g", i, GetParameter(i).GetFixedValue()));
449  } else {
450  bool printed = false;
451 
452  if (type == kIntCuba) {
453  BCLog::OutDetail(Form("Running %s (%s) integration over %i dimensions.",
454  DumpIntegrationMethod(type).c_str(),
455  DumpCubaIntegrationMethod(cubatype).c_str(),
456  NVarNow));
457  printed = true;
458  }
459 
460  if (not printed)
461  BCLog::OutDetail(Form("Running %s integration over %i dimensions.",
462  DumpIntegrationMethod(type).c_str(),
463  NVarNow));
464  }
465 
466  if (GetNIterationsMin() > 0 && GetNIterationsMax() > 0 ) {
467  BCLog::Out(level, Form(" --> Minimum number of iterations: %i", GetNIterationsMin()));
468  BCLog::Out(level, Form(" --> Maximum number of iterations: %i", GetNIterationsMax()));
469  }
470  BCLog::Out(level, Form(" --> Target relative precision: %e", GetRelativePrecision()));
471  BCLog::Out(level, Form(" --> Target absolute precision: %e", GetAbsolutePrecision()));
472 }
473 
474 // ---------------------------------------------------------
475 void BCIntegrate::LogOutputAtEndOfIntegration(double integral, double absprecision, double relprecision, int nIterations)
476 {
477  BCLog::OutSummary(Form(" --> Result of integration: %e +- %e", integral, absprecision));
478  BCLog::OutSummary(Form(" --> Obtained relative precision: %e. ", relprecision));
479  if (nIterations >= 0)
480  BCLog::OutSummary(Form(" --> Number of iterations: %i", nIterations));
481 }
482 
483 // ---------------------------------------------------------
484 void BCIntegrate::LogOutputAtIntegrationStatusUpdate(BCIntegrationMethod type, double integral, double absprecision, int nIterations)
485 {
486  BCLog::OutDetail(Form("%s. Iteration %i, integral: %e +- %e.", DumpIntegrationMethod(type).c_str(), nIterations, integral, absprecision));
487 }
488 
489 // ---------------------------------------------------------
491  std::vector<double>& sums)
492 {
494 
495  // reset variables
496  double pmax = 0;
497  double integral = 0;
498  double absprecision = 2 * fAbsolutePrecision;
499  double relprecision = 2 * fRelativePrecision;
500 
501  std::vector<double> randx (GetNParameters(), 0.);
502 
503  // how often to print out the info line to screen
504  int nwrite = UpdateFrequency(fNIterationsMax);
505 
506  // reset number of iterations
507  fNIterations = 0;
508  bool accepted;
509 
510  // iterate while number of iterations is lower than minimum number of iterations
511  // or precision is not reached and the number of iterations is lower than maximum number of iterations
512  while ((absprecision > std::max(GetAbsolutePrecision(), GetRelativePrecision() * integral) && GetNIterations() < GetNIterationsMax())
514 
515  // get random numbers
516  (this->*randomizer)(randx);
517 
518  // evaluate function at sampled point
519  // updating sums & checking for maximum probability
520 
521  SetBestFitParameters(randx, (this->*evaluator)(sums, randx, accepted), pmax);
522 
523  // increase number of iterations
524  if (accepted)
525  ++fNIterations;
526 
527  // update precisions
528  if (fNIterations % fNIterationsPrecisionCheck == 0) {
529  (*updater)(sums, fNIterations, integral, absprecision);
530  relprecision = absprecision / integral;
531  }
532 
533  // write status
534  if (fNIterations % nwrite == 0) {
535  double temp_integral;
536  double temp_absprecision;
537  (*updater)(sums, fNIterations, temp_integral, temp_absprecision);
538  LogOutputAtIntegrationStatusUpdate(type, temp_integral, temp_absprecision, fNIterations);
539  }
540  }
541 
542  // calculate integral
543  (*updater)(sums, fNIterations, integral, absprecision);
544  relprecision = absprecision / integral;
545 
546  if (fNIterations >= GetNIterationsMax())
547  BCLog::OutWarning("BCIntegrate::Integrate: Did not converge within maximum number of iterations");
548 
549  // print to log
550  LogOutputAtEndOfIntegration(integral, absprecision, relprecision, fNIterations);
551 
552  fError = absprecision;
553  return integral;
554 }
555 
556 // ---------------------------------------------------------
557 double BCIntegrate::EvaluatorMC(std::vector<double>& sums, const std::vector<double>& point, bool& accepted)
558 {
559  const double value = Eval(point);
560 
561  // all samples accepted in sample-mean integration
562  accepted = true;
563 
564  // add value to sum and sum of squares
565  sums[0] += value;
566  sums[1] += value * value;
567 
568  return value;
569 }
570 
571 // ---------------------------------------------------------
572 void BCIntegrate::IntegralUpdaterMC(const std::vector<double>& sums, const int& nIterations, double& integral, double& absprecision)
573 {
574  // sample mean including the volume of the parameter space
575  integral = sums[2] * sums[0] / nIterations;
576 
577  // unbiased estimate
578  absprecision = sqrt((1.0 / (nIterations - 1)) * (sums[2] * sums[2] * sums[1] / double(nIterations) - integral * integral));
579 }
580 
581 // ---------------------------------------------------------
583 {
584  switch (type) {
586  return false;
588  return true;
590  return true;
592  return true;
593  default:
594  BCLog::OutError(Form("BCIntegrate::CheckMarginalizationAvailability. Invalid marginalization method: %d.", type));
595  break;
596  }
597  return false;
598 }
599 
600 // ---------------------------------------------------------
601 bool BCIntegrate::CheckMarginalizationIndices(TH1* hist, const std::vector<unsigned>& index)
602 {
603  if (index.empty()) {
604  BCLog::OutError("BCIntegrate::Marginalize : No marginalization parameters chosen.");
605  return false;
606  }
607 
608  if (index.size() >= 4 || index.size() > GetNParameters()) {
609  BCLog::OutError("BCIntegrate::Marginalize : Too many marginalization parameters.");
610  return false;
611  }
612 
613  if ((int)index.size() < hist->GetDimension()) {
614  BCLog::OutError(Form("BCIntegrate::Marginalize : Too few (%d) indices supplied for histogram dimension (%d)", (int)index.size(), hist->GetDimension()));
615  return false;
616  }
617 
618  for (unsigned i = 0; i < index.size(); i++) {
619  // check if indices are in bounds
620  if (index[i] >= GetNParameters()) {
621  BCLog::OutError(Form("BCIntegrate::Marginalize : Parameter index (%d) out of bound.", index[i]));
622  return false;
623  }
624  // check for duplicate indices
625  for (unsigned j = 0; j < index.size(); j++)
626  if (i != j && index[i] == index[j]) {
627  BCLog::OutError(Form("BCIntegrate::Marginalize : Parameter index (%d) appears more than once", index[i]));
628  return false;
629  }
630  }
631  return true;
632 }
633 
634 // ---------------------------------------------------------
636 {
637  // check if parameters are defined
638  if (GetNParameters() < 1) {
639  BCLog::OutError("BCIntegrate::MarginalizeAll : No parameters defined. Aborting.");
640  return 0;
641  }
642 
643  // check if marginalization method is defined
645  BCLog::OutError(Form("BCIntegrate::MarginalizeAll : Marginalization method not implemented \'%s\'. Aborting.", DumpCurrentMarginalizationMethod().c_str()));
646  return 0;
647  }
648 
649  // output
650  if (!(fMarginalizationMethodCurrent == BCIntegrate::kMargDefault) && !(fMarginalizationMethodCurrent == BCIntegrate::kMargEmpty))
651  BCLog::OutSummary(Form("Marginalize using %s", DumpCurrentMarginalizationMethod().c_str()));
652 
653 
654  switch (GetMarginalizationMethod()) {
655 
656  // Empty
658  BCLog::OutWarning("BCIntegrate::MarginalizeAll : No marginalization method chosen.");
659  return 0;
660  }
661 
662  // Markov Chain Monte Carlo
664  // start preprocess
666 
667  // run the Markov chains
668  Metropolis();
669 
670  // start postprocess
672 
673  // set used marginalization method
674  fMarginalizationMethodUsed = BCIntegrate::kMargMetropolis;
675 
676  // check if mode is better than previous one
677  if ( (!fFlagIgnorePrevOptimization) && (fLogMaximum < BCEngineMCMC::GetLogMaximum()) ) {
678  fBestFitParameters = BCEngineMCMC::GetBestFitParameters();
679  fBestFitParameterErrors.assign(fBestFitParameters.size(), std::numeric_limits<double>::infinity());
680  fLogMaximum = BCEngineMCMC::GetLogMaximum();
681  fOptimizationMethodUsed = BCIntegrate::kOptMetropolis;
682  }
683 
684  break;
685  }
686 
687  // Sample Mean
689  return 0;
690  }
691 
692  // Slice
693  case BCIntegrate::kMargGrid: {
694  if (GetParameters().GetNFreeParameters() > 2) {
695  BCLog::OutWarning("BCIntegrate::MarginalizeAll : Grid marginalization only works for 1D and 2D problems.");
696  return 0;
697  }
698  if (GetNObservables() > 0)
699  BCLog::OutWarning("BCIntegrate::MarginalizeAll : Grid marginalization will not store resutls for user-defined observables.");
700 
701  // start preprocess
703 
704  std::vector<double> fixpoint = GetParameters().GetFixedValues();
705 
706  // delete pre-existing marginalizations
707  for (unsigned i = 0; i < fH1Marginalized.size(); ++i)
708  if (fH1Marginalized[i])
709  delete fH1Marginalized[i];
710  for (unsigned i = 0; i < fH2Marginalized.size(); ++i)
711  for (unsigned j = 0; j < fH2Marginalized[i].size(); ++j)
712  if (fH2Marginalized[i][j])
713  delete fH2Marginalized[i][j];
714  // set all pointers to zero
715  fH1Marginalized.assign(GetNParameters(), NULL);
716  fH2Marginalized.assign(GetNParameters(), std::vector<TH2*>(GetNParameters(), NULL));
717 
718  // count how often posterior is evaluated
719  unsigned nIterations = 0;
720 
721  // store highest probability
722  double log_max_val = -std::numeric_limits<double>::infinity();
723  std::vector<double> bestfit_parameters = fixpoint;
724  std::vector<double> bestfit_errors(GetNVariables(), std::numeric_limits<double>::infinity());
725 
726  if (GetParameters().GetNFreeParameters() == 1) { // Marginalize the free parameter to a 1D histogram
727  for (unsigned i = 0; i < GetNParameters(); ++i) {
728  if (GetParameter(i).Fixed())
729  continue;
730 
731  // calculate slice
732  fH1Marginalized[i] = GetSlice(i, nIterations, log_max_val, fixpoint, 0, false);
733 
734  if ( fH1Marginalized[i]->Integral() > 0 ) { // histogram is nonempty
735  const int index = fH1Marginalized[i]->GetMaximumBin();
736  bestfit_parameters[i] = fH1Marginalized[i]->GetBinCenter(index);
737  // approximate error by flat distribution in bin
738  bestfit_errors[i] = fH1Marginalized[i]->GetBinWidth(index) / sqrt(12);
739  }
740  }
741  }
742 
743  else if (GetNFreeParameters() == 2) { // marginalize the two free parameters to a 2D histogram
744  for (unsigned i = 0; i < GetNParameters(); ++i)
745  for (unsigned j = i + 1; j < GetNParameters(); ++j) {
746  if (GetParameter(i).Fixed() || GetParameter(j).Fixed())
747  continue;
748 
749  // calculate slice
750  fH2Marginalized[i][j] = GetSlice(i, j, nIterations, log_max_val, fixpoint, 0, false);
751 
752  if ( fH2Marginalized[i][j]->Integral() > 0 ) { // histogram is nonempty
753  int index1, index2, useless_index;
754  fH2Marginalized[i][j]->GetMaximumBin(index1, index2, useless_index);
755  bestfit_parameters[i] = fH2Marginalized[i][j]->GetXaxis()->GetBinCenter(index1);
756  bestfit_parameters[j] = fH2Marginalized[i][j]->GetYaxis()->GetBinCenter(index2);
757  // approximate errors by flat distribution in bin
758  bestfit_errors[i] = fH2Marginalized[i][j]->GetXaxis()->GetBinWidth(index1) / sqrt(12);
759  bestfit_errors[j] = fH2Marginalized[i][j]->GetYaxis()->GetBinWidth(index2) / sqrt(12);
760 
761  // 1D marginalize by projecting
762  fH1Marginalized[i] = fH2Marginalized[i][j]->ProjectionX(Form("h1_%s_parameter_%i", GetSafeName().data() , i));
763  if (fH1Marginalized[i])
764  fH1Marginalized[i]->SetTitle(GetParameter(i).H1Title().data());
765  fH1Marginalized[j] = fH2Marginalized[i][j]->ProjectionY(Form("h1_%s_parameter_%i", GetSafeName().data() , j));
766  if (fH1Marginalized[j])
767  fH1Marginalized[j]->SetTitle(GetParameter(j).H1Title().data());
768  }
769  }
770  }
771 
772  // save if improved the log posterior
773 
774  if (fBestFitParameters.empty() || log_max_val > GetLogMaximum()) {
775  fLogMaximum = log_max_val;
776  SetBestFitParameters(bestfit_parameters);
777  fBestFitParameterErrors = bestfit_errors;
778  }
779 
780  BCLog::OutDetail(" --> Global mode from Grid:");
781  BCLog::OutDebug(Form(" --> Posterior value: %g", log_max_val));
782  PrintParameters(GetBestFitParameters(), BCLog::OutDetail);
783 
784  // start postprocess
786 
787  // set used marginalization method
788  fMarginalizationMethodUsed = BCIntegrate::kMargGrid;
789 
790  break;
791  }
792 
793  // default
795  if ( GetNFreeParameters() <= 2 && GetNObservables() == 0)
797  else
799 
800  // call again
801  return MarginalizeAll();
802 
803  break;
804  }
805 
806  default: {
807  BCLog::OutError(Form("BCIntegrate::MarginalizeAll : Invalid marginalization method: %d", GetMarginalizationMethod()));
808  return 0;
809  break;
810  }
811 
812  } // end switch
813 
814  // set flag
815  fFlagMarginalized = true;
816 
817  return 1;
818 }
819 
820 // ---------------------------------------------------------
822 {
823  // remember original method
824  BCMarginalizationMethod method_temp = fMarginalizationMethodCurrent;
825 
826  // set method
827  SetMarginalizationMethod(margmethod);
828 
829  // run algorithm
830  int result = MarginalizeAll();
831 
832  // re-set original method
833  SetMarginalizationMethod(method_temp);
834 
835  // return result
836  return result;
837 }
838 
839 // ---------------------------------------------------------
840 TH1* BCIntegrate::GetSlice(std::vector<unsigned> indices, unsigned& nIterations, double& log_max_val, const std::vector<double> parameters, int nbins, bool normalize)
841 {
842  if (indices.empty()) {
843  BCLog::OutError("BCIntegrate::GetSlice : No parameter indices provided.");
844  return NULL;
845  }
846 
847  if (indices.size() > 3) {
848  BCLog::OutError("BCIntegrate::GetSlice : Too many parameter indices provided. Max is three.");
849  return NULL;
850  }
851 
852  for (unsigned i = 0; i < indices.size(); ++i)
853  if (indices[i] >= GetNParameters()) {
854  BCLog::OutError("BCIntegrate::GetSlice : Parameter index out of range.");
855  return NULL;
856  } else // check for duplicates
857  for (unsigned j = i + 1; j < indices.size(); ++j)
858  if (indices[i] == indices[j]) {
859  BCLog::OutError("BCIntegrate::GetSlice : duplicate parameter indices provided.");
860  return NULL;
861  }
862 
863  // project (N+n)D slice for (N)D slice
864  if (parameters.empty() && indices.size() < GetNFreeParameters() && GetNFreeParameters() <= 3) {
865  unsigned N = indices.size();
866 
867  // find unfixed parameters and add them to indices
868  for (unsigned i = 0; i < GetNParameters(); ++i)
869  if (std::find(indices.begin(), indices.end(), i) == indices.end() && !GetParameter(i).Fixed())
870  indices.push_back(i);
871 
872  // slice in full free dimensions
873  TH1* slice_NnD = GetSlice(indices, nIterations, log_max_val, parameters, nbins, normalize);
874  if (slice_NnD == NULL)
875  return NULL;
876 
877  if (N == 1) {
878  TH1* h = NULL;
879  // 2->1
880  if (dynamic_cast<TH2*>(slice_NnD) != NULL)
881  h = dynamic_cast<TH2*>(slice_NnD)->ProjectionX(Form("h1_slice_%s_%d", GetSafeName().data(), indices[0]));
882  // 3->1
883  if (dynamic_cast<TH3*>(slice_NnD) != NULL)
884  h = dynamic_cast<TH3*>(slice_NnD)->ProjectionX(Form("h1_slice_%s_%d", GetSafeName().data(), indices[0]));
885  if (h)
886  h->SetTitle(GetParameter(indices[0]).H1Title().data());
887  return h;
888  }
889  // 3->2
890  if (N == 2 && dynamic_cast<TH3*>(slice_NnD) != NULL) {
891  TH1* h = dynamic_cast<TH3*>(slice_NnD)->Project3D("xy_temp_slice_projection");
892  if (h) {
893  h->SetName(Form("h1_slice_%s_%d_%d", GetSafeName().data(), indices[0], indices[1]));
894  h->SetTitle(GetParameter(indices[0]).H2Title(GetParameter(indices[1])).data());
895  }
896  return h;
897  }
898  }
899 
900  // create local copy of parameters
901  std::vector<double> parameters_temp = parameters;
902  if (parameters_temp.empty()) {
903  // check that remaining parameters are fixed
904  for (unsigned i = 0; i < GetNParameters(); ++i)
905  if (std::find(indices.begin(), indices.end(), i) == indices.end() && !GetParameter(i).Fixed()) {
906  BCLog::OutError("BCIntegrate::GetSlice : All non-sliced parameters must be fixed or provided values in function call.");
907  return NULL;
908  }
909  // set to fixed values
910  parameters_temp = GetParameters().GetFixedValues();
911  }
912 
913  // store previous binning preferences
914  std::vector<unsigned> nbins_temp;
915  for (unsigned i = 0; i < indices.size(); ++i) {
916  nbins_temp.push_back(GetParameter(indices[i]).GetNbins());
917  if (nbins > 0) // set new binning
918  GetParameter(indices[i]).SetNbins(nbins);
919  }
920 
921  // create histogram
922  TH1* h = NULL;
923  if (indices.size() == 1) {
924  h = GetParameter(indices[0]).CreateH1(Form("h1_slice_%s_%d", GetSafeName().data(), indices[0]));
925  // set y-axis label
926  if (GetNParameters() > 1)
927  h->GetYaxis()->SetTitle(Form("%s (all other parameters fixed)", h->GetYaxis()->GetTitle()));
928  } else if (indices.size() == 2) {
929  h = GetParameter(indices[0]).CreateH2(Form("h2_slice_%s_%d_%d", GetSafeName().data(), indices[0], indices[1]), GetParameter(indices[1]));
930  // set z-axis label
931  if (GetNParameters() > 2)
932  h->GetZaxis()->SetTitle(Form("%s (all other parameters fixed)", h->GetZaxis()->GetTitle()));
933  } else if (indices.size() == 3) {
934  h = GetParameter(indices[0]).CreateH3(Form("h3_slice_%s_%d_%d_%d", GetSafeName().data(), indices[0], indices[1], indices[2]), GetParameter(indices[1]), GetParameter(indices[2]));
935  // set z-axis label
936  if (GetNParameters() > 3)
937  h->GetZaxis()->SetTitle(Form("%s (all other parameters fixed)", h->GetZaxis()->GetTitle()));
938  }
939 
940  // reset log_max_val
941  log_max_val = -std::numeric_limits<double>::infinity();
942 
943  double log_min_val = std::numeric_limits<double>::infinity();
944 
945  // fill histogram
946  // calculate number of bins
947  int N = h->GetBin(h->GetNbinsX(), h->GetNbinsY(), h->GetNbinsZ());
948  int bx, by, bz;
949  // loop over all bins
950  for (int b = 1; b <= N; ++b) {
951  // skip if bin is underflow or overflow
952  if (h->IsBinUnderflow(b) || h->IsBinOverflow(b))
953  continue;
954  // get local bin numbers for each axis
955  h->GetBinXYZ(b, bx, by, bz);
956  // update x axis value
957  parameters_temp[indices[0]] = h->GetXaxis()->GetBinCenter(bx);
958  // update y axis value if 2D
959  if (by > 0 && indices.size() > 1)
960  parameters_temp[indices[1]] = h->GetYaxis()->GetBinCenter(by);
961  // update z axis value if 3D
962  if (bz > 0 && indices.size() > 2)
963  parameters_temp[indices[2]] = h->GetZaxis()->GetBinCenter(bz);
964  // calculate log of function value at parameters
965  double log_eval = LogEval(parameters_temp);
966  ++nIterations;
967 
968  // check max val
969  log_max_val = std::max<double>(log_max_val, log_eval);
970  // check min val
971  log_min_val = std::min<double>(log_min_val, log_eval);
972  // set bin content by global bin number
973  h->SetBinContent(b, log_eval);
974  }
975 
976  // remove log pedestal and exponentiate resulting value
977  for (int b = 1; b <= N; ++b) {
978  if (h->IsBinUnderflow(b) || h->IsBinOverflow(b))
979  continue;
980  h->SetBinContent(b, exp(h->GetBinContent(b) - log_max_val));
981  }
982 
983  // normalize
984  if (normalize) {
985  double integral = h->Integral("width");
986  if (integral != 0)
987  h->Scale(1. / integral);
988  }
989 
990  // reset binning
991  for (unsigned i = 0; i < indices.size(); ++i)
992  GetParameter(indices[i]).SetNbins(nbins_temp[i]);
993 
994  return h;
995 }
996 
997 // ---------------------------------------------------------
998 TH2* BCIntegrate::GetSlice(unsigned index1, unsigned index2, unsigned& nIterations, double& log_max_val, const std::vector<double> parameters, int nbins, bool normalize)
999 {
1000  std::vector<unsigned> indices(1, index1);
1001  indices.push_back(index2);
1002  return (TH2*) GetSlice(indices, nIterations, log_max_val, parameters, nbins, normalize);
1003 }
1004 
1005 // ---------------------------------------------------------
1006 double BCIntegrate::GetRandomPoint(std::vector<double>& x)
1007 {
1009  return Eval(x);
1010 }
1011 
1012 // ---------------------------------------------------------
1013 void BCIntegrate::GetRandomVectorInParameterSpace(std::vector<double>& x) const
1014 {
1015  // get random vector in unit hypercube
1016  const_cast<TRandom3*>(&fRandom)->RndmArray(x.size(), &x.front());
1017  // translate it into values in ranges of the parameters
1019 }
1020 
1021 // ---------------------------------------------------------
1022 std::vector<double> BCIntegrate::FindMode(std::vector<double> start)
1023 {
1024  if (GetNParameters() < 1) {
1025  BCLog::OutError("FindMode : No parameters defined. Aborting.");
1026  return std::vector<double>();
1027  }
1028 
1029  if (start.empty() && GetBestFitParameters().size() >= GetNParameters())
1030  start = GetBestFitParameters();
1031 
1032  if (start.size() > GetNParameters())
1033  start.resize(GetNParameters());
1034 
1035  std::vector<double> mode_temp(GetNParameters());
1036  std::vector<double> errors_temp(GetNParameters());
1037  BCIntegrate::BCOptimizationMethod method_temp = fOptimizationMethodCurrent;
1038 
1039  // output
1040  if (!(fOptimizationMethodCurrent == BCIntegrate::kOptDefault) && !(fOptimizationMethodCurrent == BCIntegrate::kOptEmpty))
1041  BCLog::OutSummary(Form("Finding mode using %s", DumpCurrentOptimizationMethod().c_str()));
1042 
1043  switch (fOptimizationMethodCurrent) {
1044 
1045  case BCIntegrate::kOptEmpty: {
1046  BCLog::OutWarning("BCIntegrate::FindMode : No optimization method chosen.");
1047  return std::vector<double>();
1048  }
1049 
1050  case BCIntegrate::kOptSimAnn: {
1051  FindModeSA(mode_temp, errors_temp, start);
1052  break;
1053  }
1054 
1056  FindModeMCMC(mode_temp, errors_temp);
1057  break;
1058  }
1059 
1062  /* Falls through. */
1063  case BCIntegrate::kOptMinuit: {
1064  BCIntegrate::FindModeMinuit(mode_temp, errors_temp, start, ::PrintLevel());
1065  break;
1066  }
1067 
1068  default:
1069  BCLog::OutError(Form("BCIntegrate::FindMode : Invalid mode finding method: %d", GetOptimizationMethod()));
1070  return std::vector<double>();
1071  }
1072 
1073  // calculate function at new mode
1074  double fcnatmode_temp = LogEval(mode_temp);
1075 
1076  // replace previous mode
1077  if (fFlagIgnorePrevOptimization || fcnatmode_temp > fLogMaximum) {
1078  SetBestFitParameters(mode_temp);
1079  fBestFitParameterErrors = errors_temp;
1080  fBestFitParameterErrors.resize(GetBestFitParameters().size(), std::numeric_limits<double>::infinity());
1081  fOptimizationMethodUsed = method_temp;
1082  fLogMaximum = fcnatmode_temp;
1083  }
1084 
1085  // return the new mode
1086  return fBestFitParameters;
1087 }
1088 
1089 // ---------------------------------------------------------
1090 std::vector<double> BCIntegrate::FindMode(BCIntegrate::BCOptimizationMethod optmethod, std::vector<double> start)
1091 {
1092  // remember original method
1093  BCOptimizationMethod method_temp = fOptimizationMethodCurrent;
1094 
1095  // set method
1096  SetOptimizationMethod(optmethod);
1097 
1098  // run algorithm
1099  std::vector<double> mode = FindMode(start);
1100 
1101  // re-set original method
1102  SetOptimizationMethod(method_temp);
1103 
1104  // return mode
1105  return mode;
1106 }
1107 
1108 // ---------------------------------------------------------
1109 std::vector<double> BCIntegrate::FindModeMinuit(std::vector<double>& mode, std::vector<double>& errors, std::vector<double> start, int printlevel)
1110 {
1111 
1112  if (fParameters.Size() < 1) {
1113  BCLOG_ERROR("No parameters defined. Aborting.");
1114  return std::vector<double>();
1115  }
1116 
1117  // set number of chains to be at least one, and call MCMCUserInitialize
1118  // allowing the user to make preparations of his or her model if necessary
1119  if (GetNChains() == 0)
1120  SetNChains(1);
1122  // set chain number to 0
1123  UpdateChainIndex(0);
1124 
1125  // check start values
1126  if (!start.empty() && start.size() != fParameters.Size()) {
1127  BCLOG_WARNING("Start point not valid (mismatch of dimensions), set to center.");
1128  start.clear();
1129  }
1130 
1131  // check fixed values and issue warning before forcing to fixed
1132  if (!start.empty() && !GetParameters().IsAtFixedValues(start)) {
1133  BCLOG_WARNING("Start point's fixed values not properly set. Forcing to fixed values.");
1135  }
1136 
1137  // check if point is allowed
1138  if (!start.empty() && !GetParameters().IsWithinLimits(start)) {
1139  BCLOG_WARNING("Start point not valid, set unfixed parameters to range center.");
1140  start.clear();
1141  }
1142 
1143  // define minuit with starting values
1144  fMinimizer.Init(start, printlevel);
1145 
1146  // do the actual work of minimization
1147  fMinimizer.min.Minimize();
1148 
1149  // copy over most important results, the minimizer itself can't be copied
1150  std::copy(fMinimizer.min.X(), fMinimizer.min.X() + fParameters.Size(), mode.begin());
1151  std::copy(fMinimizer.min.Errors(), fMinimizer.min.Errors() + fParameters.Size(), errors.begin());
1152 
1153  return mode;
1154 }
1155 
1156 // ---------------------------------------------------------
1157 std::vector<double> BCIntegrate::FindModeSA(std::vector<double>& mode, std::vector<double>& errors, std::vector<double> start)
1158 {
1159  // set number of chains to be at least one, and call MCMCUserInitialize
1160  // allowing the user to make preparations of his or her model if necessary
1161  if (GetNChains() == 0)
1162  SetNChains(1);
1164  // set chain number to 0
1165  UpdateChainIndex(0);
1166 
1167  // note: if f(x) is the function to be minimized, then
1168  // f(x) := - LogEval(parameters)
1169 
1170  std::vector<double> x, y; // vectors for current state, new proposed state and best fit up to now
1171  double fval_x, fval_y, fval_mode; // function values at points x, y and mode (we save them rather than to re-calculate them every time)
1172  int t = 1; // time iterator
1173 
1174  // check start values
1175  if (!start.empty() && start.size() != fParameters.Size()) {
1176  BCLog::OutWarning("BCIntegrate::FindModeSA : Start point not valid (mismatch of dimensions), set to center.");
1177  start.clear();
1178  }
1179 
1180  // check if point is allowed
1181  if (!start.empty() && !GetParameters().IsWithinLimits(start)) {
1182  BCLog::OutWarning("BCIntegrate::FindModeSA : Start point not valid (parameter not inside valid range), set to center.");
1183  start.clear();
1184  }
1185 
1186  // check fixed values and issue warning before forcing to fixed
1187  if (!start.empty() && !GetParameters().IsAtFixedValues(start)) {
1188  BCLog::OutWarning("BCIntegrate::FindModeSA : Start point fixed values not properly set. Forcing to fixed values.");
1190  }
1191 
1192  if (start.empty())
1193  // if empty, set to center, with fixed values fixed
1194  start = GetParameters().GetRangeCenters();
1195 
1196  // set current state and best fit to starting point
1197  x = start;
1198  mode = start;
1199 
1200  // calculate function value at starting point
1201  fval_x = fval_mode = LogEval(x);
1202 
1203  // run while still "hot enough"
1204  while ( SATemperature(t) > fSATmin ) {
1205  // generate new state
1206  y = GetProposalPointSA(x, t);
1207 
1208  // check if the proposed point is inside the phase space (ignoring fixed parameters)
1209  if (GetParameters().IsWithinLimits(y)) {
1210  // calculate function value at new point
1211  fval_y = LogEval(y);
1212 
1213  // is it better than the last one?
1214  // if so, update state and chef if it is the new best fit...
1215  if (fval_y >= fval_x) {
1216  x = y;
1217 
1218  fval_x = fval_y;
1219 
1220  if (fval_y > fval_mode) {
1221  mode = y;
1222  fval_mode = fval_y;
1223  }
1224  }
1225  // ...else, only accept new state w/ certain probability
1226  else {
1227  if (fRandom.Rndm() <= exp( (fval_y - fval_x) / SATemperature(t) )) {
1228  x = y;
1229  fval_x = fval_y;
1230  }
1231  }
1232  }
1233 
1234  // update tree variables
1235  fSANIterations = t;
1237  fSALogProb = fval_x;
1238  fSAx = x;
1239 
1240  // increate t
1241  t++;
1242  }
1243 
1244  // calculate uncertainty
1245  errors.assign(fParameters.Size(), -1);
1246 
1247  return mode;
1248 }
1249 
1250 // ---------------------------------------------------------
1251 double BCIntegrate::SATemperature(double t) const
1252 {
1253  // do we have Cauchy (default), Boltzmann or custom annealing schedule?
1254  if (fSASchedule == BCIntegrate::kSABoltzmann)
1255  return SATemperatureBoltzmann(t);
1256  else if (fSASchedule == BCIntegrate::kSACauchy)
1257  return SATemperatureCauchy(t);
1258  else
1259  return SATemperatureCustom(t);
1260 }
1261 
1262 // ---------------------------------------------------------
1264 {
1265  return fSAT0 / log(t + 1);
1266 }
1267 
1268 // ---------------------------------------------------------
1269 double BCIntegrate::SATemperatureCauchy(double t) const
1270 {
1271  return fSAT0 / t;
1272 }
1273 
1274 // ---------------------------------------------------------
1275 double BCIntegrate::SATemperatureCustom(double /*t*/) const
1276 {
1277  BCLog::OutError("BCIntegrate::SATemperatureCustom : No custom temperature schedule defined");
1278  return 0.;
1279 }
1280 
1281 // ---------------------------------------------------------
1282 std::vector<double> BCIntegrate::GetProposalPointSA(const std::vector<double>& x, int t) const
1283 {
1284  // do we have Cauchy (default), Boltzmann or custom annealing schedule?
1285  if (fSASchedule == BCIntegrate::kSABoltzmann)
1286  return GetProposalPointSABoltzmann(x, t);
1287  else if (fSASchedule == BCIntegrate::kSACauchy)
1288  return GetProposalPointSACauchy(x, t);
1289  else
1290  return GetProposalPointSACustom(x, t);
1291 }
1292 
1293 // ---------------------------------------------------------
1294 std::vector<double> BCIntegrate::GetProposalPointSABoltzmann(const std::vector<double>& x, int t) const
1295 {
1296  std::vector<double> y;
1297  y.clear();
1298  double new_val, norm;
1299 
1300  for (unsigned i = 0; i < fParameters.Size(); i++) {
1301  if (GetParameter(i).Fixed()) {
1302  y.push_back(GetParameter(i).GetFixedValue());
1303  } else {
1304  norm = GetParameter(i).GetRangeWidth() * SATemperature(t) / 2.;
1305  new_val = x[i] + norm * const_cast<TRandom3*>(&fRandom)->Gaus();
1306  y.push_back(new_val);
1307  }
1308  }
1309 
1310  return y;
1311 }
1312 
1313 // ---------------------------------------------------------
1314 std::vector<double> BCIntegrate::GetProposalPointSACauchy(const std::vector<double>& x, int t) const
1315 {
1316  std::vector<double> y;
1317  y.clear();
1318 
1319  if (GetNParameters() == 1) {
1320  double cauchy, new_val, norm;
1321 
1322  if (GetParameter(0).Fixed()) {
1323  y.push_back(GetParameter(0).GetFixedValue());
1324  } else {
1325  norm = GetParameter(0).GetRangeWidth() * SATemperature(t) / 2.;
1326  cauchy = tan(3.14159 * (const_cast<TRandom3*>(&fRandom)->Rndm() - 0.5));
1327  new_val = x[0] + norm * cauchy;
1328  y.push_back(new_val);
1329  }
1330  } else {
1331  // use sampling to get radial n-dim Cauchy distribution
1332 
1333  // first generate a random point uniformly distributed on a
1334  // fNvar-dimensional hypersphere
1336 
1337  // scale the vector by a random factor determined by the radial
1338  // part of the fNvar-dimensional Cauchy distribution
1339  double radial = SATemperature(t) * SAHelperGetRadialCauchy();
1340 
1341  // scale y by radial part and the size of dimension i in phase space
1342  // afterwards, move by x
1343  for (unsigned i = 0; i < GetNParameters(); i++) {
1344  if (GetParameter(i).Fixed()) {
1345  y[i] = GetParameter(i).GetFixedValue();
1346  } else {
1347  y[i] = GetParameter(i).GetRangeWidth() * y[i] * radial / 2. + x[i];
1348  }
1349  }
1350  }
1351 
1352  return y;
1353 }
1354 
1355 // ---------------------------------------------------------
1356 std::vector<double> BCIntegrate::GetProposalPointSACustom(const std::vector<double>& /*x*/, int /*t*/) const
1357 {
1358  BCLog::OutError("BCIntegrate::GetProposalPointSACustom : No custom proposal function defined");
1359  return std::vector<double>(fParameters.Size());
1360 }
1361 
1362 // ---------------------------------------------------------
1364 {
1365  std::vector<double> rand_point(fParameters.Size());
1366 
1367  // This method can only be called with fNvar >= 2 since the 1-dim case
1368  // is already hard wired into the Cauchy annealing proposal function.
1369  // To speed things up, hard-code fast method for 2 and dimensions.
1370  // The algorithm for 2D can be found at
1371  // http://mathworld.wolfram.com/CirclePointPicking.html
1372  // For 3D just using ROOT's algorithm.
1373  if (fParameters.Size() == 2) {
1374  double x1, x2, s;
1375  do {
1376  x1 = const_cast<TRandom3*>(&fRandom)->Rndm() * 2. - 1.;
1377  x2 = const_cast<TRandom3*>(&fRandom)->Rndm() * 2. - 1.;
1378  s = x1 * x1 + x2 * x2;
1379  } while (s >= 1);
1380 
1381  rand_point[0] = (x1 * x1 - x2 * x2) / s;
1382  rand_point[1] = (2.*x1 * x2) / s;
1383  } else if (fParameters.Size() == 3) {
1384  const_cast<TRandom3*>(&fRandom)->Sphere(rand_point[0], rand_point[1], rand_point[2], 1.0);
1385  } else {
1386  double s = 0.,
1387  gauss_num;
1388 
1389  for (unsigned i = 0; i < fParameters.Size(); i++) {
1390  gauss_num = const_cast<TRandom3*>(&fRandom)->Gaus();
1391  rand_point[i] = gauss_num;
1392  s += gauss_num * gauss_num;
1393  }
1394  s = sqrt(s);
1395 
1396  for (unsigned i = 0; i < fParameters.Size(); i++)
1397  rand_point[i] = rand_point[i] / s;
1398  }
1399 
1400  return rand_point;
1401 }
1402 
1403 // ---------------------------------------------------------
1405 {
1406  // theta is sampled from a rather complicated distribution,
1407  // so first we create a lookup table with 10000 random numbers
1408  // once and then, each time we need a new random number,
1409  // we just look it up in the table.
1410  double theta;
1411 
1412  // static vectors for theta-sampling-map
1413  static double map_u[10001];
1414  static double map_theta[10001];
1415  static bool initialized = false;
1416  static unsigned map_dimension = 0;
1417 
1418  // is the lookup-table already initialized? if not, do it!
1419  if (!initialized || map_dimension != fParameters.Size()) {
1420  double init_theta;
1421  double beta = SAHelperSinusToNIntegral(fParameters.Size() - 1, 1.57079632679);
1422 
1423  for (int i = 0; i <= 10000; i++) {
1424  init_theta = 3.14159265 * (double)i / 5000.;
1425  map_theta[i] = init_theta;
1426 
1427  map_u[i] = SAHelperSinusToNIntegral(fParameters.Size() - 1, init_theta) / beta;
1428  }
1429 
1430  map_dimension = fParameters.Size();
1431  initialized = true;
1432  } // initializing is done.
1433 
1434  // generate uniform random number for sampling
1435  double u = const_cast<TRandom3*>(&fRandom)->Rndm();
1436 
1437  // Find the two elements just greater than and less than u
1438  // using a binary search (O(log(N))).
1439  int lo = 0;
1440  int up = 10000;
1441  int mid;
1442 
1443  while (up != lo) {
1444  mid = ((up - lo + 1) / 2) + lo;
1445 
1446  if (u >= map_u[mid])
1447  lo = mid;
1448  else
1449  up = mid - 1;
1450  }
1451  up++;
1452 
1453  // perform linear interpolation:
1454  theta = map_theta[lo] + (u - map_u[lo]) / (map_u[up] - map_u[lo]) * (map_theta[up] - map_theta[lo]);
1455 
1456  return tan(theta);
1457 }
1458 
1459 // ---------------------------------------------------------
1460 double BCIntegrate::SAHelperSinusToNIntegral(int dim, double theta) const
1461 {
1462  if (dim < 1)
1463  return theta;
1464  else if (dim == 1)
1465  return (1. - cos(theta));
1466  else if (dim == 2)
1467  return 0.5 * (theta - sin(theta) * cos(theta));
1468  else if (dim == 3)
1469  return (2. - sin(theta) * sin(theta) * cos(theta) - 2. * cos(theta)) / 3.;
1470  else
1471  return - pow(sin(theta), (double)(dim - 1)) * cos(theta) / (double)dim
1472  + (double)(dim - 1) / (double)dim
1473  * SAHelperSinusToNIntegral(dim - 2, theta);
1474 }
1475 
1476 // ---------------------------------------------------------
1477 std::vector<double> BCIntegrate::FindModeMCMC(std::vector<double>& mode, std::vector<double>& errors)
1478 {
1479  MetropolisPreRun();
1480 
1483 
1484  return mode;
1485 }
1486 
1487 // ---------------------------------------------------------
1489 {
1490  if (method >= BCIntegrate::NIntMethods) {
1491  BCLog::OutError(Form("BCIntegrate::SetIntegrationMethod: Invalid method '%d' ", method));
1492  return;
1493  }
1494  if (method == BCIntegrate::kIntCuba) {
1495 #ifndef HAVE_CUBA_H
1496  BCLog::OutError("BCIntegrate::SetIntegrationMethod: Cuba not enabled during configure");
1497 #endif
1498  }
1499  fIntegrationMethodCurrent = method;
1500 }
1501 
1502 // ---------------------------------------------------------
1504 {
1505 #ifdef HAVE_CUBA_H
1506  switch (type) {
1512  fCubaIntegrationMethod = type;
1513  return;
1514  default:
1515  BCLog::OutError(Form("Integration method of type %d is not defined for Cuba", type));
1516  return;
1517  }
1518 #else
1519  (void) type; // suppress compiler warning about unused parameters
1520  BCLog::OutError("SetCubaIntegrationMethod: Cuba not enabled during configure");
1521 #endif
1522 }
1523 
1524 // ---------------------------------------------------------
1525 double BCIntegrate::IntegrateCuba(BCCubaMethod cubatype)
1526 {
1527 #if HAVE_CUBA_H
1528  // integrand has only one component
1529  static const int ncomp = 1;
1530 
1531  // don't store integration in a slot for reuse
1532  static const int gridno = -1;
1533 
1534  // we don't want dumps of internal state
1535  static const char* statefile = "";
1536 
1537  // only evaluate at one position in parameter space at a time
1538  static const int nvec = 1;
1539 
1540 #if CUBAVERSION > 33
1541  // we have no spinning cores
1542  int* spin = 0;
1543 #endif
1544 
1545  // cuba returns info in these variables
1546  int fail = 0;
1547  int nregions = 0;
1548  std::vector<double> integral(ncomp, -1);
1549  std::vector<double> error(ncomp, -1);
1550  std::vector<double> prob(ncomp, -1);
1551 
1552  // reset number of iterations
1553  fNIterations = 0;
1554 
1555  // Cuba needs int variable
1556  int nIntegrationVariables = GetParameters().GetNFreeParameters();
1557 
1558  if (cubatype == BCIntegrate::kCubaDefault) {
1559  switch (nIntegrationVariables) {
1560  case 1:
1561  cubatype = BCIntegrate::kCubaVegas;
1562  break;
1563  case 2:
1564  case 3:
1565  cubatype = BCIntegrate::kCubaCuhre;
1566  break;
1567  default:
1568  cubatype = BCIntegrate::kCubaDivonne;
1569  break;
1570  }
1571  if (nIntegrationVariables > 33)
1572  cubatype = BCIntegrate::kCubaVegas;
1573  }
1575 
1576  switch (cubatype) {
1577 
1579  Vegas(nIntegrationVariables, ncomp,
1580  &BCIntegrate::CubaIntegrand, static_cast<void*>(this),
1581  nvec,
1582  fRelativePrecision, fAbsolutePrecision,
1583  fCubaVegasOptions.flags, fRandom.GetSeed(),
1584  fNIterationsMin, fNIterationsMax,
1585  fCubaVegasOptions.nstart, fCubaVegasOptions.nincrease, fCubaVegasOptions.nbatch,
1586  gridno, statefile,
1587 #if CUBAVERSION > 33
1588  spin,
1589 #endif
1590  &fNIterations, &fail,
1591  &integral[0], &error[0], &prob[0]);
1592  break;
1593 
1595  Suave(nIntegrationVariables, ncomp,
1596  &BCIntegrate::CubaIntegrand, static_cast<void*>(this),
1597  nvec,
1598  fRelativePrecision, fAbsolutePrecision,
1599  fCubaSuaveOptions.flags, fRandom.GetSeed(),
1600  fNIterationsMin, fNIterationsMax, fCubaSuaveOptions.nnew,
1601 #if CUBAVERSION > 40
1602  fCubaSuaveOptions.nmin,
1603 #endif
1604  fCubaSuaveOptions.flatness, statefile,
1605 #if CUBAVERSION > 33
1606  spin,
1607 #endif
1608  &nregions, &fNIterations, &fail,
1609  &integral[0], &error[0], &prob[0]);
1610  break;
1611 
1613  if (nIntegrationVariables < 2 || nIntegrationVariables > 33)
1614  BCLOG_WARNING("Divonne only works in 2 <= d <= 33 dimensions");
1615  else {
1616  // no extra info supported
1617  static const int ngiven = 0;
1618  static const int nextra = ngiven;
1619  Divonne(nIntegrationVariables, ncomp,
1620  &BCIntegrate::CubaIntegrand, static_cast<void*>(this),
1621  nvec,
1622  fRelativePrecision, fAbsolutePrecision,
1623  fCubaDivonneOptions.flags, fRandom.GetSeed(),
1624  fNIterationsMin, fNIterationsMax,
1625  fCubaDivonneOptions.key1, fCubaDivonneOptions.key2, fCubaDivonneOptions.key3,
1626  fCubaDivonneOptions.maxpass, fCubaDivonneOptions.border,
1627  fCubaDivonneOptions.maxchisq, fCubaDivonneOptions.mindeviation,
1628  ngiven, nIntegrationVariables /*ldxgiven*/, NULL, nextra, NULL,
1629  statefile,
1630 #if CUBAVERSION > 33
1631  spin,
1632 #endif
1633  &nregions, &fNIterations, &fail,
1634  &integral[0], &error[0], &prob[0]);
1635  }
1636  break;
1637 
1639  if (nIntegrationVariables < 2)
1640  BCLog::OutError("BCIntegrate::IntegrateCuba(Cuhre): Cuhre(cubature) only works in d > 1");
1641 
1642  Cuhre(nIntegrationVariables, ncomp,
1643  &BCIntegrate::CubaIntegrand, static_cast<void*>(this),
1644  nvec,
1645  fRelativePrecision, fAbsolutePrecision,
1646  fCubaCuhreOptions.flags, fNIterationsMin, fNIterationsMax,
1647  fCubaCuhreOptions.key,
1648  statefile,
1649 #if CUBAVERSION > 33
1650  spin,
1651 #endif
1652  &nregions, &fNIterations, &fail,
1653  &integral[0], &error[0], &prob[0]);
1654  break;
1655 
1657  default:
1658  BCLog::OutError("Cuba integration method not set.");
1659  error[0] = -1;
1660  integral[0] = -1;
1661  break;
1662  }
1663 
1664  fError = error[0];
1665  double result = integral[0];
1666 
1667  if (fail != 0) {
1668  BCLog::OutWarning(" Warning, integral did not converge with the given set of parameters. ");
1669  BCLog::OutWarning(Form(" neval = %d", fNIterations));
1670  BCLog::OutWarning(Form(" fail = %d", fail));
1671  BCLog::OutWarning(Form(" integral = %e", result));
1672  BCLog::OutWarning(Form(" error = %e", fError));
1673  BCLog::OutWarning(Form(" prob = %e", prob[0]));
1674 
1675  // handle cases in which cuba does not alter integral
1676  if (fNIterations == 0) {
1677  fError = -1;
1678  result = -1;
1679  }
1680 
1681  } else
1682  LogOutputAtEndOfIntegration(result, fError, fError / result, fNIterations);
1683 
1684  return result;
1685 #else
1686  (void) cubatype; // suppress compiler warning about unused parameters
1687  BCLog::OutError("IntegrateCuba: Cuba not enabled during configure");
1688  return -1;
1689 #endif
1690 }
1691 
1692 // ---------------------------------------------------------
1693 int BCIntegrate::CubaIntegrand(const int* ndim, const double xx[],
1694  const int* /*ncomp*/, double ff[], void* userdata)
1695 {
1696  BCIntegrate* local_this = static_cast<BCIntegrate*>(userdata);
1697 
1698  // scale variables
1699  double jacobian = 1.0;
1700 
1701  // create local parameter vector
1702  // important for thread safety, though not super efficient
1703  std::vector<double> scaled_parameters(local_this->fParameters.Size());
1704 
1705  // stay in sync with the possible lower number of parameters
1706  // that cuba sees due to fixing in BAT
1707  unsigned cubaIndex = 0;
1708  unsigned batIndex = 0;
1709  for (batIndex = 0; batIndex < local_this->fParameters.Size(); ++batIndex) {
1710  const BCParameter& p = local_this->GetParameter(batIndex);
1711 
1712  // get the scaled parameter value
1713  if (p.Fixed())
1714  scaled_parameters[batIndex] = p.GetFixedValue();
1715  else {
1716  // convert from unit hypercube to actual parameter hyperrectangle
1717  scaled_parameters[batIndex] = p.GetLowerLimit() + xx[cubaIndex] * p.GetRangeWidth();
1718 
1719  // multiply range to jacobian
1720  jacobian *= p.GetRangeWidth();
1721 
1722  // one more parameter that cuba varies
1723  ++cubaIndex;
1724  }
1725  }
1726 
1727  if (cubaIndex != unsigned(*ndim))
1728  BCLog::OutError(Form("BCIntegrate::CubaIntegrand: mismatch between variable parameters"
1729  "in BAT (%d) and Cuba(%d)", batIndex, cubaIndex));
1730 
1731  // call function to integrate
1732  ff[0] = local_this->Eval(scaled_parameters);
1733 
1734  // multiply jacobian
1735  ff[0] *= jacobian;
1736 
1737  return 0;
1738 }
1739 
1740 // ---------------------------------------------------------
1741 double BCIntegrate::IntegrateSlice()
1742 {
1743  // print to log
1744  LogOutputAtStartOfIntegration(fIntegrationMethodCurrent, NCubaMethods);
1745 
1746  double integral = -1;
1747  fError = -1;
1748 
1749  // precision isn't estimated here
1750  double absprecision = -1;
1751  double relprecision = -1;
1752 
1753  // get vector of fixed values
1754  std::vector<double> fixpoint = GetParameters().GetFixedValues();
1755 
1756  // get vector of indices of unfixed parameters
1757  std::vector<unsigned> indices;
1758  for (unsigned i = 0; i < GetNParameters(); ++i)
1759  if (!GetParameter(i).Fixed())
1760  indices.push_back(i);
1761 
1762  // check size of vector of indices
1763  if (indices.size() > 3) {
1764  BCLog::OutWarning("BCIntegrate::IntegrateSlice: Method only implemented for 1D, 2D, and 3D problems. Return -1.");
1765  integral = -1;
1766  }
1767 
1768  unsigned nIterations = 0;
1769  double log_max_val = -std::numeric_limits<double>::infinity();
1770 
1771  // get slice, without normalizing
1772  if (TH1* h = GetSlice(indices, nIterations, log_max_val, fixpoint, 0, false))
1773  integral = h->Integral("width") * exp(log_max_val);
1774 
1775  // print to log
1776  LogOutputAtEndOfIntegration(integral, absprecision, relprecision, nIterations);
1777 
1778  return integral;
1779 }
1780 
1781 // ---------------------------------------------------------
1783 {
1784  TMinuitMinimizer& min = fMinimizer.min;
1785  const unsigned nprevious_calls = min.NCalls();
1786  if (min.CovMatrixStatus() == 0) {
1787  BCLog::OutWarning("Laplace requires a successful run of minuit. Rerun with default starting point");
1789  }
1790 
1791  int status = min.CovMatrixStatus();
1792  switch (status) {
1793  case 1:
1794  BCLog::OutWarning("Covariance only approximated");
1795  break;
1796  case 2:
1797  BCLog::OutWarning("Covariance made positive definite");
1798  break;
1799  case 3:
1800  BCLog::OutDetail("Covariance accurate");
1801  break;
1802  case 0:
1803  default:
1804  BCLog::OutError("Cannot perform Laplace approximation without minuit's covariance. Return -1");
1805  return -1;
1806  }
1807  if (status < 3) {
1808  BCLog::OutDetail("Rerunning Hesse");
1809  min.Hesse();
1810  }
1811 
1812  // get point at which minuit evaluates the covariance
1813  std::vector<double> newpar(min.X(), min.X() + GetNParameters());
1814 
1815  /* Compute log of determinant of symmetric matrix from Cholesky decomp.
1816  * stay on log scale to avoid overflows. */
1817 
1818  // any fixed parameter reduces the rank of the covariance
1819  // ignore those zero rows/columns to compute the determinant
1820  unsigned nfree = GetNFreeParameters();
1821 
1822  TMatrixDSym cov(nfree);
1823  unsigned I = -1;
1824  for (unsigned i = 0; i < GetNParameters(); ++i) {
1825  if (GetParameter(i).Fixed())
1826  continue;
1827  ++I;
1828  cov(I, I) = min.CovMatrix(i, i);
1829 
1830  // reset counter for off diagonal elements
1831  unsigned J = I;
1832  for (unsigned j = i + 1; j < GetNParameters(); ++j) {
1833  if (GetParameter(j).Fixed())
1834  continue;
1835  ++J;
1836  cov(I, J) = min.CovMatrix(i, j);
1837  cov(J, I) = cov(I, J);
1838 
1839  }
1840  }
1841 
1842  TDecompChol CholeskyDecomposer;
1843  CholeskyDecomposer.SetMatrix(cov);
1844 
1845  if (!CholeskyDecomposer.Decompose()) {
1846  BCLog::OutError("Cholesky decomposition of covariance failed. Return -1");
1847  return -1;
1848  }
1849 
1850  // upper triagonal matrix is the result of decomposition
1851  const TMatrixD& U = CholeskyDecomposer.GetU();
1852 
1853  // determinant is just the product of diagonal elements
1854  double logDet = 0;
1855  for (unsigned I = 0; I < nfree; ++I)
1856  logDet += std::log(U(I, I));
1857 
1858  // Laplace approx. = function value over normalization constant of Gaussian
1859  double logIntegral = -min.MinValue() + 0.5 * nfree * std::log(2 * M_PI) + logDet;
1860  double linearIntegral = std::exp(logIntegral);
1861  fError = -1;
1862 
1863  BCLog::OutSummary(Form("Laplace approximation on the log scale = %g", logIntegral));
1864 
1865  LogOutputAtEndOfIntegration(linearIntegral, fError, fError, min.NCalls() - nprevious_calls);
1866 
1867  return logIntegral;
1868 }
1869 
1870 // ---------------------------------------------------------
1872 {
1873  switch (type) {
1875  return "Empty";
1877  return "Sample Mean Monte Carlo";
1878  case BCIntegrate::kIntCuba:
1879  return "Cuba";
1880  case BCIntegrate::kIntGrid:
1881  return "Grid";
1883  return "Laplace";
1884  default:
1885  return "Undefined";
1886  }
1887 }
1888 
1889 // ---------------------------------------------------------
1891 {
1892  switch (type) {
1894  return "Empty";
1896  return "Sample Mean Monte Carlo";
1898  return "Metropolis";
1900  return "Grid";
1902  return "Default";
1903  default:
1904  return "Undefined";
1905  }
1906 }
1907 
1908 // ---------------------------------------------------------
1910 {
1911  switch (type) {
1913  return "Empty";
1915  return "Simulated Annealing";
1917  return "Metropolis MCMC";
1919  return "Minuit";
1921  return "Default";
1922  default:
1923  return "Undefined";
1924  }
1925 }
1926 
1927 // ---------------------------------------------------------
1929 {
1930  switch (type) {
1932  return "Vegas";
1934  return "Suave";
1936  return "Divonne";
1938  return "Cuhre";
1940  return "Default";
1941  default:
1942  return "Undefined";
1943  }
1944 }
1945 
1946 // ---------------------------------------------------------
1947 BCCubaOptions::General::General():
1948  ncomp(1),
1949  flags(0),
1950  nregions(0),
1951  neval(0),
1952  fail(0),
1953  error(0),
1954  prob(0)
1955 {}
1956 
1957 /*
1958  * Copy default values from sec. 7.3.1 of the cuba manual for version 4.2.
1959  */
1960 
1961 // ---------------------------------------------------------
1962 BCCubaOptions::Vegas::Vegas():
1963  General(),
1964  nstart(1000),
1965  nincrease(500),
1966  nbatch(1000),
1967  gridno(0)
1968 {}
1969 
1970 // ---------------------------------------------------------
1971 BCCubaOptions::Suave::Suave():
1972  General(),
1973  nmin(2),
1974  nnew(1000),
1975  flatness(50)
1976 {}
1977 
1978 // ---------------------------------------------------------
1979 BCCubaOptions::Divonne::Divonne():
1980  General(),
1981  key1(47),
1982  key2(1),
1983  key3(1),
1984  maxpass(5),
1985  border(0),
1986  maxchisq(10),
1987  mindeviation(0.25)
1988 {}
1989 
1990 // ---------------------------------------------------------
1991 BCCubaOptions::Cuhre::Cuhre():
1992  General(),
1993  key(0) // let cuba choose default cubature rule
1994 {}
1995 
1996 // ---------------------------------------------------------
1998 {
1999  if (GetIntegral() >= 0) {
2000  BCLog::OutSummary(" Results of the integration");
2001  BCLog::OutSummary(" ============================");
2002  BCLog::OutSummary(" Integration method used: " + DumpUsedIntegrationMethod());
2003  if (GetError() >= 0)
2004  BCLog::OutSummary(Form(" Evidence: %f +- %f", GetIntegral(), GetError()));
2005  else
2006  BCLog::OutSummary(Form(" Evidence: %f (no error estimate available)", GetIntegral()));
2007  }
2008 
2009  if (fFlagMarginalized) {
2010  BCLog::OutSummary(" Marginalization algorithm used: " + DumpUsedMarginalizationMethod());
2011  BCLog::OutSummary("");
2013  }
2014 }
2015 
2016 // ---------------------------------------------------------
2018 {
2019  if (GetBestFitParameters().empty()) {
2020  BCLog::OutSummary("No best fit information available.");
2021  return;
2022  }
2023 
2024  BCLog::OutSummary(" Results of the optimization");
2025  BCLog::OutSummary(" ===========================");
2026  BCLog::OutSummary(" Optimization algorithm used: " + DumpUsedOptimizationMethod());
2027 
2029 }
2030 
2031 // ---------------------------------------------------------
2032 std::string BCIntegrate::GetBestFitSummary(unsigned i) const
2033 {
2034  if (i >= GetNVariables())
2035  return std::string("");
2036  if (i < GetBestFitParameterErrors().size() && GetBestFitParameterErrors()[i] != std::numeric_limits<double>::infinity())
2037  return BCEngineMCMC::GetBestFitSummary(i) + Form(" +- %.*g", GetVariable(i).GetPrecision(), GetBestFitParameterErrors()[i]);
2038  else if (!GetBestFitParameterErrors().empty())
2039  return BCEngineMCMC::GetBestFitSummary(i) + " (no error estimate available)";
2040  else
2042 }
BCEngineMCMC & operator=(const BCEngineMCMC &)
Copy-assignment operator.
BCIntegrate::BCMarginalizationMethod GetMarginalizationMethod() const
Definition: BCIntegrate.h:274
Simulated annealing.
Definition: BCIntegrate.h:155
virtual void ResetResults()
Reset the MCMC variables.
Print everything, including debug info.
Definition: BCLog.h:60
virtual TH1 * CreateH1(const std::string &name) const
Creates a 1D Histogram for this variable.
Definition: BCVariable.cxx:132
std::string DumpCubaIntegrationMethod() const
Return string with the name for the currently set Cuba integration type.
Definition: BCIntegrate.h:783
const std::vector< double > & GetBestFitParameterErrors() const
Returns the set of errors on the values of the parameters at the mode.
std::string DumpIntegrationMethod(BCIntegrationMethod type) const
Return string with the name for a given integration type.
BCIntegrate(const std::string &name="model")
Default constructor.
bool MetropolisPreRun()
Runs a pre run for the Metropolis algorithm.
Use CUBA interface.
Definition: BCIntegrate.h:167
double GetIntegral() const
Definition: BCIntegrate.h:259
bool CheckMarginalizationAvailability(BCMarginalizationMethod type)
Check availability of integration routine for marginalization.
double GetLogMaximum() const
Returns the posterior at the mode.
Definition: BCIntegrate.h:442
virtual unsigned Size() const
Number of variables contained.
virtual double LogEval(const std::vector< double > &x)
Evaluate the natural logarithm of the Eval function.
Definition: BCIntegrate.h:555
Sample mean method.
Definition: BCIntegrate.h:166
bool fFlagIgnorePrevOptimization
Flag for ignoring older results of optimization.
Definition: BCIntegrate.h:838
void SetMarginalizationMethod(BCIntegrate::BCMarginalizationMethod method)
Definition: BCIntegrate.h:465
virtual std::string GetBestFitSummary(unsigned i) const
Get string summarizing best fit for single variable.
void SetBestFitParameters(const std::vector< double > &x)
Set best fit parameters values.
unsigned GetNChains() const
Definition: BCEngineMCMC.h:279
void LogOutputAtEndOfIntegration(double integral, double absprecision, double relprecision, int nIterations)
Helper method to output at end of integration.
std::vector< double > GetProposalPointSACauchy(const std::vector< double > &x, int t) const
Generates a new state in a neighbourhood around x that is to be accepted or rejected by the Simulated...
int GetNIterations() const
Definition: BCIntegrate.h:311
void UpdateChainIndex(int chain)
Keep track of which chain is currently computed (within a thread).
std::string DumpCurrentOptimizationMethod() const
Return string with the name for the currently set optimization type.
Definition: BCIntegrate.h:765
bool Metropolis()
Runs Metropolis algorithm.
std::string DumpUsedOptimizationMethod() const
Return string with the name for the optimization type used to find the current mode.
Definition: BCIntegrate.h:771
virtual void PrintBestFitSummary() const
Print best fit to log.
BCParameter & GetParameter(unsigned index)
Definition: BCEngineMCMC.h:630
A class for handling numerical operations for models.
Definition: BCIntegrate.h:143
double EvaluatorMC(std::vector< double > &sums, const std::vector< double > &point, bool &accepted)
Evaluates integrator.
double(BCIntegrate::* tEvaluator)(std::vector< double > &, const std::vector< double > &, bool &)
A pointer for a function that evaluates at a point.
Definition: BCIntegrate.h:216
int MarginalizeAll()
Marginalize all probabilities wrt.
Metropolis Hastings.
Definition: BCIntegrate.h:156
virtual void MarginalizePreprocess()
Method executed for before marginalization.
Definition: BCIntegrate.h:610
virtual void MarginalizePostprocess()
Method executed after marginalization.
Definition: BCIntegrate.h:616
std::vector< double > FindMode(std::vector< double > start=std::vector< double >())
Do the mode finding using a method set via SetOptimizationMethod.
No marginalization method set.
Definition: BCIntegrate.h:177
std::string DumpMarginalizationMethod(BCMarginalizationMethod type) const
Return string with the name for a given marginalization type.
Print only results summary, warnings, and errors.
Definition: BCLog.h:62
double GetError() const
Definition: BCIntegrate.h:411
void PrintParameters(const std::vector< double > &P, void(*output)(const std::string &)=BCLog::OutSummary) const
Print parameters.
double fSALogProb
Log probability of current simulated annealing iteration.
Definition: BCIntegrate.h:858
static void Out(BCLog::LogLevel loglevelfile, BCLog::LogLevel loglevelscreen, const std::string &message)
Writes string to the file and screen log if the log level is equal or greater than the minimum...
Definition: BCLog.cxx:70
virtual void ValueFromPositionInRange(std::vector< double > &p) const
Translate from unit interval to values in variable ranges, fixing fixed parameters along the way...
double SAHelperGetRadialCauchy() const
Generates the radial part of a n-dimensional Cauchy distribution.
int GetNIterationsMin() const
Definition: BCIntegrate.h:296
std::string DumpUsedMarginalizationMethod() const
Return string with the name for the marginalization type used.
Definition: BCIntegrate.h:753
double SATemperature(double t) const
Temperature annealing schedule for use with Simulated Annealing.
virtual double GetLowerLimit() const
Definition: BCVariable.h:97
std::vector< double > modepar
mode of parameters
Definition: BCEngineMCMC.h:204
static void IntegralUpdaterMC(const std::vector< double > &sums, const int &nIterations, double &integral, double &absprecision)
Updates info about integrator.
std::vector< double > GetProposalPointSABoltzmann(const std::vector< double > &x, int t) const
Generates a new state in a neighbourhood around x that is to be accepted or rejected by the Simulated...
LogLevel
Enumerator for the amount of details to put into the log file.
Definition: BCLog.h:59
std::vector< double > fSAx
Current simulated annealing parameter point.
Definition: BCIntegrate.h:862
virtual std::vector< double > GetFixedValues(bool include_unfixed=true) const
Get vector of fixed values.
virtual bool IsWithinLimits(const std::vector< double > &x) const
Check if vector of values is within limits.
void SetCubaIntegrationMethod(BCCubaMethod type)
Set Cuba integration method.
number of available integration methods
Definition: BCIntegrate.h:171
virtual void PrintBestFitSummary() const
Print best fit to log.
Print all details of operation.
Definition: BCLog.h:61
unsigned GetNObservables() const
Definition: BCEngineMCMC.h:711
virtual void MCMCUserInitialize()
User hook called from MCMCInitialize().
virtual bool IsAtFixedValues(const std::vector< double > &x) const
Check if fixed parameters in vector of values are at fixed values.
virtual unsigned int GetNFreeParameters() const
virtual double GetLogMaximum() const
Definition: BCEngineMCMC.h:729
double GetRelativePrecision() const
Definition: BCIntegrate.h:316
BCOptimizationMethod
An enumerator for the mode finding algorithm.
Definition: BCIntegrate.h:153
Cauchy scheduler.
Definition: BCIntegrate.h:188
Laplace approximation.
Definition: BCIntegrate.h:169
void SetIntegrationMethod(BCIntegrate::BCIntegrationMethod method)
virtual void PrintMarginalizationSummary() const
Print marginalization to log.
std::string DumpOptimizationMethod(BCOptimizationMethod type) const
Return string with the name for a given optimization type.
std::vector< double > SAHelperGetRandomPointOnHypersphere() const
Generates a uniform distributed random point on the surface of a fNvar-dimensional Hypersphere...
double IntegrateLaplace()
Integrate using the Laplace approximation.
virtual const std::vector< double > & GetBestFitParameterErrors() const
BCCubaMethod
An enumerator for Cuba integration methods.
Definition: BCIntegrate.h:196
std::vector< double > GetProposalPointSA(const std::vector< double > &x, int t) const
Generates a new state in a neighbourhood around x that is to be accepted or rejected by the Simulated...
virtual double GetUpperLimit() const
Definition: BCVariable.h:102
BCEngineMCMC::Statistics fMCMCStatistics_AllChains
Statistics across all Markov chains.
void SetNChains(unsigned n)
Sets the number of Markov chains which are run in parallel.
Definition: BCEngineMCMC.h:775
A class representing a parameter of a model.
Definition: BCParameter.h:34
virtual double Eval(const std::vector< double > &x)=0
Evaluate the unnormalized probability at a point in parameter space.
double SAHelperSinusToNIntegral(int dim, double theta) const
Returns the Integral of sin^dim from 0 to theta.
double GetRandomPoint(std::vector< double > &x)
Fills a vector of (flat) random numbers in the limits of the parameters and returns the probability a...
An engine class for Markov Chain Monte Carlo.
Definition: BCEngineMCMC.h:55
BCIntegrationMethod
An enumerator for integration algorithms.
Definition: BCIntegrate.h:164
virtual double GetFixedValue() const
Definition: BCParameter.h:86
virtual void PrintMarginalizationSummary() const
Print marginalization to log.
std::vector< std::vector< TH2 * > > fH2Marginalized
Vector of 2D marginalized distributions.
std::string DumpUsedIntegrationMethod() const
Return string with the name for the previously used integration type.
Definition: BCIntegrate.h:735
std::vector< TH1 * > fH1Marginalized
Vector of 1D marginalized distributions.
void(* tIntegralUpdater)(const std::vector< double > &, const int &, double &, double &)
A pointer for a function that updates the integral and absolute precision.
Definition: BCIntegrate.h:220
std::string DumpCurrentIntegrationMethod() const
Return string with the name for the currently set integration type.
Definition: BCIntegrate.h:729
BCIntegrate::BCOptimizationMethod GetOptimizationMethod() const
Definition: BCIntegrate.h:264
double Integrate()
Perform the integration.
double fSATmin
Minimal/Threshold temperature for Simulated Annealing.
Definition: BCIntegrate.h:846
virtual double SATemperatureCustom(double t) const
Temperature annealing schedule for use with Simulated Annealing.
Integration by gridding of parameter space.
Definition: BCIntegrate.h:168
double fSATemperature
Current temperature of simulated annealing algorithm.
Definition: BCIntegrate.h:854
const std::string & GetSafeName() const
Definition: BCEngineMCMC.h:274
TRandom3 fRandom
Random number generator.
Marginalization by gridding of parameter space.
Definition: BCIntegrate.h:180
std::vector< double > stderrpar
sqrt(variance) of all parameters
Definition: BCEngineMCMC.h:197
virtual bool Fixed() const
Definition: BCParameter.h:81
virtual const std::vector< double > & GetBestFitParameters() const
BCParameterSet fParameters
Parameter settings.
virtual std::vector< double > GetProposalPointSACustom(const std::vector< double > &x, int t) const
Generates a new state in a neighbourhood around x that is to be accepted or rejected by the Simulated...
virtual std::string GetBestFitSummary(unsigned i) const
Get string summarizing best fit for single variable.
virtual std::vector< double > GetRangeCenters() const
Get range centers, leaving fixed parameters at fixed values.
BCIntegrate & operator=(const BCIntegrate &)
Copy-assignment operator.
void GetRandomVectorInParameterSpace(std::vector< double > &x) const
Fills a vector of random numbers x[i] between fMin[i] and fMax[i] into a vector.
double SATemperatureBoltzmann(double t) const
Temperature annealing schedule for use with Simulated Annealing.
TH1 * GetSlice(std::vector< unsigned > indices, unsigned &nIterations, double &log_max_val, const std::vector< double > parameters=std::vector< double >(0), int nbins=0, bool normalize=true)
Returns a one-dimensional slice of the pdf at the point and along a specific direction.
void(BCIntegrate::* tRandomizer)(std::vector< double > &) const
A pointer for a function that chooses a next random point.
Definition: BCIntegrate.h:212
virtual const std::string & GetName() const
Definition: BCVariable.h:72
double SATemperatureCauchy(double t) const
Temperature annealing schedule for use with Simulated Annealing.
No optimization method set.
Definition: BCIntegrate.h:154
No integration method set.
Definition: BCIntegrate.h:165
double GetAbsolutePrecision() const
Definition: BCIntegrate.h:321
virtual bool ApplyFixedValues(std::vector< double > &x) const
Change values to fixed values for fixed parameters.
std::string DumpCurrentMarginalizationMethod() const
Return string with the name for the currently set marginalization type.
Definition: BCIntegrate.h:747
unsigned GetNVariables() const
Definition: BCEngineMCMC.h:613
void LogOutputAtIntegrationStatusUpdate(BCIntegrationMethod type, double integral, double absprecision, int nIterations)
Helper method to output integration status.
double fSAT0
Starting temperature for Simulated Annealing.
Definition: BCIntegrate.h:842
virtual double GetRangeWidth() const
Returns the range width of the variable values.
Definition: BCVariable.h:109
Boltzman scheduler.
Definition: BCIntegrate.h:189
Sample mean Monte Carlo.
Definition: BCIntegrate.h:179
Metropolis Hastings.
Definition: BCIntegrate.h:178
int fSANIterations
Number of iterations for simualted annealing.
Definition: BCIntegrate.h:850
static BCLog::LogLevel GetLogLevelScreen()
Returns the minimum log level for screen output.
Definition: BCLog.h:88
void LogOutputAtStartOfIntegration(BCIntegrationMethod type, BCCubaMethod cubatype)
Helper method to output at beginning of integration.
bool CheckMarginalizationIndices(TH1 *hist, const std::vector< unsigned > &index)
Check that indices of parameters to marginalize w/r/t are correct.
ROOT&#39;s Minuit.
Definition: BCIntegrate.h:157
unsigned GetNParameters() const
Definition: BCEngineMCMC.h:656
virtual void ResetResults()
Reset all information on the best-fit parameters.
BCVariable & GetVariable(unsigned index)
Definition: BCEngineMCMC.h:600
BCParameterSet & GetParameters()
Definition: BCEngineMCMC.h:618
BCMarginalizationMethod
An enumerator for marginalization algorithms.
Definition: BCIntegrate.h:176
number of available CUBA methods
Definition: BCIntegrate.h:202
unsigned UpdateFrequency(unsigned N) const
return appropriate update interval
virtual const std::vector< double > & GetBestFitParameters() const
unsigned GetNFreeParameters() const
Definition: BCEngineMCMC.h:668
void SetOptimizationMethod(BCIntegrate::BCOptimizationMethod method)
Definition: BCIntegrate.h:456
bool fFlagMarginalized
flag indicating if the model was marginalized
Definition: BCIntegrate.h:878
int GetNIterationsMax() const
Definition: BCIntegrate.h:301