00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <algorithm>
00015 #include <limits>
00016 #include <cmath>
00017
00018 #include "TKDTreeBinning.h"
00019
00020 #include "Fit/BinData.h"
00021
00022 ClassImp(TKDTreeBinning)
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 struct TKDTreeBinning::CompareAsc {
00042
00043 CompareAsc(const TKDTreeBinning* treebins) : bins(treebins) {}
00044 Bool_t operator()(UInt_t bin1, UInt_t bin2) {
00045 return bins->GetBinDensity(bin1) < bins->GetBinDensity(bin2);
00046 }
00047 const TKDTreeBinning* bins;
00048 };
00049
00050 struct TKDTreeBinning::CompareDesc {
00051
00052 CompareDesc(const TKDTreeBinning* treebins) : bins(treebins) {}
00053 Bool_t operator()(UInt_t bin1, UInt_t bin2) {
00054 return bins->GetBinDensity(bin1) > bins->GetBinDensity(bin2);
00055 }
00056 const TKDTreeBinning* bins;
00057 };
00058
00059 TKDTreeBinning::TKDTreeBinning(UInt_t dataSize, UInt_t dataDim, Double_t* data, UInt_t nBins)
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 : fData(0), fBinMinEdges(std::vector<Double_t>()), fBinMaxEdges(std::vector<Double_t>()), fDataBins((TKDTreeID*)0), fDim(dataDim),
00071 fDataSize(dataSize), fDataThresholds(std::vector<std::pair<Double_t, Double_t> >(fDim, std::make_pair(0., 0.))),
00072 fIsSorted(kFALSE), fIsSortedAsc(kFALSE), fBinsContent(std::vector<UInt_t>()) {
00073 if (data) {
00074 SetData(data);
00075 SetNBins(nBins);
00076 } else {
00077 if (!fData)
00078 this->Warning("TKDTreeBinning", "Data is nil. Nothing is built.");
00079 }
00080 }
00081
00082 TKDTreeBinning::~TKDTreeBinning() {
00083
00084 if (fData) delete[] fData;
00085 if (fDataBins) delete fDataBins;
00086 }
00087
00088 void TKDTreeBinning::SetNBins(UInt_t bins) {
00089
00090 fNBins = bins;
00091 if (fDim && fNBins && fDataSize) {
00092 if (fDataSize / fNBins) {
00093 Bool_t remainingData = fDataSize % fNBins;
00094 if (remainingData) {
00095 fNBins += 1;
00096 this->Info("SetNBins", "Number of bins is not enough to hold the data. Extra bin added.");
00097 }
00098 fDataBins = new TKDTreeID(fDataSize, fDim, fDataSize / (fNBins - remainingData));
00099 SetTreeData();
00100 fDataBins->Build();
00101 SetBinsEdges();
00102 SetBinsContent();
00103 } else {
00104 fDataBins = (TKDTreeID*)0;
00105 this->Warning("SetNBins", "Number of bins is bigger than data size. Nothing is built.");
00106 }
00107 } else {
00108 fDataBins = (TKDTreeID*)0;
00109 if (!fDim)
00110 this->Warning("SetNBins", "Data dimension is nil. Nothing is built.");
00111 if (!fNBins)
00112 this->Warning("SetNBins", "Number of bins is nil. Nothing is built.");
00113 if (!fDataSize)
00114 this->Warning("SetNBins", "Data size is nil. Nothing is built.");
00115 }
00116 }
00117
00118 void TKDTreeBinning::SortBinsByDensity(Bool_t sortAsc) {
00119
00120 if (fDim == 1) {
00121 fIsSortedAsc = kTRUE;
00122 std::sort(fBinMinEdges.begin(), fBinMinEdges.end());
00123 std::sort(fBinMaxEdges.begin(), fBinMaxEdges.end());
00124
00125 fBinMinEdges.push_back(fBinMaxEdges.back());
00126 if (!sortAsc) {
00127 std::reverse(fBinMinEdges.begin(), fBinMinEdges.end());
00128 std::reverse(fBinMaxEdges.begin(), fBinMaxEdges.end());
00129 fIsSortedAsc = kFALSE;
00130 }
00131 } else {
00132 UInt_t* indices = new UInt_t[fNBins];
00133 for (UInt_t i = 0; i < fNBins; ++i)
00134 indices[i] = i;
00135 if (sortAsc) {
00136 std::sort(indices, indices + fNBins, CompareAsc(this));
00137 fIsSortedAsc = kTRUE;
00138 } else {
00139 std::sort(indices, indices + fNBins, CompareDesc(this));
00140 fIsSortedAsc = kFALSE;
00141 }
00142 std::vector<Double_t> binMinEdges; binMinEdges.reserve(fNBins * fDim);
00143 std::vector<Double_t> binMaxEdges; binMaxEdges.reserve(fNBins * fDim);
00144 for (UInt_t i = 0; i < fNBins; ++i) {
00145 for (UInt_t j = 0; j < fDim; ++j) {
00146 binMinEdges[i * fDim + j] = fBinMinEdges[indices[i] * fDim + j];
00147 binMaxEdges[i * fDim + j] = fBinMaxEdges[indices[i] * fDim + j];
00148 }
00149 }
00150 fBinMinEdges.swap(binMinEdges);
00151 fBinMaxEdges.swap(binMaxEdges);
00152
00153
00154 if ( fDataSize % fNBins != 0) {
00155 UInt_t k = 0;
00156 Bool_t found = kFALSE;
00157 while (!found) {
00158 if (indices[k] == fNBins - 1) {
00159 found = kTRUE;
00160 break;
00161 }
00162 ++k;
00163 }
00164 fBinsContent[fNBins - 1] = fDataBins->GetBucketSize();
00165 fBinsContent[k] = fDataSize % fNBins-1;
00166 }
00167 delete [] indices;
00168 fIsSorted = kTRUE;
00169 }
00170 }
00171
00172 void TKDTreeBinning::SetData(Double_t* data) {
00173
00174 fData = new Double_t*[fDim];
00175 for (UInt_t i = 0; i < fDim; ++i) {
00176 fData[i] = &data[i * fDataSize];
00177 fDataThresholds[i] = std::make_pair(*std::min_element(fData[i], fData[i] + fDataSize), *std::max_element(fData[i], fData[i] + fDataSize));
00178 }
00179 }
00180
00181 void TKDTreeBinning::SetTreeData() {
00182
00183 for (UInt_t i = 0; i < fDim; ++i)
00184 fDataBins->SetData(i, fData[i]);
00185 }
00186
00187 void TKDTreeBinning::SetBinsContent() {
00188
00189 fBinsContent.reserve(fNBins);
00190 for (UInt_t i = 0; i < fNBins; ++i)
00191 fBinsContent[i] = fDataBins->GetBucketSize();
00192 if ( fDataSize % fNBins != 0 )
00193 fBinsContent[fNBins - 1] = fDataSize % (fNBins-1);
00194 }
00195
00196 void TKDTreeBinning::SetBinsEdges() {
00197
00198 Double_t* rawBinEdges = fDataBins->GetBoundary(fDataBins->GetNNodes());
00199 fCheckedBinEdges = std::vector<std::vector<std::pair<Bool_t, Bool_t> > >(fDim, std::vector<std::pair<Bool_t, Bool_t> >(fNBins, std::make_pair(kFALSE, kFALSE)));
00200 fCommonBinEdges = std::vector<std::map<Double_t, std::vector<UInt_t> > >(fDim, std::map<Double_t, std::vector<UInt_t> >());
00201 SetCommonBinEdges(rawBinEdges);
00202 if (TestBit(kAdjustBinEdges) ) {
00203 ReadjustMinBinEdges(rawBinEdges);
00204 ReadjustMaxBinEdges(rawBinEdges);
00205 }
00206 SetBinMinMaxEdges(rawBinEdges);
00207 fCommonBinEdges.clear();
00208 fCheckedBinEdges.clear();
00209 }
00210
00211 void TKDTreeBinning::SetBinMinMaxEdges(Double_t* binEdges) {
00212
00213 fBinMinEdges.reserve(fNBins * fDim);
00214 fBinMaxEdges.reserve(fNBins * fDim);
00215 for (UInt_t i = 0; i < fNBins; ++i) {
00216 for (UInt_t j = 0; j < fDim; ++j) {
00217 fBinMinEdges.push_back(binEdges[(i * fDim + j) * 2]);
00218 fBinMaxEdges.push_back(binEdges[(i * fDim + j) * 2 + 1]);
00219 }
00220 }
00221 }
00222
00223 void TKDTreeBinning::SetCommonBinEdges(Double_t* binEdges) {
00224
00225 for (UInt_t i = 0; i < fDim; ++i) {
00226 for (UInt_t j = 0; j < fNBins; ++j) {
00227 Double_t binEdge = binEdges[(j * fDim + i) * 2];
00228 if(fCommonBinEdges[i].find(binEdge) == fCommonBinEdges[i].end()) {
00229 std::vector<UInt_t> commonBinEdges;
00230 for (UInt_t k = 0; k < fNBins; ++k) {
00231 UInt_t minBinEdgePos = (k * fDim + i) * 2;
00232 if (std::fabs(binEdge - binEdges[minBinEdgePos]) < std::numeric_limits<Double_t>::epsilon())
00233 commonBinEdges.push_back(minBinEdgePos);
00234 UInt_t maxBinEdgePos = ++minBinEdgePos;
00235 if (std::fabs(binEdge - binEdges[maxBinEdgePos]) < std::numeric_limits<Double_t>::epsilon())
00236 commonBinEdges.push_back(maxBinEdgePos);
00237 }
00238 fCommonBinEdges[i][binEdge] = commonBinEdges;
00239 }
00240 }
00241 }
00242 }
00243
00244 void TKDTreeBinning::ReadjustMinBinEdges(Double_t* binEdges) {
00245
00246 for (UInt_t i = 0; i < fDim; ++i) {
00247 for (UInt_t j = 0; j < fNBins; ++j) {
00248 if (!fCheckedBinEdges[i][j].first) {
00249 Double_t binEdge = binEdges[(j * fDim + i) * 2];
00250 Double_t adjustedBinEdge = binEdge;
00251 adjustedBinEdge -= 1.5 * std::numeric_limits<Double_t>::epsilon();
00252 for (UInt_t k = 0; k < fCommonBinEdges[i][binEdge].size(); ++k) {
00253 UInt_t binEdgePos = fCommonBinEdges[i][binEdge][k];
00254 Bool_t isMinBinEdge = binEdgePos % 2 == 0;
00255 UInt_t bin = isMinBinEdge ? (binEdgePos / 2 - i) / fDim : ((binEdgePos - 1) / 2 - i) / fDim;
00256 binEdges[binEdgePos] = adjustedBinEdge;
00257 if (isMinBinEdge)
00258 fCheckedBinEdges[i][bin].first = kTRUE;
00259 else
00260 fCheckedBinEdges[i][bin].second = kTRUE;
00261 }
00262 }
00263 }
00264 }
00265 }
00266
00267 void TKDTreeBinning::ReadjustMaxBinEdges(Double_t* binEdges) {
00268
00269 for (UInt_t i = 0; i < fDim; ++i) {
00270 for (UInt_t j = 0; j < fNBins; ++j) {
00271 if (!fCheckedBinEdges[i][j].second) {
00272 Double_t& binEdge = binEdges[(j * fDim + i) * 2 + 1];
00273 binEdge += 1.5 * std::numeric_limits<Double_t>::epsilon();
00274 }
00275 }
00276 }
00277 }
00278
00279 const Double_t* TKDTreeBinning::GetBinsMinEdges() const {
00280
00281 if (fDataBins)
00282 return &fBinMinEdges[0];
00283 this->Warning("GetBinsMinEdges", "Binning kd-tree is nil. No bin edges retrieved.");
00284 this->Info("GetBinsMinEdges", "Returning null pointer.");
00285 return (Double_t*)0;
00286 }
00287
00288 const Double_t* TKDTreeBinning::GetBinsMaxEdges() const {
00289
00290 if (fDataBins)
00291 return &fBinMaxEdges[0];
00292 this->Warning("GetBinsMaxEdges", "Binning kd-tree is nil. No bin edges retrieved.");
00293 this->Info("GetBinsMaxEdges", "Returning null pointer.");
00294 return (Double_t*)0;
00295 }
00296
00297 std::pair<const Double_t*, const Double_t*> TKDTreeBinning::GetBinsEdges() const {
00298
00299 if (fDataBins)
00300 return std::make_pair(GetBinsMinEdges(), GetBinsMaxEdges());
00301 this->Warning("GetBinsEdges", "Binning kd-tree is nil. No bin edges retrieved.");
00302 this->Info("GetBinsEdges", "Returning null pointer pair.");
00303 return std::make_pair((Double_t*)0, (Double_t*)0);
00304 }
00305
00306 const Double_t* TKDTreeBinning::GetBinMinEdges(UInt_t bin) const {
00307
00308 if (fDataBins)
00309 if (bin < fNBins)
00310 return &fBinMinEdges[bin * fDim];
00311 else
00312 this->Warning("GetBinMinEdges", "No such bin. 'bin' is between 0 and %d", fNBins - 1);
00313 else
00314 this->Warning("GetBinMinEdges", "Binning kd-tree is nil. No bin edges retrieved.");
00315 this->Info("GetBinMinEdges", "Returning null pointer.");
00316 return (Double_t*)0;
00317 }
00318
00319 const Double_t* TKDTreeBinning::GetBinMaxEdges(UInt_t bin) const {
00320
00321 if (fDataBins)
00322 if (bin < fNBins)
00323 return &fBinMaxEdges[bin * fDim];
00324 else
00325 this->Warning("GetBinMaxEdges", "No such bin. 'bin' is between 0 and %d", fNBins - 1);
00326 else
00327 this->Warning("GetBinMaxEdges", "Binning kd-tree is nil. No bin edges retrieved.");
00328 this->Info("GetBinMaxEdges", "Returning null pointer.");
00329 return (Double_t*)0;
00330 }
00331
00332 std::pair<const Double_t*, const Double_t*> TKDTreeBinning::GetBinEdges(UInt_t bin) const {
00333
00334 if (fDataBins)
00335 if (bin < fNBins)
00336 return std::make_pair(GetBinMinEdges(bin), GetBinMaxEdges(bin));
00337 else
00338 this->Warning("GetBinEdges", "No such bin. 'bin' is between 0 and %d", fNBins - 1);
00339 else
00340 this->Warning("GetBinEdges", "Binning kd-tree is nil. No bin edges retrieved.");
00341 this->Info("GetBinEdges", "Returning null pointer pair.");
00342 return std::make_pair((Double_t*)0, (Double_t*)0);
00343 }
00344
00345 UInt_t TKDTreeBinning::GetNBins() const {
00346
00347 return fNBins;
00348 }
00349
00350 UInt_t TKDTreeBinning::GetDim() const {
00351
00352 return fDim;
00353 }
00354
00355 UInt_t TKDTreeBinning::GetBinContent(UInt_t bin) const {
00356
00357 if(bin <= fNBins - 1)
00358 return fBinsContent[bin];
00359 this->Warning("GetBinContent", "No such bin. Returning 0.");
00360 this->Info("GetBinContent", "'bin' is between 0 and %d.", fNBins - 1);
00361 return 0;
00362 }
00363
00364 TKDTreeID* TKDTreeBinning::GetTree() const {
00365
00366 if (fDataBins)
00367 return fDataBins;
00368 this->Warning("GetTree", "Binning kd-tree is nil. No embedded kd-tree retrieved. Returning null pointer.");
00369 return (TKDTreeID*)0;
00370 }
00371
00372 const Double_t* TKDTreeBinning::GetDimData(UInt_t dim) const {
00373
00374 if(dim < fDim)
00375 return fData[dim];
00376 this->Warning("GetDimData", "No such dimensional coordinate. No coordinate data retrieved. Returning null pointer.");
00377 this->Info("GetDimData", "'dim' is between 0 and %d.", fDim - 1);
00378 return 0;
00379 }
00380
00381 Double_t TKDTreeBinning::GetDataMin(UInt_t dim) const {
00382
00383 if(dim < fDim)
00384 return fDataThresholds[dim].first;
00385 this->Warning("GetDataMin", "No such dimensional coordinate. No coordinate data minimum retrieved. Returning +inf.");
00386 this->Info("GetDataMin", "'dim' is between 0 and %d.", fDim - 1);
00387 return std::numeric_limits<Double_t>::infinity();
00388 }
00389
00390 Double_t TKDTreeBinning::GetDataMax(UInt_t dim) const {
00391
00392 if(dim < fDim)
00393 return fDataThresholds[dim].second;
00394 this->Warning("GetDataMax", "No such dimensional coordinate. No coordinate data maximum retrieved. Returning -inf.");
00395 this->Info("GetDataMax", "'dim' is between 0 and %d.", fDim - 1);
00396 return -1 * std::numeric_limits<Double_t>::infinity();
00397 }
00398
00399 Double_t TKDTreeBinning::GetBinDensity(UInt_t bin) const {
00400
00401 if(bin < fNBins) {
00402 Double_t volume = GetBinVolume(bin);
00403 if (!volume)
00404 this->Warning("GetBinDensity", "Volume is null. Returning -1.");
00405 return GetBinContent(bin) / volume;
00406 }
00407 this->Warning("GetBinDensity", "No such bin. Returning -1.");
00408 this->Info("GetBinDensity", "'bin' is between 0 and %d.", fNBins - 1);
00409 return -1.;
00410 }
00411
00412 Double_t TKDTreeBinning::GetBinVolume(UInt_t bin) const {
00413
00414 if(bin < fNBins) {
00415 std::pair<const Double_t*, const Double_t*> binEdges = GetBinEdges(bin);
00416 Double_t volume = 1.;
00417 for (UInt_t i = 0; i < fDim; ++i) {
00418 volume *= (binEdges.second[i] - binEdges.first[i]);
00419 }
00420 return volume;
00421 }
00422 this->Warning("GetBinVolume", "No such bin. Returning 0.");
00423 this->Info("GetBinVolume", "'bin' is between 0 and %d.", fNBins - 1);
00424 return 0.;
00425 }
00426
00427 const double * TKDTreeBinning::GetOneDimBinEdges() const {
00428
00429
00430 if (fDim == 1) {
00431
00432 return &fBinMinEdges.front();
00433 }
00434 this->Warning("GetOneDimBinEdges", "Data is multidimensional. No sorted bin edges retrieved. Returning null pointer.");
00435 this->Info("GetOneDimBinEdges", "This method can only be invoked if the data is a one dimensional set");
00436 return 0;
00437 }
00438
00439 const Double_t* TKDTreeBinning::GetBinCenter(UInt_t bin) const {
00440
00441 if(bin < fNBins) {
00442 Double_t* result = new Double_t[fDim];
00443 std::pair<const Double_t*, const Double_t*> binEdges = GetBinEdges(bin);
00444 for (UInt_t i = 0; i < fDim; ++i) {
00445 result[i] = (binEdges.second[i] + binEdges.first[i]) / 2.;
00446 }
00447 return result;
00448 }
00449 this->Warning("GetBinCenter", "No such bin. Returning null pointer.");
00450 this->Info("GetBinCenter", "'bin' is between 0 and %d.", fNBins - 1);
00451 return 0;
00452 }
00453
00454 const Double_t* TKDTreeBinning::GetBinWidth(UInt_t bin) const {
00455
00456 if(bin < fNBins) {
00457 Double_t* result = new Double_t[fDim];
00458 std::pair<const Double_t*, const Double_t*> binEdges = GetBinEdges(bin);
00459 for (UInt_t i = 0; i < fDim; ++i) {
00460 result[i] = (binEdges.second[i] - binEdges.first[i]);
00461 }
00462 return result;
00463 }
00464 this->Warning("GetBinWidth", "No such bin. Returning null pointer.");
00465 this->Info("GetBinWidth", "'bin' is between 0 and %d.", fNBins - 1);
00466 return 0;
00467 }
00468
00469 UInt_t TKDTreeBinning::GetBinMaxDensity() const {
00470
00471 if (fIsSorted) {
00472 if (fIsSortedAsc)
00473 return fNBins - 1;
00474 else return 0;
00475 }
00476 UInt_t* indices = new UInt_t[fNBins];
00477 for (UInt_t i = 0; i < fNBins; ++i)
00478 indices[i] = i;
00479 UInt_t result = *std::max_element(indices, indices + fNBins, CompareAsc(this));
00480 delete [] indices;
00481 return result;
00482 }
00483
00484 UInt_t TKDTreeBinning::GetBinMinDensity() const {
00485
00486 if (fIsSorted) {
00487 if (!fIsSortedAsc)
00488 return fNBins - 1;
00489 else return 0;
00490 }
00491 UInt_t* indices = new UInt_t[fNBins];
00492 for (UInt_t i = 0; i < fNBins; ++i)
00493 indices[i] = i;
00494 UInt_t result = *std::min_element(indices, indices + fNBins, CompareAsc(this));
00495 delete [] indices;
00496 return result;
00497 }
00498
00499 void TKDTreeBinning::FillBinData(ROOT::Fit::BinData & data) const {
00500
00501 data.Initialize(fNBins, fDim);
00502 for (unsigned int i = 0; i < fNBins; ++i) {
00503 data.Add( GetBinMinEdges(i), GetBinDensity(i), std::sqrt(double(GetBinContent(i) ))/ GetBinVolume(i) );
00504 data.AddBinUpEdge(GetBinMaxEdges(i) );
00505 }
00506 }