MINT2
HyperBinningMakerPhaseBinning.cpp
Go to the documentation of this file.
2 
3 
4 
5 
6 
7 
8 
10  HyperBinningMaker(binningRange, HyperPointSet( binningRange.getDimension() )),
11  _numBinPairs (0),
12  _maximumRandWalks(30),
13  _numWalkers (5),
14  _walkSizeFrac (0.12),
15  _numberOfSystematicSplits(0),
16  _numberOfGradientSplits (0)
17 {
18  setNumBinPairs(3);
19  setHyperFunction(func);
20  WELCOME_LOG << "Good day from the HyperBinningMakerPhaseBinning() Constructor"<<std::endl;
21 }
22 
24 
25  int dimension = _binningDimensions.size();
26 
27  int splitDim = 0;
28  if (splitDim >= dimension) splitDim = 0;
29 
30  int nBins = 0;
31  int unchanged = 0;
32 
33 
34  while ( 1==1 ){
36 
37  if (s_printBinning == true) {
38  INFO_LOG << "--------------------------------------------------" <<std::endl;
39  INFO_LOG << "Trying to split all bins" << std::endl;
40  INFO_LOG << "There are " << getNumContinueBins() << " splittable bins" << std::endl;
41  }
42 
44 
45  if (nBins == getNumBins()) unchanged++;
46  else unchanged = 0;
47  if (unchanged >= dimension) break;
48  nBins = getNumBins();
49  if (s_printBinning == true) INFO_LOG << "There is now a total of " << nBins << " bins" << std::endl;
50 
51  }
52 
53  if (s_printBinning == true) INFO_LOG << "Mint binning algorithm complete " <<std::endl;
54 
55 }
56 
57 
59 
60  VERBOSE_LOG << "HyperBinningMakerPhaseBinning::gradientSplitAll( )" << std::endl;
61 
62  int initialSize = _hyperCuboids.size();
63  int nSplits = 0;
64 
65  int splittable = getNumContinueBins();
66  LoadingBar loadingbar(splittable);
67  int splittableDone = 0;
68 
69  for (int i = 0; i < initialSize; i++){
71 
72  loadingbar.update(splittableDone);
73  splittableDone++;
74 
75  int dimension = -1;
76  int split = gradientSplit( i, dimension );
77 
78  nSplits += split;
79 
80  if (split == 0){
83  }
84 
85  }
86  }
87 
88  return nSplits;
89 }
90 
91 
93 
94  //randomly select what direction we're going to walk in
95  int walkDimNum = floor(_random->Uniform(0.0, _binningDimensions.size()));
96  int walkDim = _binningDimensions.at(walkDimNum);
97 
98  double walkSize = _walkSizeFrac*( walkLimits.getHighCorner().at(walkDim) - walkLimits.getLowCorner().at(walkDim) );
99  //if (walkSize < _minimumEdgeLength.at(walkDim)) walkSize = _minimumEdgeLength.at(walkDim);
100 
101  //randomly move along this axis
102  double direction = _random->Gaus(0.0, 1.0);
103  point.at(walkDim) += walkSize*direction;
104 
105  //If this walk went out of the walk limits, move back, and try again.
106  if ( walkLimits.inVolume(point) == false ){
107  point.at(walkDim) -= walkSize*direction;
108  walk( point, walkLimits);
109  }
110 
111 }
112 
114 
115  HyperPoint walkWidth = (walkLimits.getHighCorner() - walkLimits.getLowCorner())*_walkSizeFrac;
116 
117  for (int i = 0; i < point.getDimension(); i++){
118  if ( isValidBinningDimension(i) == false ) {
119  walkWidth.at(i) = 0.0;
120  }
121  else{
122  walkWidth.at(i) = walkWidth.at(i)*_random->Gaus(0.0, 1.0);
123  }
124  }
125 
126  point = point + walkWidth;
127 
128  //If this walk went out of the walk limits, move back, and try again.
129  if ( walkLimits.inVolume(point) == false ){
130  point = point - walkWidth;
131  walk( point, walkLimits);
132  }
133 
134 }
135 
136 int HyperBinningMakerPhaseBinning::splitByCoord(int volumeNumber, int dimension, HyperPoint& point){
137 
138  double low = _hyperCuboids.at(volumeNumber).getLowCorner ().at(dimension);
139  double high = _hyperCuboids.at(volumeNumber).getHighCorner().at(dimension);
140  double splitPoint = (point.at(dimension) - low)/(high-low);
141  return split(volumeNumber, dimension, splitPoint);
142 
143 }
144 
145 
147  _numBinPairs = binpairs;
148  std::vector<double> binEdges;
149 
150  for (int i = 0; i < 2*_numBinPairs; i++){
151  binEdges.push_back( - TMath::Pi() + (TMath::Pi()/double(_numBinPairs))*i );
152  }
153 
154  _binEdges = CyclicPhaseBins(binEdges);
155 }
156 
157 void HyperBinningMakerPhaseBinning::setBinEdges(std::vector<double> binEdges){
158  _binEdges = CyclicPhaseBins(binEdges);
159  _numBinPairs = binEdges.size();
160 }
161 
162 
164 
165  if (phase < -10.0) return -1;
166 
167  return _binEdges.getBinNumber(phase);
168 
169 }
170 
172 
173  return _binEdges.getLowBinBoundary(phase);
174 
175 }
176 
178 
179  return _binEdges.getHighBinBoundary(phase);
180 
181 }
182 
184 
185  double low = getLowBinBoundary (val);
186  double high = getHighBinBoundary(val);
187 
188  double distLow = fabs(val - low );
189  double distHigh = fabs(val - high);
190 
191  if (distLow < distHigh) return low;
192 
193  return high;
194 
195 }
196 
198 
199  return getBinNumFromFuncVal(_func->getVal(point));
200 
201 }
202 
204 
205  int nBinningDims = _binningDimensions.size();
206  int nDims = _hyperCuboids.at(0).getDimension();
207 
208  HyperPoint grad(nDims, 0.0);
209 
210  for (int i = 0; i < nBinningDims; i++){
211  int dim = _binningDimensions.at(i);
212  double stepsize = _minimumEdgeLength.at(dim)*0.5;
213 
214  HyperPoint low (point);
215  HyperPoint high(point);
216  low .at(i) -= stepsize;
217  high.at(i) += stepsize;
218 
219  double valLow = _func->getVal(low );
220  double valHigh = _func->getVal(high);
221 
222  std::complex<double> compLow (cos(valLow ), sin(valLow ));
223  std::complex<double> compHigh(cos(valHigh), sin(valHigh));
224 
225  grad.at(i) = arg( compHigh*conj(compLow) )/(2.0*stepsize);
226  }
227  return grad;
228 }
229 
231 
232  int nBinningDims = _binningDimensions.size();
233  int nDims = _hyperCuboids.at(0).getDimension();
234 
235  HyperPoint grad(nDims, 0.0);
236 
237  for (int i = 0; i < nBinningDims; i++){
238  int dim = _binningDimensions.at(i);
239  double stepsize = _minimumEdgeLength.at(dim)*0.5;
240 
241  HyperPoint high(point);
242  high.at(i) += stepsize;
243 
244  double valHigh = _func->getVal(high);
245 
246  std::complex<double> compVal (cos(funcValAtPoint ), sin(funcValAtPoint ));
247  std::complex<double> compHigh(cos(valHigh), sin(valHigh));
248 
249  grad.at(i) = arg( compHigh*conj(compVal) )/(stepsize);
250  }
251 
252  return grad;
253 }
254 
255 double HyperBinningMakerPhaseBinning::getSecondDerivative(HyperPoint& point, HyperPoint& vector, double funcValAtPoint, double& firstDeriv){
256 
257  bool centeral = true;
258 
259  HyperPoint normVector = vector/vector.norm();
260 
261  double stepLength = fabs(_minimumEdgeLength.dotProduct(normVector)*0.5);
262  //double stepLength = vector.norm()*0.25;
263 
264  if (centeral){
265  HyperPoint low = point - normVector*stepLength;
266  HyperPoint high = point + normVector*stepLength;
267 
268  double val = funcValAtPoint;
269  double lowVal = _func->getVal(low );
270  double highVal = _func->getVal(high );
271 
272  double h = (high - low).norm()*0.5;
273 
274  firstDeriv = (highVal - lowVal)/(2.0*h);
275  double secondDeriv = (lowVal + highVal - 2.0*val)/(h*h);
276  return secondDeriv;
277  }
278 
279  HyperPoint high1 = point + normVector*stepLength;
280  HyperPoint high2 = point + normVector*stepLength*2.0;
281 
282  double val = _func->getVal(point );
283  double high1Val = _func->getVal(high1 );
284  double high2Val = _func->getVal(high2 );
285 
286  double h = (high1 - high2).norm();
287 
288  double secondDeriv = (val + high2Val - 2.0*high1Val)/(h*h);
289  return secondDeriv;
290 
291 
292 }
293 
294 
296 
297  double minGrad = gradient.norm()*0.25;
298 
299 
300  double maxGrad = -1.0;
301  int dimWithMaxGrad = -1;
302 
303  for (int i = 0; i < gradient.getDimension(); i++){
304 
305  if ( getDimensionSpecificVolumeStatus(volumeNumber, i) == VolumeStatus::DONE ) continue;
306 
307  double gradInThisDim = fabs( gradient.at(i) ) + minGrad;
308 
309  gradInThisDim *= _hyperCuboids.at(volumeNumber).getWidth(i);
310  gradInThisDim /= _minimumEdgeLength.at(i);
311 
312  if ( gradInThisDim > maxGrad ) {
313  maxGrad = gradInThisDim;
314  dimWithMaxGrad = i;
315  }
316 
317  }
318 
319  if (dimWithMaxGrad == -1){
320  ERROR_LOG << "Something has gone horribly wrong - if no dimensions can be split, I shouldn't be arriving here" << std::endl;
321  }
322 
323  //std::cout << gradient << " " << dimWithMaxGrad <<std::endl;
324 
325  return dimWithMaxGrad;
326 }
327 
329 
330  //Get the cuboid we are trying to split
331  HyperCuboid& chosenHyperCuboid = _hyperCuboids.at(volumeNumber);
332 
333  //Figure out what dimesions we need
334  int dimensions = _hyperCuboids.at(0).getDimension();
335 
336  std::vector<int> binningDimensions;
337  for (int i = 0; i < dimensions; i++){
338  if ( chosenHyperCuboid.getWidth(i) < 2.0*_minimumEdgeLength.at(i) ) continue;
339  if ( isValidBinningDimension(i) == false ) continue;
340  binningDimensions.push_back(i);
341  }
342 
343  int nSplittingDims = binningDimensions.size();
344 
345  //Get the center of the bin and get the function / bin value
346  HyperPoint point = chosenHyperCuboid.getCenter();
347 
348  //Project the cuboid into the splitting dimensions
349  HyperCuboid projectedCuboid = chosenHyperCuboid.project(binningDimensions);
350 
351  VERBOSE_LOG << "Geting vector of all my verticies" << std::endl;
352 
353  //Get the verticies of the projected cuboid
354  HyperPointSet projectedVerticies = projectedCuboid.getVertices();
355 
356  //Turn the `projected verticies` into `verticies` that use the coordinates
357  //of the bin centre for all dimensions that are not in binningDimensions
358 
359  HyperPointSet verticies(dimensions);
360 
361  for (unsigned i = 0; i < projectedVerticies.size(); i++){
362  HyperPoint vertex(point);
363 
364  for (int j = 0; j < nSplittingDims; j++){
365  vertex.at( binningDimensions.at(j) ) = projectedVerticies.at(i).at(j);
366  }
367 
368  //move the verticies a very small amount towards the bin centre.
369  //can cause issues if the verticies are on the limit of the
370  //kinematically allowed region
371 
372  for (int j = 0; j < nSplittingDims; j++){
373 
374  int thisDim = binningDimensions.at(j);
375 
376  double addOrSubtract = 0.0;
377  double pointVal = point .at( thisDim );
378  double vertVal = vertex.at( thisDim );
379  if ( vertVal > pointVal ) { addOrSubtract = -1.00; }
380  else { addOrSubtract = +1.00; }
381 
382  //if (dimension != thisDim ) {
383  // addOrSubtract *= 0.99;
384  //}
385 
386  vertex.at( thisDim ) += addOrSubtract*_minimumEdgeLength.at( thisDim );
387  }
388 
389  verticies.push_back(vertex);
390  }
391 
392  return verticies;
393 }
394 
396 
397 
398  //Get the cuboid we are trying to split
399  HyperCuboid& chosenHyperCuboid = _hyperCuboids.at(volumeNumber);
400 
401  //Figure out what dimesions we need
402  int dimensions = _hyperCuboids.at(0).getDimension();
403 
404  std::vector<int> binningDimensions;
405  for (int i = 0; i < dimensions; i++){
406  if ( chosenHyperCuboid.getWidth(i) < 2.0*_minimumEdgeLength.at(i) ) continue;
407  if ( isValidBinningDimension(i) == false ) continue;
408  binningDimensions.push_back(i);
409  }
410 
411  int nSplittingDims = binningDimensions.size();
412 
413 
414  //Get the center of the bin and get the function / bin value
415  HyperPoint point = chosenHyperCuboid.getCenter();
416 
417  //Project the cuboid into the splitting dimensions
418  HyperCuboid projectedCuboid = chosenHyperCuboid.project(binningDimensions);
419 
420  VERBOSE_LOG << "Geting vector of all my faces" << std::endl;
421 
422 
423 
424  HyperPointSet verticies(dimensions);
425 
426  for (int i = 0; i < nSplittingDims; i++){
427 
428  int thisDim = binningDimensions.at(i);
429  HyperPoint faceA(point);
430  HyperPoint faceB(point);
431 
432  faceA.at(thisDim) = faceA.at(thisDim) - 0.5*chosenHyperCuboid.getWidth(thisDim) + _minimumEdgeLength.at(thisDim);
433  faceB.at(thisDim) = faceB.at(thisDim) + 0.5*chosenHyperCuboid.getWidth(thisDim) - _minimumEdgeLength.at(thisDim);
434 
435  verticies.push_back(faceA);
436  verticies.push_back(faceB);
437 
438  }
439 
440  return verticies;
441 
442 }
443 
445 
446 
447  //Get the cuboid we are trying to split
448  HyperCuboid& chosenHyperCuboid = _hyperCuboids.at(volumeNumber);
449 
450  //Figure out what dimesions we need
451  int dimensions = _hyperCuboids.at(0).getDimension();
452 
453  std::vector<int> binningDimensions;
454  for (int i = 0; i < dimensions; i++){
455  if ( chosenHyperCuboid.getWidth(i) < 2.0*_minimumEdgeLength.at(i) ) continue;
456  if ( isValidBinningDimension(i) == false ) continue;
457  binningDimensions.push_back(i);
458  }
459 
460  int nSplittingDims = binningDimensions.size();
461 
462  if (nSplittingDims == 0){
463  ERROR_LOG << "There should always be at least 1 splittable dimension!" << std::endl;
464  }
465 
466  //Get the center of the bin and get the function / bin value
467  HyperPoint point = chosenHyperCuboid.getCenter();
468 
469  //Project the cuboid into the splitting dimensions
470  HyperCuboid projectedCuboid = chosenHyperCuboid.project(binningDimensions);
471 
472  VERBOSE_LOG << "Geting vector of all my edges" << std::endl;
473  VERBOSE_LOG << "There are " << nSplittingDims << " split dimensions" << std::endl;
474 
475  //Get the verticies of the projected cuboid
476  HyperPointSet projectedVerticies = projectedCuboid.getEdgeCenters();
477 
478  VERBOSE_LOG << "There are " << projectedVerticies.size() << " verticies" << std::endl;
479 
480  //Turn the `projected verticies` into `verticies` that use the coordinates
481  //of the bin centre for all dimensions that are not in binningDimensions
482 
483  HyperPointSet verticies(dimensions);
484 
485  for (unsigned i = 0; i < projectedVerticies.size(); i++){
486  HyperPoint vertex(point);
487 
488  for (int j = 0; j < nSplittingDims; j++){
489  vertex.at( binningDimensions.at(j) ) = projectedVerticies.at(i).at(j);
490  }
491 
492  //move the verticies a very small amount towards the bin centre.
493  //can cause issues if the verticies are on the limit of the
494  //kinematically allowed region
495 
496  for (int j = 0; j < nSplittingDims; j++){
497 
498  int thisDim = binningDimensions.at(j);
499 
500  double addOrSubtract = 0.0;
501  double pointVal = point .at( thisDim );
502  double vertVal = vertex.at( thisDim );
503  if ( vertVal == pointVal ) { addOrSubtract = 0.00; }
504  else if ( vertVal > pointVal ) { addOrSubtract = -1.00; }
505  else { addOrSubtract = +1.00; }
506 
507  //if (dimension != thisDim ) {
508  // addOrSubtract *= 0.99;
509  //}
510 
511  vertex.at( thisDim ) += addOrSubtract*_minimumEdgeLength.at( thisDim );
512  }
513 
514  verticies.push_back(vertex);
515  }
516 
517  VERBOSE_LOG << "About to return my verticies" << std::endl;
518 
519 
520  return verticies;
521 
522 }
523 
524 
525 
527 
528  int bin = getBinNumFromFuncVal(valAtPoint);
529 
530  //To speed things up, we want to order the corners by
531  //the most likely to split. Can use gradient to see
532 
533  //The FOM is essentially just the distance to the nearest bin edge.
534  //It's negative if we are still inside the bin.
535 
536  std::vector<double> functionEstimateFom;
537  std::vector<double> functionEstimate;
538  std::vector<int> index;
539 
540  double lowBoundary = getLowBinBoundary (valAtPoint);
541  double highBoundary = getHighBinBoundary(valAtPoint);
542 
543  VERBOSE_LOG << "Sorting points to speed my life up" << std::endl;
544 
545  for (unsigned i = 0; i < points.size(); i++){
546 
547  index.push_back(i);
548 
549  double estimate = valAtPoint + gradient.dotProduct(points.at(i) - point);
550  double fom = 0.0;
551  if ( estimate >= lowBoundary && estimate <= highBoundary ){
552  double fom1 = lowBoundary - estimate;
553  double fom2 = estimate - highBoundary;
554 
555  if (fom1 > fom2) {fom = fom1;}
556  else {fom = fom2;}
557  }
558  if (estimate < lowBoundary){
559  fom = lowBoundary - estimate;
560  }
561  if (estimate > highBoundary){
562  fom = estimate - highBoundary;
563  }
564 
565  functionEstimate .push_back(estimate);
566  functionEstimateFom.push_back(fom );
567 
568  }
569 
570 
571  TMath::Sort( (int)points.size(), &(functionEstimateFom.at(0)), &(index.at(0)) );
572  //for (unsigned i = 0; i < points.size(); i++){
573  // std::cout << functionEstimateFom.at( index.at(i) ) << std::endl;
574  //}
575 
576  //Evaluate the function for each vertex and see if the bin number changes.
577  //If so, choose a split point that is somewhere between the vetex and the
578  //bin center.
579 
580  //Each time we evaluate the function at a corner, we can see how good
581  //our predictions are, and set an error.
582 
583  double uncertaintySum = 0.0;
584  int uncertainiesAdded = 0;
585 
586  for (unsigned i = 0; i < points.size(); i++){
587 
588  double vtxNum = index.at(i);
589  double estimate = functionEstimate .at(vtxNum);
590  double fom = functionEstimateFom.at(vtxNum);
591  double estimateUncert = TMath::Pi()*2.0;
592 
593  if (uncertainiesAdded >= 2){
594  estimateUncert = uncertaintySum/double(uncertainiesAdded - 1.0);
595  }
596 
597  // i.e. if our estimate indicates that this bin is
598  // more than 3.5 sigma from a bin boundary, we give up.
599  if ( fom < -estimateUncert*5.0 ) {
600  //std::cout << "Breaking loop at " << i << "; fom est = " << fom << " ± " << estimateUncert << std::endl;
601  break;
602  }
603  double valHere = _func->getVal(points.at(vtxNum));
604  int binHere = getBinNumFromFuncVal(valHere);
605 
606  std::complex<double> cEst(cos(estimate), sin(estimate));
607  std::complex<double> cValHere(cos(valHere) , sin(valHere ));
608 
609  double diff = arg( cEst*conj(cValHere) );
610 
611  uncertaintySum += fabs(diff);
612  uncertainiesAdded++;
613 
614  //std::cout << i << " "<< estimate << " : [ " << lowBoundary << ", " << highBoundary << "] "<< valHere << std::endl;
615 
616  if (binHere != bin){
617  HyperPoint returnPoint(points.at(vtxNum));
618  returnPoint.setWeight(0, valHere);
619  return returnPoint;
620  }
621 
622  }
623 
624  HyperPoint returnPoint(0);
625  if (returnPoint.getDimension() !=0 ){
626  ERROR_LOG << "This should be zero" << std::endl;
627  }
628 
629  return returnPoint;
630 
631 }
632 
633 int HyperBinningMakerPhaseBinning::systematicSplit(int volumeNumber, int dimension, double valAtCenter, HyperPoint gradient){
634 
636 
637  //int binNumAtCenter = getBinNumFromFuncVal(valAtCenter);
638 
639  HyperCuboid& chosenHyperCuboid = _hyperCuboids.at(volumeNumber);
640  HyperPoint centerPoint = chosenHyperCuboid.getCenter();
641 
642 
643 
644  HyperPointSet pointsToTest( _hyperCuboids.at(0).getDimension() );
645 
646  HyperPointSet corners = getSplitCorners(volumeNumber);
647  HyperPointSet faces = getSplitFaces (volumeNumber);
648  HyperPointSet edges = getSplitEdges (volumeNumber);
649 
650  pointsToTest.addHyperPointSet(corners);
651  pointsToTest.addHyperPointSet(faces );
652  pointsToTest.addHyperPointSet(edges );
653 
654  VERBOSE_LOG << "Got a big list of " << pointsToTest.size() << " to test " << std::endl;
655 
656  //pointsToTest.print();
657 
658  //for (int i = 0; i < corners.size(); i++){
659  // pointsToTest.push_back( (corners.at(i) + centerPoint)*0.5 );
660  //}
661 
662 
663  HyperPoint point = orderAndTestSplitPoints(pointsToTest, centerPoint, valAtCenter, gradient);
664 
665  if ( point.getDimension() == 0 ) return 0;
666 
667  double valAtPoint = point.getWeight();
668 
669  std::complex<double> cValAtPoint (cos(valAtPoint) , sin(valAtPoint ));
670  std::complex<double> cValAtCenter(cos(valAtCenter) , sin(valAtCenter));
671 
672  double dy = arg( cValAtCenter*conj(cValAtPoint) );
673 
674  double binEdge = 0.0;
675  if (dy > 0.0){
676  binEdge = getLowBinBoundary(valAtCenter);
677  }
678  else{
679  binEdge = getHighBinBoundary(valAtCenter);
680  }
681 
682  double scale = fabs( (binEdge - valAtCenter)/dy );
683  if (scale > 1.00){
684  //ERROR_LOG << "THIS HAS TO BE LESS THAN 1.0 - It's " << scale << std::endl;
685  scale = 1.0;
686  }
687 
688  HyperPoint splitPoint = centerPoint + ( point - centerPoint )*scale;
689  return splitByCoord(volumeNumber, dimension, splitPoint );
690 
691 
692 }
693 
694 
695 
696 
697 
698 
699 int HyperBinningMakerPhaseBinning::gradientSplit(int volumeNumber, int& dimension){
700 
702 
703  VERBOSE_LOG <<"Calling gradientSplit(" << volumeNumber << ", " << dimension << ")" << std::endl;
704 
705  //first get the Hypercube that we want to split
706 
707  HyperCuboid& chosenHyperCuboid = _hyperCuboids.at(volumeNumber);
708 
709 
710  //Get the center of the bin. Ideally we want
711  //to find a split point as colse as possible to this
712  HyperPoint binCenter = chosenHyperCuboid.getCenter();
713 
714  //Evaluate the function at the bin center and find the
715  //'bin number' from this. Also find out which bin boundary
716  //is closest to us.
717 
718  double valCenter = _func->getVal(binCenter);
719  int binNumber = getBinNumFromFuncVal(valCenter);
720  double closestBound = closestBinBoundary(valCenter);
721 
722  //Gradient given in the same coordinates as the binning
723  HyperPoint gradient = getGradPos(binCenter, valCenter);
724 
725  dimension = splitDimFromGrad(volumeNumber, gradient);
726 
727  //if (fabs(gradient.at(dimension))*10.0 < gradient.norm()){
728  // return randomWalkSplit(volumeNumber, dimension);
729  //}
730 
731  //When we are splitting the bin, there is no point in splitting in a
732  //region that will result in bins that are too narrow. Therefore define the "splitLimits"
733 
734  HyperPoint lowPoint = chosenHyperCuboid.getLowCorner ();
735  HyperPoint highPoint = chosenHyperCuboid.getHighCorner();
736 
737  lowPoint = lowPoint + _minimumEdgeLength*0.499;
738  highPoint = highPoint - _minimumEdgeLength*0.499;
739 
740  lowPoint .at(dimension) += _minimumEdgeLength.at(dimension)*0.5;
741  highPoint.at(dimension) -= _minimumEdgeLength.at(dimension)*0.5;
742 
743  HyperCuboid splitLimits(lowPoint, highPoint);
744  HyperPoint splitLimitsWidth = highPoint - lowPoint;
745  VERBOSE_LOG << "I have a nice set of split limits" << std::endl;
746 
747 
748  //tranform gradient to a coordinate system where the bin
749  //is limited by [-1, 1] in all dims
750 
751  HyperPoint gradientTrans = gradient;
752 
753  int nDims = _hyperCuboids.at(0).getDimension();
754 
755  for (int i = 0; i < nDims; i++){
756  gradientTrans.at(i) *= (splitLimitsWidth.at(i)*2.0);
757  }
758 
759  //if I move along in space by 'gradient' the change in the function will be
760 
761  double rateOfInc = gradientTrans.norm2();
762 
763  //We need the function to change by the distance to the nearest boundary:
764 
765  double scale = (closestBound - valCenter)/rateOfInc;
766 
767  HyperPoint splitVector = gradientTrans*scale;
768 
769  //Now we need to transform the SplitVector back to
770  //the real coordinate system.
771  //The fact that we multiply by the same thing again
772  //I found counter-intuative, but I think it's correct.
773 
774  for (int i = 0; i < nDims; i++){
775  splitVector.at(i) *= (splitLimitsWidth.at(i)*2.0);
776  }
777 
778  //Now we have a direction to look along, we can find the
779  //second derivate in this direction to improve the estimate
780 
781  //double firstDeriv = gradientOrig.dotProduct(splitVector)/splitVector.norm();
782  double firstDeriv = 0.0;
783  double secondDeriv = getSecondDerivative(binCenter, splitVector, valCenter, firstDeriv);
784 
785  // f(x) = f(x0) + f'(x0) (x-x0) + f''(x0) (x-x0)^2 / 2
786  //solve the quadratic eqn
787 
788  double a = secondDeriv/2.0;
789  double b = firstDeriv;
790  double c = valCenter - closestBound;
791 
792  double quadraticSol1 = (-b + sqrt(b*b - 4.0*a*c))/(2.0*a);
793  double quadraticSol2 = (-b - sqrt(b*b - 4.0*a*c))/(2.0*a);
794 
795  //choose the solution that is closest to the bin center
796 
797  double quadraticSol = quadraticSol1;
798  if ( fabs(quadraticSol1) > fabs(quadraticSol2) ){
799  quadraticSol = quadraticSol2;
800  }
801 
802  //If the solution to the quadratic is NaN, just go with the
803  //more simple cornerSplit function.
804 
805  if (quadraticSol != quadraticSol){
806  return systematicSplit(volumeNumber, dimension, valCenter, gradient);
807  }
808 
809  //Get a refined split vector using improved first deriv and second deriv
810  HyperPoint refinedSplitVector = (splitVector * quadraticSol ) / splitVector.norm();
811 
812  //Use the split vectors to get split points
813 
814  HyperPoint splitPoint = splitVector + binCenter;
815  HyperPoint refinedSplitPoint = refinedSplitVector + binCenter;
816 
817  //Want to add a small amount extra to make sure we cross a bin boundary.
818 
819  HyperPoint refinedSplitPointExtended = refinedSplitVector*1.05 + binCenter;
820 
821  //As a cross check, can make a function in the original coordinate
822  //system that models the function using f(x0) and grad(x0). We then
823  //evaluate this at the split point that was determined. Hopefully
824  //this returns the nearest bin boundary!!! (It does)
825 
826  bool crossCheck1 = false;
827  bool crossCheck2 = false;
828  bool crossCheck4 = false;
829 
830  if (crossCheck1 == true){
831 
832  double predictedVal = valCenter + gradient.dotProduct( splitPoint - binCenter );
833  std::cout << predictedVal << ", " << closestBound << std::endl;
834 
835  }
836 
837  if (crossCheck2 == true){
838 
839  double directionVal = splitVector.dotProduct(refinedSplitPoint - binCenter);
840 
841  if (directionVal < 0.0) directionVal = -1.0;
842  else directionVal = 1.0;
843 
844  double predictedVal = 0.5*secondDeriv*(refinedSplitPoint - binCenter).norm2() + directionVal*firstDeriv*(refinedSplitPoint - binCenter).norm() + valCenter;
845 
846  std::cout << predictedVal << ", " << closestBound << std::endl;
847 
848  }
849 
850  if (crossCheck4 == true){
851 
852  std::cout << gradient.dotProduct( splitVector )/splitVector.norm() << ", " << firstDeriv << std::endl;
853  }
854 
855 
856  //See if the predicted split point is within the bin limits, if not
857  //return try a less sophisticated method.
858 
859  if (splitLimits.inVolume(refinedSplitPointExtended) == false) {
860  return systematicSplit(volumeNumber, dimension, valCenter, gradient);
861  }
862 
863  //See what the function and the bin number is at the new point
864  double valNew = _func->getVal(refinedSplitPointExtended);
865  int binNew = getBinNumFromFuncVal(valNew);
866 
867  //As a cross check we can see how the extrapolation agrees with the real value.
868 
869  bool crossCheck3 = false;
870 
871  if (crossCheck3 == true){
872 
873  double valReal = _func->getVal( splitPoint);
874  double valRealRef = _func->getVal(refinedSplitPoint);
875  double valExtrap = closestBound;
876 
877  std::complex<double> cValReal (cos(valReal) , sin(valReal) );
878  std::complex<double> cValRealRef(cos(valRealRef), sin(valRealRef) );
879  std::complex<double> cValExtrap (cos(valExtrap) , sin(valExtrap));
880  double diff = arg(cValReal *conj(cValExtrap));
881  double diffRef = arg(cValRealRef*conj(cValExtrap));
882 
883  std::cout << valCenter << " -> (" << valReal << " ?= " << valExtrap << " ) -> " << diff / fabs(valCenter-valExtrap) << std::endl;
884  std::cout << diff << " -> " << diffRef << std::endl;
885 
886  }
887 
888  //If we end up in the same bin, try a less sophisticated approach
889 
890  if ( binNew == binNumber ) {
891  return systematicSplit(volumeNumber, dimension, valCenter, gradient);
892  }
893 
894  //Finally, if everything else goes OK, split bin at the chosen split point
895 
896  return splitByCoord(volumeNumber, dimension, refinedSplitPointExtended );
897 
898 }
899 
900 int HyperBinningMakerPhaseBinning::randomWalkSplit(int volumeNumber, int dimension){
901 
902  VERBOSE_LOG <<"Calling gradientSplit(" << volumeNumber << ", " << dimension << ")" << std::endl;
903 
904  //first get the Hypercube that we want to split
905 
906  HyperCuboid& chosenHyperCuboid = _hyperCuboids.at(volumeNumber);
907 
908  HyperPoint lowPoint = chosenHyperCuboid.getLowCorner ();
909  HyperPoint highPoint = chosenHyperCuboid.getHighCorner();
910 
911 
912  //get the minumum bin width in the dimension we're splitting in
913  double minBinWidth = _minimumEdgeLength.at(dimension);
914 
915  //if the volume we're splitting is narrower than minBinWidth*2 we bail now
916  //if ( binWidth < minBinWidth*2.0 ) return 0;
917 
918 
919 
920  //When we do the random walk, there is no point in walking to regions that will
921  //result in bins that are too narrow. Therefore define the "walkLimits"
922 
923 
924  HyperPoint binCenter = chosenHyperCuboid.getCenter();
925 
926  lowPoint = lowPoint + _minimumEdgeLength*0.499;
927  highPoint = highPoint - _minimumEdgeLength*0.499;
928 
929  //for ( int i = 0; i < lowPoint.getDimension(); i++ ){
930  // if ( highPoint.at(i) - lowPoint.at(i) < 2.0*_minimumEdgeLength.at(i) ){
931  // lowPoint .at(i) = binCenter.at(i) - 0.01*_minimumEdgeLength.at(i);
932  // highPoint.at(i) = binCenter.at(i) + 0.01*_minimumEdgeLength.at(i);
933  // }
934  // else{
935  // lowPoint .at(i) += _minimumEdgeLength.at(i);
936  // highPoint.at(i) -= _minimumEdgeLength.at(i);
937  // }
938  //}
939 
940  lowPoint .at(dimension) += minBinWidth*0.5;
941  highPoint.at(dimension) -= minBinWidth*0.5;
942 
943  VERBOSE_LOG <<"Walk width in split dim = " << highPoint.at(dimension) - lowPoint.at(dimension) << std::endl;
944 
945  //INFO_LOG << "I bet this happens first" << std::endl;
946  HyperCuboid walkLimits(lowPoint, highPoint);
947 
948 
949  //Random walk starting point
950  HyperPoint point = chosenHyperCuboid.getCenter();
951  //point.at(2) = 0.3;
952  //point.at(3) = -0.2;
953  //point.at(4) = 2.0;
954 
955  HyperPointSet points(_numWalkers, point);
956 
957  double valCenter = getBinNumFromFunc(point);
958 
959 
960  for ( int i = 0; i < _maximumRandWalks; i++ ){
961 
962  VERBOSE_LOG <<"Random walk " << i << " of " << _maximumRandWalks << std::endl;
963 
964 
965  for (int j = 0; j < _numWalkers; j++){
966  VERBOSE_LOG <<"-- walker " << j << " fancies exploring this space" << std::endl;
967 
968  walk( points.at(j), walkLimits );
969  VERBOSE_LOG <<"-- walker " << j;
970  double val = getBinNumFromFunc( points.at(j) );
971  VERBOSE_LOG << " has fnc val = " << val << std::endl;
972 
973  if ( fabs(val - valCenter) > 0.5 ) {
974 
975  return splitByCoord(volumeNumber, dimension, points.at(j) );
976 
977  }
978 
979  }
980 
981  //make two pointx which are a short distance either size of the split
982 
983  //HyperPoint point1(point);
984  //HyperPoint point2(point);
985  //point1.at(dimension) += walkSize*0.5;
986  //point2.at(dimension) -= walkSize*0.5;
987  //
988  //if ( walkLimits.inVolume(point1) == false ){
989  // point1.at(dimension) -= walkSize*0.5;
990  // point1.at(dimension) += minBinWidth*0.5;
991  //}
992  //
993  //if ( walkLimits.inVolume(point2) == false ){
994  // point2.at(dimension) += walkSize*0.5;
995  // point2.at(dimension) -= minBinWidth*0.5;
996  //}
997 
998  //Evaluate the function for each point
999  //double val1 = _func->getVal(point1);
1000  //double val2 = _func->getVal(point2);
1001 
1002  //double val = _func->getVal(point);
1003 
1004 
1005  //If the function values are sufficiently different - SPLIT!!
1006  //if ( fabs(val1 - val2) > 0.5 ) {
1007  //if ( fabs(val - valCenter) > 0.5 ) {
1008 
1009  // splitByCoord();
1010 
1011  //}
1012 
1013  }
1014 
1015  return 0;
1016 
1017 }
1018 
1019 
1020 
1022 
1023  INFO_LOG << "Number of gradient split attempts: " << _numberOfGradientSplits << std::endl;
1024  INFO_LOG << "Number of systematic split attempts: " << _numberOfSystematicSplits << std::endl;
1025 
1026 
1027  GOODBYE_LOG << "Goodbye from the HyperBinningMakerPhaseBinning() Constructor" <<std::endl;
1028 }
virtual int gradientSplit(int binNumber, int &dimension)
HyperPointSet getVertices() const
int getNumContinueBins(int dimension=-1) const
HyperPoint _minimumEdgeLength
#define INFO_LOG
static bool s_printBinning
double dotProduct(const HyperPoint &other) const
Definition: HyperPoint.cpp:147
int splitByCoord(int volumeNumber, int dimension, HyperPoint &coord)
void setWeight(int i, double w)
Definition: Weights.cpp:52
#define ERROR_LOG
double getHighBinBoundary(int bin) const
bool isValidBinningDimension(int dimension)
HyperPointSet getEdgeCenters() const
#define VERBOSE_LOG
HyperPointSet getSplitFaces(int volumeNumber)
HyperPointSet getSplitEdges(int volumeNumber)
int systematicSplit(int volumeNumber, int dimension, double valAtCenter, HyperPoint gradient)
virtual void finishedIteration()
HyperPoint orderAndTestSplitPoints(HyperPointSet &points, HyperPoint &point, double valAtPoint, HyperPoint gradient)
const HyperPoint & at(int i) const
HyperFunction * _func
HyperPoint getCenter() const
Definition: HyperCuboid.cpp:93
const HyperPoint & getHighCorner() const
Definition: HyperCuboid.h:89
void updateGlobalStatusFromDimSpecific(int volumeNumber)
#define GOODBYE_LOG
void walkOrthogonal(HyperPoint &point, HyperCuboid &walkLimits)
HyperPoint getWidth() const
virtual double getVal(const HyperPoint &point) const =0
double getSecondDerivative(HyperPoint &point, HyperPoint &vector, double funcValAtPoint, double &deriv)
const double & at(int i) const
Definition: HyperPoint.cpp:433
int splitDimFromGrad(int volumeNumber, HyperPoint gradient)
void setHyperFunction(HyperFunction *fnc)
Set the HyperFunction - only used by some binning Algs.
const HyperPoint & getLowCorner() const
Definition: HyperCuboid.h:87
unsigned int size() const
#define WELCOME_LOG
int & getGlobalVolumeStatus(int volumeNumber)
double getLowBinBoundary(int bin) const
void walk(HyperPoint &point, HyperCuboid &walkLimits)
int randomWalkSplit(int volumeNumber, int dimension)
void setBinEdges(std::vector< double > binEdges)
void update(int i)
Definition: LoadingBar.cpp:33
int & getDimensionSpecificVolumeStatus(int volumeNumber, int dimension)
double getWeight(int i=0) const
Definition: Weights.cpp:40
double norm2() const
Definition: HyperPoint.cpp:139
int getBinNumber(double phase) const
HyperPoint getGradPos(HyperPoint &point, double funcValAtPoint)
std::vector< HyperCuboid > _hyperCuboids
HyperPointSet getSplitCorners(int volumeNumber)
std::vector< int > _binningDimensions
int getDimension() const
Definition: HyperPoint.h:99
HyperBinningMakerPhaseBinning(const HyperCuboid &binningRange, HyperFunction *func)
HyperCuboid project(std::vector< int > dims) const
int split(int volumeNumber, int dimension, double splitPoint)
void push_back(const HyperPoint &point)
double norm() const
Definition: HyperPoint.cpp:131
bool inVolume(const HyperPoint &coords) const