26 class THnSparseBinIter:
public ROOT::Internal::THnBaseBinIter {
28 THnSparseBinIter(Bool_t respectAxisRange,
const THnSparse* hist):
29 ROOT::Internal::THnBaseBinIter(respectAxisRange), fHist(hist),
30 fNbins(hist->GetNbins()), fIndex(-1) {
32 fCoord =
new Int_t[hist->GetNdimensions()];
35 virtual ~THnSparseBinIter() {
delete [] fCoord; }
37 virtual Int_t GetCoord(Int_t dim)
const;
38 virtual Long64_t Next(Int_t* coord = 0);
41 THnSparseBinIter(
const THnSparseBinIter&);
42 THnSparseBinIter& operator=(
const THnSparseBinIter&);
44 const THnSparse* fHist;
51 Int_t THnSparseBinIter::GetCoord(Int_t dim)
const
53 if (fCoord[0] == -1) {
54 fHist->GetBinContent(fIndex, fCoord);
59 Long64_t THnSparseBinIter::Next(Int_t* coord )
64 if (!fHist)
return -1;
67 Int_t* useCoordBuf = fCoord;
75 if (fIndex >= fHist->GetNbins()) {
79 if (RespectsAxisRange()) {
80 fHist->GetBinContent(fIndex, useCoordBuf);
82 }
while (RespectsAxisRange()
83 && !fHist->IsInRange(useCoordBuf)
84 && (fHaveSkippedBin = kTRUE ));
86 if (coord && coord[0] == -1) {
87 if (fCoord[0] == -1) {
88 fHist->GetBinContent(fIndex, coord);
90 memcpy(coord, fCoord, fHist->GetNdimensions() *
sizeof(Int_t));
113 class THnSparseCoordCompression {
115 THnSparseCoordCompression(Int_t dim,
const Int_t* nbins);
116 THnSparseCoordCompression(
const THnSparseCoordCompression& other);
117 ~THnSparseCoordCompression();
119 THnSparseCoordCompression& operator=(
const THnSparseCoordCompression& other);
121 ULong64_t GetHashFromBuffer(
const Char_t* buf)
const;
122 Int_t GetBufferSize()
const {
return fCoordBufferSize; }
123 Int_t GetNdimensions()
const {
return fNdimensions; }
124 void SetCoordFromBuffer(
const Char_t* buf_in, Int_t* coord_out)
const;
125 ULong64_t SetBufferFromCoord(
const Int_t* coord_in, Char_t* buf_out)
const;
128 Int_t GetNumBits(Int_t n)
const {
136 Int_t fCoordBufferSize;
150 THnSparseCoordCompression::THnSparseCoordCompression(Int_t dim,
const Int_t* nbins):
151 fNdimensions(dim), fCoordBufferSize(0), fBitOffsets(0)
153 fBitOffsets =
new Int_t[dim + 1];
156 for (Int_t i = 0; i < dim; ++i) {
157 fBitOffsets[i] = shift;
158 shift += GetNumBits(nbins[i] + 2);
160 fBitOffsets[dim] = shift;
161 fCoordBufferSize = (shift + 7) / 8;
168 THnSparseCoordCompression::THnSparseCoordCompression(
const THnSparseCoordCompression& other)
170 fNdimensions = other.fNdimensions;
171 fCoordBufferSize = other.fCoordBufferSize;
172 fBitOffsets =
new Int_t[fNdimensions + 1];
173 memcpy(fBitOffsets, other.fBitOffsets,
sizeof(Int_t) * fNdimensions);
180 THnSparseCoordCompression& THnSparseCoordCompression::operator=(
const THnSparseCoordCompression& other)
182 if (&other ==
this)
return *
this;
184 fNdimensions = other.fNdimensions;
185 fCoordBufferSize = other.fCoordBufferSize;
186 delete [] fBitOffsets;
187 fBitOffsets =
new Int_t[fNdimensions + 1];
188 memcpy(fBitOffsets, other.fBitOffsets,
sizeof(Int_t) * fNdimensions);
196 THnSparseCoordCompression::~THnSparseCoordCompression()
198 delete [] fBitOffsets;
206 void THnSparseCoordCompression::SetCoordFromBuffer(
const Char_t* buf_in,
207 Int_t* coord_out)
const
209 for (Int_t i = 0; i < fNdimensions; ++i) {
210 const Int_t offset = fBitOffsets[i] / 8;
211 Int_t shift = fBitOffsets[i] % 8;
212 Int_t nbits = fBitOffsets[i + 1] - fBitOffsets[i];
213 const UChar_t* pbuf = (
const UChar_t*) buf_in + offset;
214 coord_out[i] = *pbuf >> shift;
215 Int_t subst = (Int_t) -1;
216 subst = subst << nbits;
217 nbits -= (8 - shift);
219 for (Int_t n = 0; n * 8 < nbits; ++n) {
221 coord_out[i] += *pbuf << shift;
224 coord_out[i] &= ~subst;
234 ULong64_t THnSparseCoordCompression::SetBufferFromCoord(
const Int_t* coord_in,
235 Char_t* buf_out)
const
237 if (fCoordBufferSize <= 8) {
238 ULong64_t l64buf = 0;
239 for (Int_t i = 0; i < fNdimensions; ++i) {
240 l64buf += ((ULong64_t)((UInt_t)coord_in[i])) << fBitOffsets[i];
242 memcpy(buf_out, &l64buf,
sizeof(Long64_t));
247 memset(buf_out, 0, fCoordBufferSize);
248 for (Int_t i = 0; i < fNdimensions; ++i) {
249 const Int_t offset = fBitOffsets[i] / 8;
250 const Int_t shift = fBitOffsets[i] % 8;
251 ULong64_t val = coord_in[i];
253 Char_t* pbuf = buf_out + offset;
254 *pbuf += 0xff & (val << shift);
255 val = val >> (8 - shift);
263 return GetHashFromBuffer(buf_out);
270 ULong64_t THnSparseCoordCompression::GetHashFromCoords(const Int_t* coord) const
272 // Bins are addressed in two different modes, depending
273 // on whether the compact bin index fits into a Long64_t or not.
274 // If it does, we can use it as a "perfect hash" for the TExMap.
275 // If not we build a hash from the compact bin index, and use that
276 // as the TExMap's hash.
278 if (fCoordBufferSize <= 8) {
279 // fits into a Long64_t
281 for (Int_t i = 0; i < fNdimensions; ++i) {
282 hash1 += coord[i] << fBitOffsets[i];
287 // else: doesn't fit into a Long64_t:
288 memset(coord, 0, fCoordBufferSize);
289 for (Int_t i = 0; i < fNdimensions; ++i) {
290 const Int_t offset = fBitOffsets[i] / 8;
291 const Int_t shift = fBitOffsets[i] % 8;
292 ULong64_t val = coord[i];
294 Char_t* pbuf = fCoordBuffer + offset;
295 *pbuf += 0xff & (val << shift);
296 val = val >> (8 - shift);
304 ULong64_t hash = 5381;
305 Char_t* str = fCoordBuffer;
306 while (str - fCoordBuffer < fCoordBufferSize) {
318 ULong64_t THnSparseCoordCompression::GetHashFromBuffer(
const Char_t* buf)
const
326 if (fCoordBufferSize <= 8) {
329 memcpy(&hash1, buf, fCoordBufferSize);
334 ULong64_t hash = 5381;
335 const Char_t* str = buf;
336 while (str - buf < fCoordBufferSize) {
352 class THnSparseCompactBinCoord:
public THnSparseCoordCompression {
354 THnSparseCompactBinCoord(Int_t dim,
const Int_t* nbins);
355 ~THnSparseCompactBinCoord();
356 Int_t* GetCoord() {
return fCurrentBin; }
357 const Char_t* GetBuffer()
const {
return fCoordBuffer; }
358 ULong64_t GetHash()
const {
return fHash; }
360 fHash = SetBufferFromCoord(fCurrentBin, fCoordBuffer);
362 void SetCoord(
const Int_t* coord) {
363 memcpy(fCurrentBin, coord,
sizeof(Int_t) * GetNdimensions());
364 fHash = SetBufferFromCoord(coord, fCoordBuffer);
366 void SetBuffer(
const Char_t* buf) {
367 memcpy(fCoordBuffer, buf, GetBufferSize());
368 fHash = GetHashFromBuffer(fCoordBuffer);
373 THnSparseCompactBinCoord(
const THnSparseCompactBinCoord&);
375 THnSparseCompactBinCoord& operator=(
const THnSparseCompactBinCoord&);
379 Char_t *fCoordBuffer;
392 THnSparseCompactBinCoord::THnSparseCompactBinCoord(Int_t dim,
const Int_t* nbins):
393 THnSparseCoordCompression(dim, nbins),
394 fHash(0), fCoordBuffer(0), fCurrentBin(0)
396 fCurrentBin =
new Int_t[dim];
397 size_t bufAllocSize = GetBufferSize();
398 if (bufAllocSize <
sizeof(Long64_t))
399 bufAllocSize =
sizeof(Long64_t);
400 fCoordBuffer =
new Char_t[bufAllocSize];
407 THnSparseCompactBinCoord::~THnSparseCompactBinCoord()
409 delete [] fCoordBuffer;
410 delete [] fCurrentBin;
422 ClassImp(THnSparseArrayChunk);
428 THnSparseArrayChunk::THnSparseArrayChunk(Int_t coordsize,
bool errors, TArray* cont):
429 fCoordinateAllocationSize(-1), fSingleCoordinateSize(coordsize), fCoordinatesSize(0),
430 fCoordinates(0), fContent(cont),
433 fCoordinateAllocationSize = fSingleCoordinateSize * cont->GetSize();
434 fCoordinates =
new Char_t[fCoordinateAllocationSize];
441 THnSparseArrayChunk::~THnSparseArrayChunk()
444 delete [] fCoordinates;
451 void THnSparseArrayChunk::AddBin(Int_t idx,
const Char_t* coordbuf)
462 if (fCoordinateAllocationSize == -1 && fContent) {
463 Int_t chunksize = fSingleCoordinateSize * fContent->GetSize();
464 if (fCoordinatesSize < chunksize) {
466 Char_t *newcoord =
new Char_t[chunksize];
467 memcpy(newcoord, fCoordinates, fCoordinatesSize);
468 delete [] fCoordinates;
469 fCoordinates = newcoord;
471 fCoordinateAllocationSize = chunksize;
474 memcpy(fCoordinates + idx * fSingleCoordinateSize, coordbuf, fSingleCoordinateSize);
475 fCoordinatesSize += fSingleCoordinateSize;
481 void THnSparseArrayChunk::Sumw2()
484 fSumw2 =
new TArrayD(fContent->GetSize());
486 for (Int_t bin=0; bin < fContent->GetSize(); bin++) {
487 fSumw2->fArray[bin] = fContent->GetAt(bin);
590 THnSparse::THnSparse():
591 fChunkSize(1024), fFilledBins(0), fCompactCoord(0)
593 fBinContent.SetOwner();
604 THnSparse::THnSparse(
const char* name,
const char* title, Int_t dim,
605 const Int_t* nbins,
const Double_t* xmin,
const Double_t* xmax,
607 THnBase(name, title, dim, nbins, xmin, xmax),
608 fChunkSize(chunksize), fFilledBins(0), fCompactCoord(0)
610 fCompactCoord =
new THnSparseCompactBinCoord(dim, nbins);
611 fBinContent.SetOwner();
617 THnSparse::~THnSparse() {
618 delete fCompactCoord;
624 void THnSparse::AddBinContent(Long64_t bin, Double_t v)
626 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
628 v += chunk->fContent->GetAt(bin);
629 return chunk->fContent->SetAt(v, bin);
635 THnSparseArrayChunk* THnSparse::AddChunk()
637 THnSparseArrayChunk* chunk =
638 new THnSparseArrayChunk(GetCompactCoord()->GetBufferSize(),
639 GetCalculateErrors(), GenerateArray());
640 fBinContent.AddLast(chunk);
647 void THnSparse::InitStorage(Int_t* nbins, Int_t chunkSize)
649 fChunkSize = chunkSize;
650 fCompactCoord =
new THnSparseCompactBinCoord(fNdimensions, nbins);
656 void THnSparse::FillExMap()
658 TIter iChunk(&fBinContent);
659 THnSparseArrayChunk* chunk = 0;
660 THnSparseCoordCompression compactCoord(*GetCompactCoord());
662 if (2 * GetNbins() > fBins.Capacity())
663 fBins.Expand(3 * GetNbins());
664 while ((chunk = (THnSparseArrayChunk*) iChunk())) {
665 const Int_t chunkSize = chunk->GetEntries();
666 Char_t* buf = chunk->fCoordinates;
667 const Int_t singleCoordSize = chunk->fSingleCoordinateSize;
668 const Char_t* endbuf = buf + singleCoordSize * chunkSize;
669 for (; buf < endbuf; buf += singleCoordSize, ++idx) {
670 Long64_t hash = compactCoord.GetHashFromBuffer(buf);
671 Long64_t linidx = fBins.GetValue(hash);
673 Long64_t nextidx = linidx;
677 nextidx = fBinsContinued.GetValue(linidx);
679 fBinsContinued.Add(linidx, idx + 1);
681 fBins.Add(hash, idx + 1);
690 void THnSparse::Reserve(Long64_t nbins) {
691 if (!fBins.GetSize() && fBinContent.GetSize()) {
694 if (2 * nbins > fBins.Capacity()) {
695 fBins.Expand(3 * nbins);
703 Long64_t THnSparse::GetBin(
const Double_t* x, Bool_t allocate )
705 THnSparseCompactBinCoord* cc = GetCompactCoord();
706 Int_t *coord = cc->GetCoord();
707 for (Int_t i = 0; i < fNdimensions; ++i)
708 coord[i] = GetAxis(i)->FindBin(x[i]);
711 return GetBinIndexForCurrentBin(allocate);
719 Long64_t THnSparse::GetBin(
const char* name[], Bool_t allocate )
721 THnSparseCompactBinCoord* cc = GetCompactCoord();
722 Int_t *coord = cc->GetCoord();
723 for (Int_t i = 0; i < fNdimensions; ++i)
724 coord[i] = GetAxis(i)->FindBin(name[i]);
727 return GetBinIndexForCurrentBin(allocate);
734 Long64_t THnSparse::GetBin(
const Int_t* coord, Bool_t allocate )
736 GetCompactCoord()->SetCoord(coord);
737 return GetBinIndexForCurrentBin(allocate);
745 Double_t THnSparse::GetBinContent(Long64_t idx, Int_t* coord )
const
748 THnSparseArrayChunk* chunk = GetChunk(idx / fChunkSize);
750 if (chunk && chunk->fContent->GetSize() > idx) {
752 THnSparseCompactBinCoord* cc = GetCompactCoord();
753 Int_t sizeCompact = cc->GetBufferSize();
754 cc->SetCoordFromBuffer(chunk->fCoordinates + idx * sizeCompact,
758 return chunk->fContent->GetAt(idx);
762 memset(coord, -1,
sizeof(Int_t) * fNdimensions);
772 Double_t THnSparse::GetBinError2(Long64_t linidx)
const {
773 if (!GetCalculateErrors())
774 return GetBinContent(linidx);
776 if (linidx < 0)
return 0.;
777 THnSparseArrayChunk* chunk = GetChunk(linidx / fChunkSize);
778 linidx %= fChunkSize;
779 if (!chunk || chunk->fContent->GetSize() < linidx)
782 return chunk->fSumw2->GetAt(linidx);
790 Long64_t THnSparse::GetBinIndexForCurrentBin(Bool_t allocate)
792 THnSparseCompactBinCoord* cc = GetCompactCoord();
793 ULong64_t hash = cc->GetHash();
794 if (fBinContent.GetSize() && !fBins.GetSize())
796 Long64_t linidx = (Long64_t) fBins.GetValue(hash);
799 THnSparseArrayChunk* chunk = GetChunk((linidx - 1)/ fChunkSize);
800 if (chunk->Matches((linidx - 1) % fChunkSize, cc->GetBuffer()))
803 Long64_t nextlinidx = fBinsContinued.GetValue(linidx);
804 if (!nextlinidx)
break;
808 if (!allocate)
return -1;
813 THnSparseArrayChunk *chunk = (THnSparseArrayChunk*) fBinContent.Last();
814 Long64_t newidx = chunk ? ((Long64_t) chunk->GetEntries()) : -1;
815 if (!chunk || newidx == (Long64_t)fChunkSize) {
819 chunk->AddBin(newidx, cc->GetBuffer());
822 newidx += (fBinContent.GetEntriesFast() - 1) * fChunkSize;
825 if (2 * GetNbins() > fBins.Capacity())
826 fBins.Expand(3 * GetNbins());
827 fBins.Add(hash, newidx + 1);
831 fBinsContinued.Add(linidx, newidx + 1);
839 THnSparseCompactBinCoord* THnSparse::GetCompactCoord()
const
841 if (!fCompactCoord) {
842 Int_t *bins =
new Int_t[fNdimensions];
843 for (Int_t d = 0; d < fNdimensions; ++d)
844 bins[d] = GetAxis(d)->GetNbins();
845 const_cast<THnSparse*
>(
this)->fCompactCoord
846 =
new THnSparseCompactBinCoord(fNdimensions, bins);
849 return fCompactCoord;
855 Double_t THnSparse::GetSparseFractionBins()
const {
856 Double_t nbinsTotal = 1.;
857 for (Int_t d = 0; d < fNdimensions; ++d)
858 nbinsTotal *= GetAxis(d)->GetNbins() + 2;
859 return fFilledBins / nbinsTotal;
866 Double_t THnSparse::GetSparseFractionMem()
const {
867 Int_t arrayElementSize = 0;
869 TClass* clArray = GetChunk(0)->fContent->IsA();
870 TDataMember* dm = clArray ? clArray->GetDataMember(
"fArray") : 0;
871 arrayElementSize = dm ? dm->GetDataType()->Size() : 0;
873 if (!arrayElementSize) {
874 Warning(
"GetSparseFractionMem",
"Cannot determine type of elements!");
878 Double_t sizePerChunkElement = arrayElementSize + GetCompactCoord()->GetBufferSize();
879 if (fFilledBins && GetChunk(0)->fSumw2)
880 sizePerChunkElement +=
sizeof(Double_t);
883 size += fBinContent.GetEntries() * (GetChunkSize() * sizePerChunkElement +
sizeof(THnSparseArrayChunk));
884 size += + 3 *
sizeof(Long64_t) * fBins.GetSize() ;
886 Double_t nbinsTotal = 1.;
887 for (Int_t d = 0; d < fNdimensions; ++d)
888 nbinsTotal *= GetAxis(d)->GetNbins() + 2;
890 return size / nbinsTotal / arrayElementSize;
897 ROOT::Internal::THnBaseBinIter* THnSparse::CreateIter(Bool_t respectAxisRange)
const
899 return new THnSparseBinIter(respectAxisRange,
this);
905 void THnSparse::SetBinContent(Long64_t bin, Double_t v)
907 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
908 chunk->fContent->SetAt(v, bin % fChunkSize);
915 void THnSparse::SetBinError2(Long64_t bin, Double_t e2)
917 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
918 if (!chunk->fSumw2 ) {
920 if (GetCalculateErrors()) {
921 Error(
"SetBinError",
"GetCalculateErrors() logic error!");
926 chunk->fSumw2->SetAt(e2, bin % fChunkSize);
932 void THnSparse::AddBinError2(Long64_t bin, Double_t e2)
934 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
935 if (!chunk->fSumw2 ) {
937 if (GetCalculateErrors()) {
938 Error(
"SetBinError",
"GetCalculateErrors() logic error!");
943 (*chunk->fSumw2)[bin % fChunkSize] += e2;
949 void THnSparse::Sumw2()
951 if (GetCalculateErrors())
return;
954 TIter iChunk(&fBinContent);
955 THnSparseArrayChunk* chunk = 0;
956 while ((chunk = (THnSparseArrayChunk*) iChunk()))
963 void THnSparse::Reset(Option_t *option )
967 fBinsContinued.Clear();
968 fBinContent.Delete();