MINT2
HyperBinningMaker.cpp
Go to the documentation of this file.
2 
3 #include "Mint/HyperHistogram.h"
4 
8  _minimumEdgeLength(0),
9  _drawAlgorithm (false),
10  _iterationNum (0 ),
11  _names( 0 ),
12  _func( 0 ),
13  _snapToGrid(false),
14  _gridMultiplier( 0 )
15 {
16 
17 }
18 
23  _hyperCuboids (1, binningRange),
24  _linkedBins (1, std::vector<int>(0,0) ),
25  _hyperPointSets (1, filterHyperPointSet( data, binningRange, true ) ),
26  _shadowHyperPointSets (1, HyperPointSet( binningRange.getDimension() ) ),
27  _status (1, VolumeStatus::CONTINUE ),
28  _dimSpecificStatus (1, std::vector<int>( binningRange.getDimension(), VolumeStatus::CONTINUE ) ),
29  _shadowAdded (false),
30  _useEventWeights (false),
31  _minimumBinContent (15),
32  _shadowMinimumBinContent(15),
33  _minimumEdgeLength ( HyperPoint(binningRange.getDimension(), 0.1) ),
34  _random (new TRandom3(0)),
35  _drawAlgorithm (false),
36  _iterationNum (0 ),
37  _names( binningRange.getDimension() ),
38  _func (0),
39  _snapToGrid(false),
40  _gridMultiplier( HyperPoint(binningRange.getDimension(), 1) )
41 
42 {
43  for (int i = 0; i < binningRange.getDimension(); i++) _binningDimensions.push_back(i);
44  WELCOME_LOG << "Good day from the HyperBinningMaker() Constructor"<<std::endl;
45 
46 }
47 
48 
52 
53  if (_hyperPointSets.size() != 1) {
54  ERROR_LOG << "You can only call the updateFromExistingHyperBinning if the HyperBinningMaker has" << std::endl;
55  ERROR_LOG << "a single HyperVolume";
56  }
57  else{
58  INFO_LOG << "Congratulations, you've taken the bold step of calling the updateFromExistingHyperBinning function" << std::endl;
59  }
60 
61  HyperPointSet points = _hyperPointSets .at(0);
62  HyperPointSet shadPoints = _shadowHyperPointSets.at(0);
63 
64  _hyperCuboids .clear();
65  _linkedBins .clear();
66  _status .clear();
67  _dimSpecificStatus .clear();
68 
69 
70  int nvols = binning.getNumHyperVolumes();
71 
72  for (int i = 0; i < nvols; i++){
73  _hyperCuboids.push_back( binning.getHyperVolume(i).at(0) );
74  _linkedBins .push_back( binning.getLinkedHyperVolumes(i) );
75 
76  if ( _linkedBins.at(i).size() == 0 ){
77  _status .push_back( VolumeStatus::CONTINUE );
78  _dimSpecificStatus.push_back( std::vector<int>( binning.getDimension(), VolumeStatus::CONTINUE ) );
79  }
80  else {
81  _status .push_back( VolumeStatus::DONE );
82  _dimSpecificStatus.push_back( std::vector<int>( binning.getDimension(), VolumeStatus::DONE ) );
83  }
84 
85  }
86 
87  _hyperPointSets.clear();
88  _hyperPointSets.resize(nvols, HyperPointSet(binning.getDimension()) );
89 
90  std::vector<int> binNums = binning.getBinNum(points);
91 
92  for (unsigned i = 0; i < points.size(); i++){
93  int binNum = binNums.at(i);
94  if (binNum == -1) continue;
95  int volNum = binning.getHyperVolumeNumber( binNum );
96  _hyperPointSets.at(volNum).push_back( points.at(i) );
97  }
98 
99  _shadowHyperPointSets.clear();
100  _shadowHyperPointSets.resize(nvols, HyperPointSet(binning.getDimension()) );
101 
102 
103  std::vector<int> shadBinNums = binning.getBinNum(shadPoints);
104 
105  for (unsigned i = 0; i < shadPoints.size(); i++){
106  int binNum = shadBinNums.at(i);
107  if (binNum == -1) continue;
108  int volNum = binning.getHyperVolumeNumber( binNum );
109  _hyperPointSets.at(volNum).push_back( shadPoints.at(i) );
110  }
111 
112 
113 }
114 
115 
116 
117 
122  if (_hyperCuboids.size() != 1) ERROR_LOG << "You have to add the shadow set before you make the binning"<<std::endl;
123  else{
124  _shadowHyperPointSets.at(0) = filterHyperPointSet(data, _hyperCuboids.at(0), true);
125  _shadowAdded = true;
126  }
127 }
128 
136 HyperCuboid HyperBinningMaker::splitAbovePoint(int dim, double splitPoint, const HyperCuboid& original, bool noSnapToGrid) const{
137 
138  HyperPoint lowCorner ( original.getLowCorner () );
139  HyperPoint highCorner ( original.getHighCorner() );
140 
141  double splitCoord = lowCorner.at(dim) + (highCorner.at(dim) - lowCorner.at(dim))*splitPoint;
142  if ( _snapToGrid == true && noSnapToGrid == false ) {
143  if ( snapToGrid(original, dim, splitCoord) == false ){
144  return HyperCuboid(0);
145  }
146  }
147 
148  HyperPoint newLowCorner( lowCorner );
149  newLowCorner.at(dim) = splitCoord;
150 
151  HyperCuboid temp(newLowCorner, highCorner);
152  return temp;
153 
154 }
155 
163 HyperCuboid HyperBinningMaker::splitBelowPoint(int dim, double splitPoint, const HyperCuboid& original, bool noSnapToGrid) const{
164 
165  HyperPoint lowCorner ( original.getLowCorner () );
166  HyperPoint highCorner ( original.getHighCorner() );
167 
168  double splitCoord = lowCorner.at(dim) + (highCorner.at(dim) - lowCorner.at(dim))*splitPoint;
169  if ( _snapToGrid == true && noSnapToGrid == false ) {
170  if ( snapToGrid(original, dim, splitCoord) == false ){
171  return HyperCuboid(0);
172  }
173  }
174 
175  HyperPoint newHighCorner( highCorner );
176  newHighCorner.at(dim) = splitCoord;
177 
178  HyperCuboid temp(lowCorner, newHighCorner);
179  return temp;
180 
181 }
182 
185 HyperPointSet HyperBinningMaker::filterHyperPointSet(const HyperPointSet& hyperPointSet, const HyperCuboid& hyperCuboid, bool print) const{
186 
187  if (print == true && s_printBinning == true) INFO_LOG << "Before filtering there are " << hyperPointSet.size() << " events" << std::endl;
188 
189  HyperPointSet temp(hyperPointSet.getDimension());
190  for(unsigned int i = 0; i < hyperPointSet.size(); i++){
191  if( hyperCuboid.inVolume(hyperPointSet.at(i)) ) temp.push_back(hyperPointSet.at(i));
192  }
193 
194  if (print == true && s_printBinning == true) INFO_LOG << "After filtering there are " << temp.size() << " events" << std::endl;
195 
196  return temp;
197 
198 }
199 
203 
204  delete _random;
205  _random = new TRandom3(seed);
206 
207 }
208 
214  _snapToGrid = val;
215 }
216 
220  _gridMultiplier = multipliers;
221 }
222 
225 void HyperBinningMaker::setGridMultiplier(double multiplier){
226  HyperPoint point( _hyperCuboids.at(0).getDimension(), multiplier );
227  setGridMultiplier( point );
228 }
229 
232 double HyperBinningMaker::getSumOfWeights(const HyperPointSet& hyperPointSet) const{
233 
234  if (_useEventWeights == true) return hyperPointSet.getSumW();
235  return hyperPointSet.size();
236 
237 }
238 
239 
242 double HyperBinningMaker::getWeight(const HyperPoint& hyperPoint) const{
243 
244  if (_useEventWeights == true) return hyperPoint.getWeight();
245  return 1.0;
246 
247 }
248 
249 
252 void HyperBinningMaker::addBin(const HyperCuboid& hyperCuboid, const HyperPointSet& hyperPointSet, const HyperPointSet& shadowHyperPointSet, int status){
253  _hyperPointSets.push_back(hyperPointSet);
254  _shadowHyperPointSets.push_back(shadowHyperPointSet);
255  _hyperCuboids .push_back(hyperCuboid);
256  _status .push_back(status);
257  _linkedBins .push_back( std::vector<int>(0,0) );
258 
259  std::vector<int> dimStatus( hyperCuboid.getDimension(), status);
260  _dimSpecificStatus.push_back(dimStatus);
261 
262 }
263 
267 
268  bool isBinningDim = false;
269  for ( unsigned i = 0; i < _binningDimensions.size(); i++ ) {
270  if (_binningDimensions.at(i) == dimension) {
271  isBinningDim = true;
272  break;
273  }
274  }
275  if (isBinningDim == false) return false;
276  return true;
277 
278 }
279 
289 
290  HyperCuboid& chosenHyperCuboid = _hyperCuboids .at(volumeNumber);
291 
292  int dim = _hyperCuboids.at(0).getDimension();
293 
294  bool allDone = true;
295 
296  for (int i = 0; i < dim; i++){
297  double low = chosenHyperCuboid.getLowCorner ().at(i);
298  double high = chosenHyperCuboid.getHighCorner().at(i);
299  double width = high - low;
300  double minwidth = _minimumEdgeLength.at(i);
301 
302  if ( width < minwidth*2.0 || isValidBinningDimension(i) == false ) {
304  }
305  else{
306  allDone = false;
307  }
308 
309  }
310 
311  if (allDone == true){
313  }
314 
315 }
316 
322 
323  int dim = _hyperCuboids.at(0).getDimension();
324 
325  bool allDone = true;
326 
327  for (int i = 0; i < dim; i++){
328 
329  int status = getDimensionSpecificVolumeStatus(volumeNumber, i);
330 
331  if (status != VolumeStatus::DONE){
332  allDone = false;
333  break;
334  }
335 
336  }
337 
338  if (allDone == true){
340  }
341 
342 }
343 
365 int HyperBinningMaker::split(int volumeNumber, int dimension, double splitPoint){
366 
367  //check if we're allowed to bin in this dimension
368 
369  VERBOSE_LOG << "Calling the HyperBinningMaker::split function that gets used by all the algorithms" << std::endl;
370 
371 
372  if (isValidBinningDimension(dimension) == false) {
373  VERBOSE_LOG << "This isn't a valid binning dimension, so not splitting" << std::endl;
374  return 0;
375  }
376 
377  //get the HyperPointSet, ShadowHyperPointSet, and HyperCuboid associated to
378  //this volume number
379  HyperPointSet& chosenHyperPointSet = _hyperPointSets .at(volumeNumber);
380  HyperPointSet& chosenShadowHyperPointSet = _shadowHyperPointSets.at(volumeNumber);
381  HyperCuboid& chosenHyperCuboid = _hyperCuboids .at(volumeNumber);
382 
383  //create the two HyperCuboid's that are been split
384  HyperCuboid cuboid1 = splitBelowPoint(dimension, splitPoint, chosenHyperCuboid);
385  HyperCuboid cuboid2 = splitAbovePoint(dimension, splitPoint, chosenHyperCuboid);
386 
387  if (cuboid1.getDimension() == 0 || cuboid2.getDimension() == 0){
388  VERBOSE_LOG << "It looks like the snap to grid option means that this bin cannot be split. Returning 0."<<std::endl;
389  return 0;
390  }
391 
392  //calcuate the edge length of each HyperCuboid in the binning dimension
393  double edgeLength1 = cuboid1.getHighCorner().at(dimension) - cuboid1.getLowCorner().at(dimension);
394  double edgeLength2 = cuboid2.getHighCorner().at(dimension) - cuboid2.getLowCorner().at(dimension);
395  double minEdgeLength = _minimumEdgeLength.at(dimension);
396 
397  //first check if the new bins are too small - if they are, return 0
398  if (edgeLength1 < minEdgeLength || edgeLength2 < minEdgeLength){
399  VERBOSE_LOG << "Tired to split bin but one of the resulting bins is too small... hopefully spliting in another dim will help."<<std::endl;
400  return 0;
401  }
402 
403  //find the HyperPoint's that fall into each of the new HyperCuboid's
404  HyperPointSet hyperPointSet1 = filterHyperPointSet(chosenHyperPointSet, cuboid1);
405  HyperPointSet hyperPointSet2 = filterHyperPointSet(chosenHyperPointSet, cuboid2);
406 
407  //find the shadow HyperPoint's that fall into each of the new HyperCuboid's
408  HyperPointSet shadowHyperPointSet1 = filterHyperPointSet(chosenShadowHyperPointSet, cuboid1);
409  HyperPointSet shadowHyperPointSet2 = filterHyperPointSet(chosenShadowHyperPointSet, cuboid2);
410 
411  double evts1 = getSumOfWeights(hyperPointSet1 );
412  double evts2 = getSumOfWeights(hyperPointSet2 );
413  double shadowEvts1 = getSumOfWeights(shadowHyperPointSet1);
414  double shadowEvts2 = getSumOfWeights(shadowHyperPointSet2);
415 
416  //check if there are enough HyperPoint's in the split bins - if not, return 0
417  if ( evts1 < _minimumBinContent || evts2 < _minimumBinContent){
418  VERBOSE_LOG << "Tired to split bin but one half has too little events... hopefully spliting in another dim will help."<<std::endl;
419  VERBOSE_LOG << "It contained " << chosenHyperPointSet.size() << " events, and was split into " << hyperPointSet1.size() << " and " << hyperPointSet2.size()<<std::endl;
420  return 0;
421  }
422 
423  //check if there are enough shadow HyperPoint's in the split bins - if not, return 0
424  if (_shadowAdded == true){
425  if ( shadowEvts1 < _shadowMinimumBinContent || shadowEvts2 < _shadowMinimumBinContent){
426  VERBOSE_LOG << "Tired to split bin but one half has too little events... hopefully spliting in another dim will help."<<std::endl;
427  VERBOSE_LOG << "It contained " << chosenHyperPointSet.size() << " events, and was split into " << hyperPointSet1.size() << " and " << hyperPointSet2.size()<<std::endl;
428  return 0;
429  }
430  }
431 
432  //There is an option to pass a function - if so check that the new
433  //bins pass the 'function criteria' (in passFunctionCriteria).
434  //Default behaviour returns true, but some Algs may override this
435  if (_func != 0){
436  if ( passFunctionCriteria(cuboid1, cuboid2) == 0 ) {
437  VERBOSE_LOG << "I tired to split this bin but the Function criteria failed." <<std::endl;
438  return 0;
439  }
440  }
441 
442  // Add bins to the HyperVolume vector
443  // if the bin content is less than double the _minimumBinContent,
444  // there is no way to split it any further. In this case, mark
445  // the bin as DONE. In not mark the bin as CONTINUE
446 
447  if ( evts1 >= 2.0*_minimumBinContent && (shadowEvts1 >= 2.0*_shadowMinimumBinContent || _shadowAdded == false) ){
448  VERBOSE_LOG << "Adding HyperVolume 1 with status 1";
449  addBin(cuboid1, hyperPointSet1, shadowHyperPointSet1, VolumeStatus::CONTINUE);
450  }
451  else{
452  VERBOSE_LOG << "Adding HyperVolume 1 with status 0"<<std::endl;
453  addBin(cuboid1, hyperPointSet1, shadowHyperPointSet1, VolumeStatus::DONE );
454  }
455 
456  if ( evts2 >= 2.0*_minimumBinContent && (shadowEvts2 >= 2.0*_shadowMinimumBinContent || _shadowAdded == false) ){
457  VERBOSE_LOG << "Adding HyperVolume 2 with status 1"<<std::endl;
458  addBin(cuboid2, hyperPointSet2, shadowHyperPointSet2, VolumeStatus::CONTINUE);
459  }
460  else{
461  VERBOSE_LOG << "Adding HyperVolume 2 with status 0"<<std::endl;
462  addBin(cuboid2, hyperPointSet2, shadowHyperPointSet2, VolumeStatus::DONE );
463  }
464 
465  //Link the old bin to the new bins
466 
467  int newVolumeNum1 = _hyperPointSets.size() - 2;
468  int newVolumeNum2 = _hyperPointSets.size() - 1;
469 
470  VERBOSE_LOG << "Linking old bin to new bins"<<std::endl;
471  _linkedBins.at( volumeNumber ).push_back( newVolumeNum1 );
472  _linkedBins.at( volumeNumber ).push_back( newVolumeNum2 );
473 
474  //clear the HyperPoints and Shadow HyperPoints associated
475  //to the original volume.
476 
477  int dim = _hyperPointSets.at(volumeNumber).getDimension();
478 
479  VERBOSE_LOG << "Removing data associated with old bin..." << std::endl;
480  _hyperPointSets .at(volumeNumber) = HyperPointSet(dim);
481  _shadowHyperPointSets.at(volumeNumber) = HyperPointSet(dim);
482  VERBOSE_LOG << "and setting it's status to 0" << std::endl;
483 
484  //finally, set the status of the original volume to DONE
485 
486  _status.at(volumeNumber) = VolumeStatus::DONE;
487 
488  setDimSpecStatusFromMinBinWidths(newVolumeNum1);
489  setDimSpecStatusFromMinBinWidths(newVolumeNum2);
490 
491  return 1;
492 
493 
494  //if (_verbose){
495  // std::stringstream ss;
496  // chosenHyperCuboid.print(ss, 0);
497  // VERBOSE_LOG << "Original Cuboid: " << ss.str();
498  // std::stringstream ss2;
499  // cuboid1.print(ss2, 0);
500  // VERBOSE_LOG << "Split Cuboid 1: " << ss2.str();
501  // std::stringstream ss3;
502  // cuboid2.print(ss3, 0);
503  // VERBOSE_LOG << "Split Cuboid 2: " << ss3.str();
504  // VERBOSE_LOG << "HyperCuboid 1 contains " << getSumOfWeights( hyperPointSet1 ) << "events";
505  // VERBOSE_LOG << "HyperCuboid 2 contains " << getSumOfWeights( hyperPointSet2 ) << "events";
506  //}
507 
508 }
509 
512 bool HyperBinningMaker::snapToGrid(const HyperCuboid& cuboid, int dimension, double& splitCoord) const{
513 
514  double absMax = _hyperCuboids.at(0).getHighCorner ().at(dimension);
515  double absMin = _hyperCuboids.at(0).getLowCorner ().at(dimension);
516 
517  double minEdgeLength = _minimumEdgeLength.at(dimension);
518 
519  int gridMultiplier = floor( _gridMultiplier.at(dimension) );
520  int nbins = floor((absMax - absMin)/minEdgeLength)*gridMultiplier;
521 
522  double gridWidth = (absMax - absMin)/double(nbins);
523 
524 
525  int binNumLow = floor( (splitCoord - absMin)/gridWidth );
526  int binNumHigh = ceil ( (splitCoord - absMin)/gridWidth );
527 
528  double lowCoord = absMin + double(binNumLow )*gridWidth;
529  double highCoord = absMin + double(binNumHigh)*gridWidth;
530 
531 
532  double closestGridPoint = 0.0;
533  double furthestGridPoint = 0.0;
534 
535 
536  if ( fabs(lowCoord - splitCoord) <= fabs(highCoord - splitCoord) ){
537  closestGridPoint = lowCoord ;
538  furthestGridPoint = highCoord;
539  }
540  else{
541  closestGridPoint = highCoord;
542  furthestGridPoint = lowCoord ;
543  }
544 
545  double min = cuboid.getLowCorner ().at(dimension);
546  double max = cuboid.getHighCorner().at(dimension);
547 
548  //std::cout << min << " " << lowCoord << " " << splitCoord << " " << highCoord << " " << max << std::endl;
549 
550 
551  if ( closestGridPoint - min >= minEdgeLength && max - closestGridPoint >= minEdgeLength ){
552  splitCoord = closestGridPoint;
553  return true;
554  }
555  if ( furthestGridPoint - min >= minEdgeLength && max - furthestGridPoint >= minEdgeLength ){
556  splitCoord = furthestGridPoint;
557  return true;
558  }
559 
560  VERBOSE_LOG << "I failed to snap to grid - very sad" << std::endl;
561 
562  splitCoord = closestGridPoint;
563  return false;
564 
565 }
566 
567 
568 
569 
574 
575  cuboid1.getLowCorner();
576  cuboid2.getHighCorner();
577 
578  return true;
579 }
580 
581 
582 
586 double HyperBinningMaker::neg2LLH(int binNumber, int dimension, double splitPoint, bool useConstraints){
587 
588  double binLength = _hyperCuboids.at(binNumber).getHighCorner().at(dimension) - _hyperCuboids.at(binNumber).getLowCorner().at(dimension);
589 
590  double total = getSumOfWeights( _hyperPointSets.at(binNumber) );
591  double nBelow = countEventsBelowSplitPoint(binNumber, dimension, splitPoint);
592  double nAbove = total - nBelow;
593 
594  if (useConstraints == true){
595  if (nBelow < _minimumBinContent || nAbove < _minimumBinContent) return nullNeg2LLH(binNumber);
596  if (binLength*splitPoint < _minimumEdgeLength.at(dimension) || binLength*(1.0 - splitPoint) < _minimumEdgeLength.at(dimension)) return nullNeg2LLH(binNumber);
597  }
598 
599  if (_shadowAdded == false){
600 
601  double fracBelow = nBelow/total;
602  double fracAbove = nAbove/total;
603 
604  double PDFabove = fracAbove/(1.0 - splitPoint);
605  double PDFbelow = fracBelow/splitPoint;
606 
607  if (PDFabove == 0.0) PDFabove = 1e-16;
608  if (PDFbelow == 0.0) PDFbelow = 1e-16;
609 
610  return -2.0*(nAbove*log(PDFabove) + nBelow*log(PDFbelow));
611  }
612 
613  double shadowTotal = getSumOfWeights( _shadowHyperPointSets.at(binNumber) );
614  double shadowNBelow = countShadowEventsBelowSplitPoint(binNumber, dimension, splitPoint);
615  double shadowNAbove = shadowTotal - shadowNBelow;
616 
617  double allTotal = shadowTotal + total;
618 
619  double PDFNumeratorAbove = (nAbove / allTotal) / (1.0 -splitPoint);
620  double PDFDenominatorAbove = (shadowNAbove / allTotal) / (1.0 -splitPoint);
621  double PDFNumeratorBelow = (nBelow / allTotal) / (splitPoint);
622  double PDFDenominatorBelow = (shadowNBelow / allTotal) / (splitPoint);
623 
624  if (PDFNumeratorAbove <= 0.0) PDFNumeratorAbove = 1e-16;
625  if (PDFDenominatorAbove <= 0.0) PDFDenominatorAbove = 1e-16;
626  if (PDFNumeratorBelow <= 0.0) PDFNumeratorBelow = 1e-16;
627  if (PDFDenominatorBelow <= 0.0) PDFDenominatorBelow = 1e-16;
628 
629  return -2.0*( shadowNBelow*log(PDFDenominatorBelow) + shadowNAbove*log(PDFDenominatorAbove) + nBelow*log(PDFNumeratorBelow) + nAbove*log(PDFNumeratorAbove) );
630 
631 }
632 
633 
634 
638 double HyperBinningMaker::nullNeg2LLH(int binNumber){
639 
640  if (_shadowAdded == false) return 0.0;
641 
642  double num = getSumOfWeights( _hyperPointSets.at(binNumber) );
643  double sha = getSumOfWeights( _shadowHyperPointSets.at(binNumber) );
644  double tot = num + sha;
645 
646  double probNum = num/tot;
647  double probDen = sha/tot;
648 
649  return -2.0*(num*log(probNum) + sha*log(probDen));
650 
651 }
652 
656 TH1D* HyperBinningMaker::scanSig(int binNumber, int dimension, int nbins, bool useConstraints){
657 
658  TH1D* scan = new TH1D("scan", "scan", nbins, 0.0, 1.0);
659  double nullHypothesis = nullNeg2LLH(binNumber);
660 
661  for (int i = 1; i < nbins; i++){
662  double neg2LLHval = neg2LLH(binNumber, dimension, scan->GetXaxis()->GetBinCenter(i), useConstraints );
663  neg2LLHval = nullHypothesis - neg2LLHval;
664  if (neg2LLHval < 0.0) neg2LLHval = 0.0;
665  double sig = sqrt( neg2LLHval );
666  scan->SetBinContent( i, sig );
667  }
668 
669  return scan;
670 
671 }
672 
676 void HyperBinningMaker::getSplitToMinNeg2LLH(double& split, double& sig, int binNumber, int dimension, bool useConstraints){
677 
678  bool plot = false;
679 
680  int nBins = 25;
681 
682  //std::cout << "OK here?" << std::endl;
683 
684  TH1D* splitHist = scanSig(binNumber, dimension, nBins, useConstraints);
685 
686  int splitBin = splitHist->GetMaximumBin();
687 
688  split = splitHist->GetXaxis()->GetBinCenter(splitBin);
689  sig = splitHist->GetBinContent(splitBin);
690 
691  //std::cout << "OK here?" << sig << std::endl;
692 
693  if (plot == true){
694  RootPlotter1D plotter(splitHist);
695  TString name = "splitHist";
696  name += binNumber;
697  name += "_";
698  name += dimension;
699  plotter.plot(name);
700  INFO_LOG << "Min split point = " << split << " in dimension " << dimension<<std::endl;
701  }
702 
703  delete splitHist;
704 
705 }
706 
710 void HyperBinningMaker::getDimWithLargestSplitSignificance(int& dim, double& split, int binNumber, bool useConstraints){
711 
712  int nDim = _binningDimensions.size();
713 
714  double bigestSig = -2e40;
715 
716  for (int i = 0; i < nDim; i++){
717 
718  double tmpSplit = 0.0; double tmpSig = 0.0;
719  getSplitToMinNeg2LLH(tmpSplit, tmpSig, binNumber, _binningDimensions.at(i), useConstraints);
720 
721  if ( tmpSig > bigestSig ) {
722  bigestSig = tmpSig;
723  dim = _binningDimensions.at(i);
724  split = tmpSplit;
725  }
726 
727  }
728 
729 }
730 
735 
736  int dim = -1;
737  double splitPoint = -1.0;
738 
739  getDimWithLargestSplitSignificance(dim, splitPoint, binNumber, true);
740 
741  //INFO_LOG << "likelihoodSplit(" << binNumber << ") gives dim " << dim << " and split point " << splitPoint;
742 
743  splitPoint = _random->Gaus(splitPoint, 0.2); //I think this is needed to make the binning unbiased
744  if (splitPoint <= 0.0 || splitPoint >= 1.0) return likelihoodSplit(binNumber);
745 
746  if ( split(binNumber, dim, splitPoint) == 1) return 1;
747  if ( smartSplit(binNumber, dim, 0.5) == 1) return 1;
748 
749  int ndim = _binningDimensions.size();
750  for (int i = 0; i < ndim; i++){
751  if ( smartSplit(binNumber, _binningDimensions.at(i), 0.5) == 1 ) return 1;
752  }
753 
754  return 0;
755 
756 }
757 
762 
763  int dim = -1;
764  double splitPoint = -1.0;
765 
766  getDimWithLargestSplitSignificance(dim, splitPoint, binNumber, false);
767 
768  if ( smartSplit(binNumber, dim, 0.5) == 1) return 1;
769 
770  int ndim = _binningDimensions.size();
771  for (int i = 0; i < ndim; i++){
772  if ( smartSplit(binNumber, _binningDimensions.at(i), 0.5) == 1 ) return 1;
773  }
774 
775  return 0;
776 
777 }
778 
783 
784  int initialSize = _hyperCuboids.size();
785  int nSplits = 0;
786 
787  for (int i = 0; i < initialSize; i++){
788  if (_status.at(i) == 1) {
789  nSplits += likelihoodSplit(i);
790  }
791  }
792 
793  return nSplits;
794 }
795 
800 
801  int initialSize = _hyperCuboids.size();
802  int nSplits = 0;
803 
804  for (int i = 0; i < initialSize; i++){
805  if (_status.at(i) == 1) {
807  nSplits++;
808  }
809  }
810 
811  return nSplits;
812 }
813 
814 
820 double HyperBinningMaker::countEventsBelowSplitPoint(int binNumber, int dimension, double splitPoint ) const{
821 
822  bool forceNoSnapToGrid = true;
823 
824  const HyperCuboid& cuboid = _hyperCuboids.at(binNumber);
825  HyperCuboid newCuboid = splitBelowPoint(dimension, splitPoint, cuboid, forceNoSnapToGrid);
826 
827  const HyperPointSet& chosenHyperPointSet = _hyperPointSets.at(binNumber);
828 
829  double events = countEventsInHyperCuboid(chosenHyperPointSet, newCuboid);
830 
831  return events;
832 }
833 
839 double HyperBinningMaker::countShadowEventsBelowSplitPoint(int binNumber, int dimension, double splitPoint) const{
840 
841  bool forceNoSnapToGrid = true;
842 
843  const HyperCuboid& cuboid = _hyperCuboids.at(binNumber);
844  HyperCuboid newCuboid = splitBelowPoint(dimension, splitPoint, cuboid, forceNoSnapToGrid);
845 
846  const HyperPointSet& chosenHyperPointSet = _shadowHyperPointSets.at(binNumber);
847 
848  double events = countEventsInHyperCuboid(chosenHyperPointSet, newCuboid);
849 
850  return events;
851 }
852 
855 double HyperBinningMaker::countEventsInHyperCuboid(const HyperPointSet& hyperPointSet, const HyperCuboid& hyperCuboid) const{
856 
857  double count = 0.0;
858  for(unsigned int i = 0; i < hyperPointSet.size(); i++){
859  if( hyperCuboid.inVolume(hyperPointSet.at(i)) ) {
860  count = count + getWeight( hyperPointSet.at(i) ) ;
861  }
862  }
863  return count;
864 
865 }
866 
869 double HyperBinningMaker::findSmartSplitPoint(int binNumber, int dimension, double dataFraction) const{
870 
871  double splitPoint = 0.5;
872  double shift = 0.25;
873 
874  double dataBefore = getSumOfWeights( _hyperPointSets.at(binNumber) );
875 
876  while (shift > 0.001){
877  double dataNow = countEventsBelowSplitPoint(binNumber, dimension, splitPoint);
878  double dataFrac = dataNow/dataBefore;
879 
880  if (dataFrac < dataFraction) splitPoint += shift;
881  else if (dataFrac > dataFraction) splitPoint -= shift;
882  else break;
883 
884  shift = shift*0.5;
885  }
886 
887  return splitPoint;
888 }
889 
893 double HyperBinningMaker::findSmartSplitPointInt(int binNumber, int dimension, double dataFraction) const{
894 
895  const HyperCuboid& cuboid = _hyperCuboids.at(binNumber);
896 
897  HyperPoint lowCorner ( cuboid.getLowCorner () );
898  HyperPoint highCorner ( cuboid.getHighCorner() );
899 
900  double lowEdge = lowCorner .at(dimension);
901  double highEdge = highCorner.at(dimension);
902 
903  int lowInt = ceil (lowEdge );
904  int highInt = floor(highEdge);
905 
906  if (lowInt == highInt) return 0.0; // everything is an integer - so if this is true, there is only one integer between the limits already
907 
908  VERBOSE_LOG << "------------------> bin num " << binNumber << ", dimension " << dimension << std::endl;
909  VERBOSE_LOG << "------------------> [ " << lowEdge << ", " << highEdge << "]" << std::endl;
910  VERBOSE_LOG << "------------------> [ " << lowInt << ", " << highInt << "]" << std::endl;
911 
912  double dataBefore = getSumOfWeights( _hyperPointSets.at(binNumber) );
913 
914  double splitPoint = 0.0;
915 
916  for (int i = lowInt; i < highInt; i++){
917 
918  double val = double(i) + 0.5;
919  splitPoint = (val - lowEdge)/(highEdge - lowEdge);
920 
921  double dataNow = countEventsBelowSplitPoint(binNumber, dimension, splitPoint);
922  double dataFrac = dataNow/dataBefore;
923 
924  if (dataFrac > dataFraction) break;
925 
926  }
927 
928  VERBOSE_LOG << "------------------> split point " << splitPoint << std::endl;
929 
930  return splitPoint;
931 }
932 
933 
936 int HyperBinningMaker::smartSplit(int binNumber, int dimension, double dataFraction){
937 
938  double splitPoint = findSmartSplitPoint(binNumber, dimension, dataFraction);
939  return split(binNumber, dimension, splitPoint);
940 
941 }
942 
943 
944 
945 
948 int HyperBinningMaker::smartMultiSplit(int binNumber, int dimension, int parts){
949 
950  int binToSplit = binNumber;
951 
952  int nSplits = 0;
953 
954  for (int i = 0; i < (parts - 1); i++){
955  double fraction = 1.0/double(parts - i);
956  double splitPoint = findSmartSplitPoint(binToSplit, dimension, fraction);
957  bool ok = split(binToSplit, dimension, splitPoint);
958  nSplits += ok;
959  if (!ok) return nSplits;
960 
961  binToSplit = _linkedBins.at(binToSplit).at(1);
962  }
963 
964  return nSplits;
965 }
966 
969 int HyperBinningMaker::smartMultiSplit(int binNumber, int dimension){
970 
971  const HyperPointSet& points = _hyperPointSets.at(binNumber);
972 
973  double nEvents = getSumOfWeights(points);
974  double ratio = nEvents/_minimumBinContent;
975 
976  if (ratio >= 0.0 && ratio < 3.0) return smartMultiSplit(binNumber, dimension, 2);
977  if (ratio >= 3.0 && ratio < 4.0) return smartMultiSplit(binNumber, dimension, 3);
978  if (ratio >= 4.0 && ratio < 5.0) return smartMultiSplit(binNumber, dimension, 2);
979  if (ratio >= 5.0 && ratio < 6.0) return smartMultiSplit(binNumber, dimension, 5);
980 
981  return smartMultiSplit(binNumber, dimension, 2);
982 
983 }
984 
985 
988 int HyperBinningMaker::smartSplitInt(int binNumber, int dimension, double dataFraction){
989 
990  double splitPoint = findSmartSplitPointInt(binNumber, dimension, dataFraction);
991  return split(binNumber, dimension, splitPoint);
992 
993 }
994 
998 int HyperBinningMaker::splitAll(int dimension, double splitPoint){
999 
1000  int initialSize = _hyperCuboids.size();
1001  int nSplits = 0;
1002 
1003  for (int i = 0; i < initialSize; i++){
1004  if (_status.at(i) == VolumeStatus::CONTINUE) {
1005  nSplits += split(i, dimension, splitPoint);
1006  }
1007  }
1008 
1009  return nSplits;
1010 }
1011 
1015 int HyperBinningMaker::smartSplitAll(int dimension, double dataFraction){
1016 
1017  int initialSize = _hyperCuboids.size();
1018  int nSplits = 0;
1019 
1020  for (int i = 0; i < initialSize; i++){
1021  if (_status.at(i) == VolumeStatus::CONTINUE) {
1022  nSplits += smartSplit(i, dimension, dataFraction);
1023  }
1024  }
1025 
1026 
1027  return nSplits;
1028 }
1029 
1034 
1035  int initialSize = _hyperCuboids.size();
1036  int nSplits = 0;
1037 
1038  for (int i = 0; i < initialSize; i++){
1039  if (_status.at(i) == VolumeStatus::CONTINUE) {
1040  nSplits += smartMultiSplit(i, dimension);
1041  }
1042  }
1043 
1044 
1045  return nSplits;
1046 }
1047 
1048 
1049 
1056 int HyperBinningMaker::smartSplitAllInt(int dimension, double dataFraction){
1057 
1058  int initialSize = _hyperCuboids.size();
1059  int nSplits = 0;
1060 
1061  for (int i = 0; i < initialSize; i++){
1062  if (_status.at(i) == 1) {
1063  nSplits += smartSplitInt(i, dimension, dataFraction);
1064  }
1065  }
1066 
1067  return nSplits;
1068 }
1069 
1075 
1076  int initialSize = _hyperCuboids.size();
1077  int nSplits = 0;
1078 
1079  int ndim = _binningDimensions.size();
1080 
1081  for (int i = 0; i < initialSize; i++){
1082  if (_status.at(i) == VolumeStatus::CONTINUE) {
1083  int dimension = floor(_random->Uniform(0, ndim));
1084  nSplits += smartSplit(i, _binningDimensions.at(dimension) , dataFraction);
1085  }
1086  }
1087 
1088  return nSplits;
1089 
1090 }
1091 
1096 
1097  int initialSize = _hyperCuboids.size();
1098  int nSplits = 0;
1099 
1100  int ndim = _binningDimensions.size();
1101 
1102  for (int i = 0; i < initialSize; i++){
1103  if (_status.at(i) == VolumeStatus::CONTINUE) {
1104  int dimension = floor(_random->Uniform(0, ndim));
1105  nSplits += split(i, _binningDimensions.at(dimension), splitPoint);
1106  }
1107  }
1108 
1109  return nSplits;
1110 
1111 }
1112 
1116  _minimumBinContent = val;
1117 }
1118 
1119 
1122  _func = fnc;
1123 }
1124 
1125 
1130 }
1131 
1135 
1136  _minimumEdgeLength = HyperPoint( _hyperCuboids.at(0).getDimension(), val );
1137 
1138 }
1139 
1143 
1144  _minimumEdgeLength = val;
1145 
1146 }
1147 
1153  int count = 0;
1154  for ( int i = 0; i < getNumHyperVolumes(); i++){
1155  if (_linkedBins.at(i).size() == 0) count++;
1156  }
1157  return count;
1158 }
1159 
1163 
1164  return _hyperCuboids.size();
1165 
1166 }
1167 
1172 int HyperBinningMaker::getNumContinueBins(int dimension) const{
1173 
1174  int size = getNumHyperVolumes();
1175  int count = 0;
1176 
1177  //std::cout << "getNumContinueBins " << dimension << std::endl;
1178 
1179  for (int i = 0; i < size; i++){
1181  if ( dimension == -1 ){
1182  count++;
1183  }
1184  else{
1186  count++;
1187  }
1188  }
1189  }
1190  }
1191 
1192  return count;
1193 }
1194 
1195 
1196 
1200 
1201  int dimension = _hyperCuboids.at(0).getDimension();
1202 
1203  HyperBinningMemRes temp;
1204 
1205  for (unsigned int i = 0; i < _hyperCuboids.size(); i++){
1206  HyperVolume hyperVolume(dimension);
1207  hyperVolume.addHyperCuboid(_hyperCuboids.at(i));
1208  temp.addHyperVolume(hyperVolume, _linkedBins.at(i));
1209  }
1210 
1211  temp.addPrimaryVolumeNumber(0);
1212 
1213  if (s_printBinning == true) INFO_LOG << "Made HyperVolumeBinning"<<std::endl;
1214 
1215  return temp;
1216 
1217 }
1218 
1219 
1223 
1225 
1226  HyperHistogram* histogram = new HyperHistogram( binning );
1227 
1228  for ( int i = 0; i < binning.getNumBins(); i++){
1229  int volumeNumber = binning.getHyperVolumeNumber(i);
1230  histogram->setBinContent(i, double( _hyperPointSets.at(volumeNumber).getSumW() ) );
1231  histogram->setBinError (i, double( sqrt(_hyperPointSets.at(volumeNumber).getSumW2() ) ) );
1232  }
1233 
1234  if (s_printBinning == true) {
1235  INFO_LOG << "Made HyperHistogram"<<std::endl;
1236  }
1237 
1238  histogram->setNames(_names);
1239 
1240  return histogram;
1241 
1242 }
1243 
1247 
1249 
1250  HyperHistogram* histogram = new HyperHistogram( binning );
1251 
1252  for ( int i = 0; i < binning.getNumBins(); i++){
1253  int volumeNumber = binning.getHyperVolumeNumber(i);
1254  histogram->setBinContent(i, double( _shadowHyperPointSets.at(volumeNumber).getSumW() ) );
1255  histogram->setBinError (i, double( sqrt(_shadowHyperPointSets.at(volumeNumber).getSumW2() ) ) );
1256  }
1257 
1258  if (s_printBinning == true) INFO_LOG << "Made HyperHistogram"<<std::endl;
1259 
1260  histogram->setNames(_names);
1261 
1262  return histogram;
1263 
1264 }
1265 
1269 
1272 
1273  numerator->divide(denominator);
1274 
1275  return numerator;
1276 
1277 }
1278 
1283 void HyperBinningMaker::drawCurrentState(TString path) const{
1284 
1286 
1287  hist->drawDensity(path);
1288 
1289 }
1290 
1291 
1296 
1297 
1298 }
1299 
1300 
1306 
1307 }
1308 
1309 
1315 
1316 
1317 
1318 }
1319 
1325 
1326  if (_drawAlgorithm){
1327 
1328  TString outputdir = _drawAlgorithmDir + "_iteration";
1329  outputdir += _iterationNum;
1330 
1331  drawCurrentState(outputdir);
1332 
1333  }
1334 
1335  _iterationNum++;
1336 
1337 }
1338 
1344  _drawAlgorithm = true;
1345  _drawAlgorithmDir = path;
1346 }
1347 
1348 
1350 
1353  delete _random;
1354 }
1355 
1356 
1357 
void addShadowHyperPointSet(const HyperPointSet &data)
virtual ~HyperBinningMaker()
destructor
void setShadowMinimumBinContent(double val)
int getNumContinueBins(int dimension=-1) const
HyperPoint _minimumEdgeLength
void getDimWithLargestSplitSignificance(int &dim, double &split, int binNumber, bool useConstraints=true)
int smartMultiSplitAll(int dimension)
#define INFO_LOG
bool snapToGrid(const HyperCuboid &cuboid, int dimension, double &splitCoord) const
HyperHistogram * getShadowHyperBinningHistogram() const
void drawDensity(TString path, TString options="")
std::vector< std::vector< int > > _linkedBins
virtual void startedIteration()
const HyperCuboid & at(int i) const
Definition: HyperVolume.h:55
static bool s_printBinning
void getSplitToMinNeg2LLH(double &split, double &sig, int binNumber, int dimension, bool useConstraints=true)
int smartSplitAllInt(int dimension, double dataFraction)
virtual HyperVolume getHyperVolume(int volumeNumber) const =0
virtual void startedAlgorithm()
void drawAfterEachIteration(TString path)
std::vector< int > _status
void setGridMultiplier(HyperPoint &multipliers)
void setBinError(int bin, double val)
#define ERROR_LOG
double findSmartSplitPointInt(int binNumber, int dimension, double dataFraction) const
HyperPoint _gridMultiplier
void setMinimumEdgeLength(double val)
virtual std::vector< int > getLinkedHyperVolumes(int volumeNumber) const =0
double countEventsBelowSplitPoint(int binNumber, int dimension, double splitPoint) const
int smartSplit(int binNumber, int dimension, double dataFraction)
bool isValidBinningDimension(int dimension)
virtual int getNumHyperVolumes() const =0
void useSnapToGrid(bool val)
void updateFromExistingHyperBinning(const HyperBinning &binning)
virtual void finishedAlgorithm()
void setBinContent(int bin, double val)
void drawCurrentState(TString path) const
void setDimSpecStatusFromMinBinWidths(int volumeNumber)
std::vector< HyperPointSet > _shadowHyperPointSets
#define VERBOSE_LOG
HyperBinningMemRes getHyperVolumeBinning() const
void addBin(const HyperCuboid &hyperCuboid, const HyperPointSet &hyperPointSet, const HyperPointSet &shadowHyperPointSet, int status)
HyperCuboid splitAbovePoint(int dim, double splitPoint, const HyperCuboid &original, bool noSnapToGrid=false) const
double nullNeg2LLH(int binNumber)
const int & getDimension() const
Definition: HyperCuboid.h:45
virtual void finishedIteration()
HyperHistogram * getHyperBinningHistogram() const
const HyperPoint & at(int i) const
HyperFunction * _func
HyperPointSet filterHyperPointSet(const HyperPointSet &hyperPointSet, const HyperCuboid &hyperCuboid, bool print=false) const
const HyperPoint & getHighCorner() const
Definition: HyperCuboid.h:89
double getSumOfWeights(const HyperPointSet &hyperPointSet) const
void setNames(HyperName names)
void updateGlobalStatusFromDimSpecific(int volumeNumber)
virtual void plot(TString plotDirectory, TString plotOptions="", TPad *pad=0, double scaleFactor=1.0)
int likelihoodSplit(int binNumber)
int splitAll(int dimension, double splitPoint)
TH1D * scanSig(int binNumber, int dimension, int nbins, bool useConstraints=true)
int smartLikelihoodSplit(int binNumber)
const int & getDimension() const
Definition: BinningBase.cpp:30
const double & at(int i) const
Definition: HyperPoint.cpp:433
const int & getDimension() const
Definition: HyperPointSet.h:40
void divide(const HistogramBase &other)
int splitAllRandomise(double splitPoint=0.5)
void setHyperFunction(HyperFunction *fnc)
Set the HyperFunction - only used by some binning Algs.
int smartSplitInt(int binNumber, int dimension, double dataFraction)
int smartMultiSplit(int binNumber, int dimension, int parts)
const HyperPoint & getLowCorner() const
Definition: HyperCuboid.h:87
unsigned int size() const
#define WELCOME_LOG
int & getGlobalVolumeStatus(int volumeNumber)
void addHyperCuboid(const HyperPoint &lowCorner, const HyperPoint &highCorner)
Definition: HyperVolume.cpp:91
virtual int getNumBins() const
void setSeed(int seed)
int & getDimensionSpecificVolumeStatus(int volumeNumber, int dimension)
int getHyperVolumeNumber(int binNumber) const
double getWeight(int i=0) const
Definition: Weights.cpp:40
int getNumHyperVolumes() const
std::vector< HyperCuboid > _hyperCuboids
double countShadowEventsBelowSplitPoint(int binNumber, int dimension, double splitPoint) const
std::vector< int > _binningDimensions
double getWeight(const HyperPoint &hyperPoint) const
int getBinNum(int volumeNumber) const
HyperHistogram * getRatioHyperBinningHistogram() const
virtual void addPrimaryVolumeNumber(int volumeNumber)
int smartSplitAllRandomise(double dataFraction=0.5)
double findSmartSplitPoint(int binNumber, int dimension, double dataFraction) const
void setMinimumBinContent(double val)
int split(int volumeNumber, int dimension, double splitPoint)
virtual bool addHyperVolume(const HyperVolume &hyperVolume, std::vector< int > linkedVolumes=std::vector< int >(0, 0))
void push_back(const HyperPoint &point)
std::vector< std::vector< int > > _dimSpecificStatus
double countEventsInHyperCuboid(const HyperPointSet &hyperPointSet, const HyperCuboid &hyperCuboid) const
double getSumW() const
std::vector< HyperPointSet > _hyperPointSets
bool inVolume(const HyperPoint &coords) const
HyperCuboid splitBelowPoint(int dim, double splitPoint, const HyperCuboid &original, bool noSnapToGrid=false) const
int smartSplitAll(int dimension, double dataFraction)
virtual bool passFunctionCriteria(HyperCuboid &cuboid1, HyperCuboid &cuboid2)
double neg2LLH(int binNumber, int dimension, double splitPoint, bool useConstraints=true)