ROOT  6.06/09
Reference Guide
THnSparse.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Axel Naumann (2007-09-11)
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "THnSparse.h"
13 
14 #include "TAxis.h"
15 #include "TClass.h"
16 #include "TDataMember.h"
17 #include "TDataType.h"
18 
19 namespace {
20 //______________________________________________________________________________
21 //
22 // THnSparseBinIter iterates over all filled bins of a THnSparse.
23 //______________________________________________________________________________
24 
25  class THnSparseBinIter: public ROOT::Internal::THnBaseBinIter {
26  public:
27  THnSparseBinIter(Bool_t respectAxisRange, const THnSparse* hist):
28  ROOT::Internal::THnBaseBinIter(respectAxisRange), fHist(hist),
29  fNbins(hist->GetNbins()), fIndex(-1) {
30  // Construct a THnSparseBinIter
31  fCoord = new Int_t[hist->GetNdimensions()];
32  fCoord[0] = -1;
33  }
34  virtual ~THnSparseBinIter() { delete [] fCoord; }
35 
36  virtual Int_t GetCoord(Int_t dim) const;
37  virtual Long64_t Next(Int_t* coord = 0);
38 
39  private:
40  THnSparseBinIter(const THnSparseBinIter&); // intentionally unimplemented
41  THnSparseBinIter& operator=(const THnSparseBinIter&); // intentionally unimplemented
42 
43  const THnSparse* fHist;
44  Int_t* fCoord; // coord buffer for fIndex; fCoord[0] == -1 if not yet calculated
45  Long64_t fNbins; // number of bins to iterate over
46  Long64_t fIndex; // current bin index
47  };
48 }
49 
50 Int_t THnSparseBinIter::GetCoord(Int_t dim) const
51 {
52  if (fCoord[0] == -1) {
53  fHist->GetBinContent(fIndex, fCoord);
54  }
55  return fCoord[dim];
56 }
57 
58 Long64_t THnSparseBinIter::Next(Int_t* coord /*= 0*/)
59 {
60  // Get next bin index (in range if RespectsAxisRange()).
61  // If coords != 0, set it to the index's axis coordinates
62  // (i.e. coord must point to an array of Int_t[fNdimension]
63  if (!fHist) return -1;
64 
65  fCoord[0] = -1;
66  Int_t* useCoordBuf = fCoord;
67  if (coord) {
68  useCoordBuf = coord;
69  coord[0] = -1;
70  }
71 
72  do {
73  ++fIndex;
74  if (fIndex >= fHist->GetNbins()) {
75  fHist = 0;
76  return -1;
77  }
78  if (RespectsAxisRange()) {
79  fHist->GetBinContent(fIndex, useCoordBuf);
80  }
81  } while (RespectsAxisRange()
82  && !fHist->IsInRange(useCoordBuf)
83  && (fHaveSkippedBin = kTRUE /* assignment! */));
84 
85  if (coord && coord[0] == -1) {
86  if (fCoord[0] == -1) {
87  fHist->GetBinContent(fIndex, coord);
88  } else {
89  memcpy(coord, fCoord, fHist->GetNdimensions() * sizeof(Int_t));
90  }
91  }
92 
93  return fIndex;
94 }
95 
96 
97 
98 /** \class THnSparseCoordCompression
99 THnSparseCoordCompression is a class used by THnSparse internally. It
100 represents a compacted n-dimensional array of bin coordinates (indices).
101 As the total number of bins in each dimension is known by THnSparse, bin
102 indices can be compacted to only use the amount of bins needed by the total
103 number of bins in each dimension. E.g. for a THnSparse with
104 {15, 100, 2, 20, 10, 100} bins per dimension, a bin index will only occupy
105 28 bits (4+7+1+5+4+7), i.e. less than a 32bit integer. The tricky part is
106 the fast compression and decompression, the platform-independent storage
107 (think of endianness: the bits of the number 0x123456 depend on the
108 platform), and the hashing needed by THnSparseArrayChunk.
109 */
110 
111 
112 class THnSparseCoordCompression {
113 public:
114  THnSparseCoordCompression(Int_t dim, const Int_t* nbins);
115  THnSparseCoordCompression(const THnSparseCoordCompression& other);
116  ~THnSparseCoordCompression();
117 
118  THnSparseCoordCompression& operator=(const THnSparseCoordCompression& other);
119 
120  ULong64_t GetHashFromBuffer(const Char_t* buf) const;
121  Int_t GetBufferSize() const { return fCoordBufferSize; }
122  Int_t GetNdimensions() const { return fNdimensions; }
123  void SetCoordFromBuffer(const Char_t* buf_in, Int_t* coord_out) const;
124  ULong64_t SetBufferFromCoord(const Int_t* coord_in, Char_t* buf_out) const;
125 
126 protected:
127  Int_t GetNumBits(Int_t n) const {
128  // return the number of bits allocated by the number "n"
129  Int_t r = (n > 0);
130  while (n/=2) ++r;
131  return r;
132  }
133 private:
134  Int_t fNdimensions; // number of dimensions
135  Int_t fCoordBufferSize; // size of coordbuf
136  Int_t *fBitOffsets; //[fNdimensions + 1] bit offset of each axis index
137 };
138 
139 
140 //______________________________________________________________________________
141 //______________________________________________________________________________
142 
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// Initialize a THnSparseCoordCompression object with "dim" dimensions
146 /// and "bins" holding the number of bins for each dimension; it
147 /// stores the
148 
149 THnSparseCoordCompression::THnSparseCoordCompression(Int_t dim, const Int_t* nbins):
150  fNdimensions(dim), fCoordBufferSize(0), fBitOffsets(0)
151 {
152  fBitOffsets = new Int_t[dim + 1];
153 
154  int shift = 0;
155  for (Int_t i = 0; i < dim; ++i) {
156  fBitOffsets[i] = shift;
157  shift += GetNumBits(nbins[i] + 2);
158  }
159  fBitOffsets[dim] = shift;
160  fCoordBufferSize = (shift + 7) / 8;
161 }
162 
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Construct a THnSparseCoordCompression from another one
166 
167 THnSparseCoordCompression::THnSparseCoordCompression(const THnSparseCoordCompression& other)
168 {
169  fNdimensions = other.fNdimensions;
170  fCoordBufferSize = other.fCoordBufferSize;
171  fBitOffsets = new Int_t[fNdimensions + 1];
172  memcpy(fBitOffsets, other.fBitOffsets, sizeof(Int_t) * fNdimensions);
173 }
174 
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Set this to other if different.
178 
179 THnSparseCoordCompression& THnSparseCoordCompression::operator=(const THnSparseCoordCompression& other)
180 {
181  if (&other == this) return *this;
182 
183  fNdimensions = other.fNdimensions;
184  fCoordBufferSize = other.fCoordBufferSize;
185  delete [] fBitOffsets;
186  fBitOffsets = new Int_t[fNdimensions + 1];
187  memcpy(fBitOffsets, other.fBitOffsets, sizeof(Int_t) * fNdimensions);
188  return *this;
189 }
190 
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// destruct a THnSparseCoordCompression
194 
195 THnSparseCoordCompression::~THnSparseCoordCompression()
196 {
197  delete [] fBitOffsets;
198 }
199 
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 /// Given the compressed coordinate buffer buf_in, calculate ("decompact")
203 /// the bin coordinates and return them in coord_out.
204 
205 void THnSparseCoordCompression::SetCoordFromBuffer(const Char_t* buf_in,
206  Int_t* coord_out) const
207 {
208  for (Int_t i = 0; i < fNdimensions; ++i) {
209  const Int_t offset = fBitOffsets[i] / 8;
210  Int_t shift = fBitOffsets[i] % 8;
211  Int_t nbits = fBitOffsets[i + 1] - fBitOffsets[i];
212  const UChar_t* pbuf = (const UChar_t*) buf_in + offset;
213  coord_out[i] = *pbuf >> shift;
214  Int_t subst = (Int_t) -1;
215  subst = subst << nbits;
216  nbits -= (8 - shift);
217  shift = 8 - shift;
218  for (Int_t n = 0; n * 8 < nbits; ++n) {
219  ++pbuf;
220  coord_out[i] += *pbuf << shift;
221  shift += 8;
222  }
223  coord_out[i] &= ~subst;
224  }
225 }
226 
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 /// Given the cbin coordinates coord_in, calculate ("compact")
230 /// the bin coordinates and return them in buf_in.
231 /// Return the hash value.
232 
233 ULong64_t THnSparseCoordCompression::SetBufferFromCoord(const Int_t* coord_in,
234  Char_t* buf_out) const
235 {
236  if (fCoordBufferSize <= 8) {
237  ULong64_t l64buf = 0;
238  for (Int_t i = 0; i < fNdimensions; ++i) {
239  l64buf += ((ULong64_t)((UInt_t)coord_in[i])) << fBitOffsets[i];
240  }
241  memcpy(buf_out, &l64buf, sizeof(Long64_t));
242  return l64buf;
243  }
244 
245  // else: doesn't fit into a Long64_t:
246  memset(buf_out, 0, fCoordBufferSize);
247  for (Int_t i = 0; i < fNdimensions; ++i) {
248  const Int_t offset = fBitOffsets[i] / 8;
249  const Int_t shift = fBitOffsets[i] % 8;
250  ULong64_t val = coord_in[i];
251 
252  Char_t* pbuf = buf_out + offset;
253  *pbuf += 0xff & (val << shift);
254  val = val >> (8 - shift);
255  while (val) {
256  ++pbuf;
257  *pbuf += 0xff & val;
258  val = val >> 8;
259  }
260  }
261 
262  return GetHashFromBuffer(buf_out);
263 }
264 
265 /*
266 ////////////////////////////////////////////////////////////////////////////////
267 /// Calculate hash from bin indexes.
268 
269 ULong64_t THnSparseCoordCompression::GetHashFromCoords(const Int_t* coord) const
270 {
271  // Bins are addressed in two different modes, depending
272  // on whether the compact bin index fits into a Long64_t or not.
273  // If it does, we can use it as a "perfect hash" for the TExMap.
274  // If not we build a hash from the compact bin index, and use that
275  // as the TExMap's hash.
276 
277  if (fCoordBufferSize <= 8) {
278  // fits into a Long64_t
279  ULong64_t hash1 = 0;
280  for (Int_t i = 0; i < fNdimensions; ++i) {
281  hash1 += coord[i] << fBitOffsets[i];
282  }
283  return hash1;
284  }
285 
286  // else: doesn't fit into a Long64_t:
287  memset(coord, 0, fCoordBufferSize);
288  for (Int_t i = 0; i < fNdimensions; ++i) {
289  const Int_t offset = fBitOffsets[i] / 8;
290  const Int_t shift = fBitOffsets[i] % 8;
291  ULong64_t val = coord[i];
292 
293  Char_t* pbuf = fCoordBuffer + offset;
294  *pbuf += 0xff & (val << shift);
295  val = val >> (8 - shift);
296  while (val) {
297  ++pbuf;
298  *pbuf += 0xff & val;
299  val = val >> 8;
300  }
301  }
302 
303  ULong64_t hash = 5381;
304  Char_t* str = fCoordBuffer;
305  while (str - fCoordBuffer < fCoordBufferSize) {
306  hash *= 5;
307  hash += *(str++);
308  }
309  return hash;
310 }
311 */
312 
313 
314 ////////////////////////////////////////////////////////////////////////////////
315 /// Calculate hash from compact bin index.
316 
317 ULong64_t THnSparseCoordCompression::GetHashFromBuffer(const Char_t* buf) const
318 {
319  // Bins are addressed in two different modes, depending
320  // on whether the compact bin index fits into a Long64_t or not.
321  // If it does, we can use it as a "perfect hash" for the TExMap.
322  // If not we build a hash from the compact bin index, and use that
323  // as the TExMap's hash.
324 
325  if (fCoordBufferSize <= 8) {
326  // fits into a Long64_t
327  ULong64_t hash1 = 0;
328  memcpy(&hash1, buf, fCoordBufferSize);
329  return hash1;
330  }
331 
332  // else: doesn't fit into a Long64_t:
333  ULong64_t hash = 5381;
334  const Char_t* str = buf;
335  while (str - buf < fCoordBufferSize) {
336  hash *= 5;
337  hash += *(str++);
338  }
339  return hash;
340 }
341 
342 
343 
344 
345 /** \class THnSparseCompactBinCoord
346 THnSparseCompactBinCoord is a class used by THnSparse internally. It
347 maps between an n-dimensional array of bin coordinates (indices) and
348 its compact version, the THnSparseCoordCompression.
349 */
350 
351 class THnSparseCompactBinCoord: public THnSparseCoordCompression {
352 public:
353  THnSparseCompactBinCoord(Int_t dim, const Int_t* nbins);
354  ~THnSparseCompactBinCoord();
355  Int_t* GetCoord() { return fCurrentBin; }
356  const Char_t* GetBuffer() const { return fCoordBuffer; }
357  ULong64_t GetHash() const { return fHash; }
358  void UpdateCoord() {
359  fHash = SetBufferFromCoord(fCurrentBin, fCoordBuffer);
360  }
361  void SetCoord(const Int_t* coord) {
362  memcpy(fCurrentBin, coord, sizeof(Int_t) * GetNdimensions());
363  fHash = SetBufferFromCoord(coord, fCoordBuffer);
364  }
365  void SetBuffer(const Char_t* buf) {
366  memcpy(fCoordBuffer, buf, GetBufferSize());
367  fHash = GetHashFromBuffer(fCoordBuffer);
368  }
369 
370 private:
371  // intentionally not implemented
372  THnSparseCompactBinCoord(const THnSparseCompactBinCoord&);
373  // intentionally not implemented
374  THnSparseCompactBinCoord& operator=(const THnSparseCompactBinCoord&);
375 
376 private:
377  ULong64_t fHash; // hash for current coordinates; 0 if not calculated
378  Char_t *fCoordBuffer; // compact buffer of coordinates
379  Int_t *fCurrentBin; // current coordinates
380 };
381 
382 
383 //______________________________________________________________________________
384 //______________________________________________________________________________
385 
386 
387 ////////////////////////////////////////////////////////////////////////////////
388 /// Initialize a THnSparseCompactBinCoord object with "dim" dimensions
389 /// and "bins" holding the number of bins for each dimension.
390 
391 THnSparseCompactBinCoord::THnSparseCompactBinCoord(Int_t dim, const Int_t* nbins):
392  THnSparseCoordCompression(dim, nbins),
393  fHash(0), fCoordBuffer(0), fCurrentBin(0)
394 {
395  fCurrentBin = new Int_t[dim];
396  size_t bufAllocSize = GetBufferSize();
397  if (bufAllocSize < sizeof(Long64_t))
398  bufAllocSize = sizeof(Long64_t);
399  fCoordBuffer = new Char_t[bufAllocSize];
400 }
401 
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 /// destruct a THnSparseCompactBinCoord
405 
406 THnSparseCompactBinCoord::~THnSparseCompactBinCoord()
407 {
408  delete [] fCoordBuffer;
409  delete [] fCurrentBin;
410 }
411 
412 /** \class THnSparseArrayChunk
413 THnSparseArrayChunk is used internally by THnSparse.
414 THnSparse stores its (dynamic size) array of bin coordinates and their
415 contents (and possibly errors) in a TObjArray of THnSparseArrayChunk. Each
416 of the chunks holds an array of THnSparseCompactBinCoord and the content
417 (a TArray*), which is created outside (by the templated derived classes of
418 THnSparse) and passed in at construction time.
419 */
420 
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// (Default) initialize a chunk. Takes ownership of cont (~THnSparseArrayChunk deletes it),
425 /// and create an ArrayF for errors if "errors" is true.
426 
428  fCoordinateAllocationSize(-1), fSingleCoordinateSize(coordsize), fCoordinatesSize(0),
429  fCoordinates(0), fContent(cont),
430  fSumw2(0)
431 {
434  if (errors) Sumw2();
435 }
436 
437 ////////////////////////////////////////////////////////////////////////////////
438 /// Destructor
439 
441 {
442  delete fContent;
443  delete [] fCoordinates;
444  delete fSumw2;
445 }
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// Create a new bin in this chunk
449 
450 void THnSparseArrayChunk::AddBin(Int_t idx, const Char_t* coordbuf)
451 {
452  // When streaming out only the filled chunk is saved.
453  // When reading back only the memory needed for that filled part gets
454  // allocated. We need to check whether the allowed chunk size is
455  // bigger than the allocated size. If fCoordinateAllocationSize is
456  // set to -1 this chunk has been allocated by the streamer and the
457  // buffer allocation size is defined by [fCoordinatesSize]. In that
458  // case we need to compare fCoordinatesSize to
459  // fSingleCoordinateSize * fContent->GetSize()
460  // to determine whether we need to expand the buffer.
461  if (fCoordinateAllocationSize == -1 && fContent) {
462  Int_t chunksize = fSingleCoordinateSize * fContent->GetSize();
463  if (fCoordinatesSize < chunksize) {
464  // need to re-allocate:
465  Char_t *newcoord = new Char_t[chunksize];
466  memcpy(newcoord, fCoordinates, fCoordinatesSize);
467  delete [] fCoordinates;
468  fCoordinates = newcoord;
469  }
470  fCoordinateAllocationSize = chunksize;
471  }
472 
473  memcpy(fCoordinates + idx * fSingleCoordinateSize, coordbuf, fSingleCoordinateSize);
475 }
476 
477 ////////////////////////////////////////////////////////////////////////////////
478 /// Turn on support of errors
479 
481 {
482  if (!fSumw2)
483  fSumw2 = new TArrayD(fContent->GetSize());
484  // fill the structure with the current content
485  for (Int_t bin=0; bin < fContent->GetSize(); bin++) {
486  fSumw2->fArray[bin] = fContent->GetAt(bin);
487  }
488 
489 }
490 
491 
492 /** \class THnSparse
493  \ingroup Hist
494 
495 Efficient multidimensional histogram.
496 
497 Use a THnSparse instead of TH1 / TH2 / TH3 / array for histogramming when
498 only a small fraction of bins is filled. A 10-dimensional histogram with 10
499 bins per dimension has 10^10 bins; in a naive implementation this will not
500 fit in memory. THnSparse only allocates memory for the bins that have
501 non-zero bin content instead, drastically reducing both the memory usage
502 and the access time.
503 
504 To construct a THnSparse object you must use one of its templated, derived
505 classes:
506 - THnSparseD (typedef for THnSparseT<ArrayD>): bin content held by a Double_t,
507 - THnSparseF (typedef for THnSparseT<ArrayF>): bin content held by a Float_t,
508 - THnSparseL (typedef for THnSparseT<ArrayL>): bin content held by a Long_t,
509 - THnSparseI (typedef for THnSparseT<ArrayI>): bin content held by an Int_t,
510 - THnSparseS (typedef for THnSparseT<ArrayS>): bin content held by a Short_t,
511 - THnSparseC (typedef for THnSparseT<ArrayC>): bin content held by a Char_t,
512 
513 They take name and title, the number of dimensions, and for each dimension
514 the number of bins, the minimal, and the maximal value on the dimension's
515 axis. A TH2 h("h","h",10, 0., 10., 20, -5., 5.) would correspond to
516 
517  Int_t bins[2] = {10, 20};
518  Double_t xmin[2] = {0., -5.};
519  Double_t xmax[2] = {10., 5.};
520  THnSparse hs("hs", "hs", 2, bins, min, max);
521 
522 ## Filling
523 A THnSparse is filled just like a regular histogram, using
524 THnSparse::Fill(x, weight), where x is a n-dimensional Double_t value.
525 To take errors into account, Sumw2() must be called before filling the
526 histogram.
527 
528 Bins are allocated as needed; the status of the allocation can be observed
529 by GetSparseFractionBins(), GetSparseFractionMem().
530 
531 ## Fast Bin Content Access
532 When iterating over a THnSparse one should only look at filled bins to save
533 processing time. The number of filled bins is returned by
534 THnSparse::GetNbins(); the bin content for each (linear) bin number can
535 be retrieved by THnSparse::GetBinContent(linidx, (Int_t*)coord).
536 After the call, coord will contain the bin coordinate of each axis for the bin
537 with linear index linidx. A possible call would be
538 
539  std::cout << hs.GetBinContent(0, coord);
540  std::cout <<" is the content of bin [x = " << coord[0] "
541  << " | y = " << coord[1] << "]" << std::endl;
542 
543 ## Efficiency
544 TH1 and TH2 are generally faster than THnSparse for one and two dimensional
545 distributions. THnSparse becomes competitive for a sparsely filled TH3
546 with large numbers of bins per dimension. The tutorial hist/sparsehist.C
547 shows the turning point. On a AMD64 with 8GB memory, THnSparse "wins"
548 starting with a TH3 with 30 bins per dimension. Using a THnSparse for a
549 one-dimensional histogram is only reasonable if it has a huge number of bins.
550 
551 ## Projections
552 The dimensionality of a THnSparse can be reduced by projecting it to
553 1, 2, 3, or n dimensions, which can be represented by a TH1, TH2, TH3, or
554 a THnSparse. See the Projection() members. To only project parts of the
555 histogram, call
556 
557  THnSparse::GetAxis(12)->SetRange(from_bin, to_bin);
558 
559 ## Internal Representation
560 An entry for a filled bin consists of its n-dimensional coordinates and
561 its bin content. The coordinates are compacted to use as few bits as
562 possible; e.g. a histogram with 10 bins in x and 20 bins in y will only
563 use 4 bits for the x representation and 5 bits for the y representation.
564 This is handled by the internal class THnSparseCompactBinCoord.
565 Bin data (content and coordinates) are allocated in chunks of size
566 fChunkSize; this parameter can be set when constructing a THnSparse. Each
567 chunk is represented by an object of class THnSparseArrayChunk.
568 
569 Translation from an n-dimensional bin coordinate to the linear index within
570 the chunks is done by GetBin(). It creates a hash from the compacted bin
571 coordinates (the hash of a bin coordinate is the compacted coordinate itself
572 if it takes less than 8 bytes, the size of a Long64_t.
573 This hash is used to lookup the linear index in the TExMap member fBins;
574 the coordinates of the entry fBins points to is compared to the coordinates
575 passed to GetBin(). If they do not match, these two coordinates have the same
576 hash - which is extremely unlikely but (for the case where the compact bin
577 coordinates are larger than 4 bytes) possible. In this case, fBinsContinued
578 contains a chain of linear indexes with the same hash. Iterating through this
579 chain and comparing each bin coordinates with the one passed to GetBin() will
580 retrieve the matching bin.
581 */
582 
583 
585 
586 ////////////////////////////////////////////////////////////////////////////////
587 /// Construct an empty THnSparse.
588 
590  fChunkSize(1024), fFilledBins(0), fCompactCoord(0)
591 {
593 }
594 
595 ////////////////////////////////////////////////////////////////////////////////
596 /// Construct a THnSparse with "dim" dimensions,
597 /// with chunksize as the size of the chunks.
598 /// "nbins" holds the number of bins for each dimension;
599 /// "xmin" and "xmax" the minimal and maximal value for each dimension.
600 /// The arrays "xmin" and "xmax" can be NULL; in that case SetBinEdges()
601 /// must be called for each dimension.
602 
603 THnSparse::THnSparse(const char* name, const char* title, Int_t dim,
604  const Int_t* nbins, const Double_t* xmin, const Double_t* xmax,
605  Int_t chunksize):
606  THnBase(name, title, dim, nbins, xmin, xmax),
607  fChunkSize(chunksize), fFilledBins(0), fCompactCoord(0)
608 {
609  fCompactCoord = new THnSparseCompactBinCoord(dim, nbins);
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 /// Destruct a THnSparse
615 
617  delete fCompactCoord;
618 }
619 
620 ////////////////////////////////////////////////////////////////////////////////
621 /// Add "v" to the content of bin with index "bin"
622 
624 {
625  THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
626  bin %= fChunkSize;
627  v += chunk->fContent->GetAt(bin);
628  return chunk->fContent->SetAt(v, bin);
629 }
630 
631 ////////////////////////////////////////////////////////////////////////////////
632 /// Create a new chunk of bin content
633 
635 {
636  THnSparseArrayChunk* chunk =
637  new THnSparseArrayChunk(GetCompactCoord()->GetBufferSize(),
639  fBinContent.AddLast(chunk);
640  return chunk;
641 }
642 
643 ////////////////////////////////////////////////////////////////////////////////
644 /// Initialize the storage of a histogram created via Init()
645 
646 void THnSparse::InitStorage(Int_t* nbins, Int_t chunkSize)
647 {
648  fChunkSize = chunkSize;
649  fCompactCoord = new THnSparseCompactBinCoord(fNdimensions, nbins);
650 }
651 
652 ////////////////////////////////////////////////////////////////////////////////
653 ///We have been streamed; set up fBins
654 
656 {
657  TIter iChunk(&fBinContent);
658  THnSparseArrayChunk* chunk = 0;
659  THnSparseCoordCompression compactCoord(*GetCompactCoord());
660  Long64_t idx = 0;
661  if (2 * GetNbins() > fBins.Capacity())
662  fBins.Expand(3 * GetNbins());
663  while ((chunk = (THnSparseArrayChunk*) iChunk())) {
664  const Int_t chunkSize = chunk->GetEntries();
665  Char_t* buf = chunk->fCoordinates;
666  const Int_t singleCoordSize = chunk->fSingleCoordinateSize;
667  const Char_t* endbuf = buf + singleCoordSize * chunkSize;
668  for (; buf < endbuf; buf += singleCoordSize, ++idx) {
669  Long64_t hash = compactCoord.GetHashFromBuffer(buf);
670  Long64_t linidx = fBins.GetValue(hash);
671  if (linidx) {
672  Long64_t nextidx = linidx;
673  while (nextidx) {
674  // must be a collision, so go to fBinsContinued.
675  linidx = nextidx;
676  nextidx = fBinsContinued.GetValue(linidx);
677  }
678  fBinsContinued.Add(linidx, idx + 1);
679  } else {
680  fBins.Add(hash, idx + 1);
681  }
682  }
683  }
684 }
685 
686 ////////////////////////////////////////////////////////////////////////////////
687 /// Initialize storage for nbins
688 
690  if (!fBins.GetSize() && fBinContent.GetSize()) {
691  FillExMap();
692  }
693  if (2 * nbins > fBins.Capacity()) {
694  fBins.Expand(3 * nbins);
695  }
696 }
697 
698 ////////////////////////////////////////////////////////////////////////////////
699 /// Get the bin index for the n dimensional tuple x,
700 /// allocate one if it doesn't exist yet and "allocate" is true.
701 
702 Long64_t THnSparse::GetBin(const Double_t* x, Bool_t allocate /* = kTRUE */)
703 {
704  THnSparseCompactBinCoord* cc = GetCompactCoord();
705  Int_t *coord = cc->GetCoord();
706  for (Int_t i = 0; i < fNdimensions; ++i)
707  coord[i] = GetAxis(i)->FindBin(x[i]);
708  cc->UpdateCoord();
709 
710  return GetBinIndexForCurrentBin(allocate);
711 }
712 
713 
714 ////////////////////////////////////////////////////////////////////////////////
715 /// Get the bin index for the n dimensional tuple addressed by "name",
716 /// allocate one if it doesn't exist yet and "allocate" is true.
717 
718 Long64_t THnSparse::GetBin(const char* name[], Bool_t allocate /* = kTRUE */)
719 {
720  THnSparseCompactBinCoord* cc = GetCompactCoord();
721  Int_t *coord = cc->GetCoord();
722  for (Int_t i = 0; i < fNdimensions; ++i)
723  coord[i] = GetAxis(i)->FindBin(name[i]);
724  cc->UpdateCoord();
725 
726  return GetBinIndexForCurrentBin(allocate);
727 }
728 
729 ////////////////////////////////////////////////////////////////////////////////
730 /// Get the bin index for the n dimensional coordinates coord,
731 /// allocate one if it doesn't exist yet and "allocate" is true.
732 
733 Long64_t THnSparse::GetBin(const Int_t* coord, Bool_t allocate /*= kTRUE*/)
734 {
735  GetCompactCoord()->SetCoord(coord);
736  return GetBinIndexForCurrentBin(allocate);
737 }
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 /// Return the content of the filled bin number "idx".
741 /// If coord is non-null, it will contain the bin's coordinates for each axis
742 /// that correspond to the bin.
743 
744 Double_t THnSparse::GetBinContent(Long64_t idx, Int_t* coord /* = 0 */) const
745 {
746  if (idx >= 0) {
747  THnSparseArrayChunk* chunk = GetChunk(idx / fChunkSize);
748  idx %= fChunkSize;
749  if (chunk && chunk->fContent->GetSize() > idx) {
750  if (coord) {
751  THnSparseCompactBinCoord* cc = GetCompactCoord();
752  Int_t sizeCompact = cc->GetBufferSize();
753  cc->SetCoordFromBuffer(chunk->fCoordinates + idx * sizeCompact,
754  coord);
755 
756  }
757  return chunk->fContent->GetAt(idx);
758  }
759  }
760  if (coord)
761  memset(coord, -1, sizeof(Int_t) * fNdimensions);
762  return 0.;
763 }
764 
765 ////////////////////////////////////////////////////////////////////////////////
766 /// Get square of the error of bin addressed by linidx as
767 /// BEGIN_LATEX #sum weight^{2}
768 /// END_LATEX
769 /// If errors are not enabled (via Sumw2() or CalculateErrors())
770 /// return contents.
771 
773  if (!GetCalculateErrors())
774  return GetBinContent(linidx);
775 
776  if (linidx < 0) return 0.;
777  THnSparseArrayChunk* chunk = GetChunk(linidx / fChunkSize);
778  linidx %= fChunkSize;
779  if (!chunk || chunk->fContent->GetSize() < linidx)
780  return 0.;
781 
782  return chunk->fSumw2->GetAt(linidx);
783 }
784 
785 
786 ////////////////////////////////////////////////////////////////////////////////
787 /// Return the index for fCurrentBinIndex.
788 /// If it doesn't exist then return -1, or allocate a new bin if allocate is set
789 
791 {
792  THnSparseCompactBinCoord* cc = GetCompactCoord();
793  ULong64_t hash = cc->GetHash();
794  if (fBinContent.GetSize() && !fBins.GetSize())
795  FillExMap();
796  Long64_t linidx = (Long64_t) fBins.GetValue(hash);
797  while (linidx) {
798  // fBins stores index + 1!
799  THnSparseArrayChunk* chunk = GetChunk((linidx - 1)/ fChunkSize);
800  if (chunk->Matches((linidx - 1) % fChunkSize, cc->GetBuffer()))
801  return linidx - 1; // we store idx+1, 0 is "TExMap: not found"
802 
803  Long64_t nextlinidx = fBinsContinued.GetValue(linidx);
804  if (!nextlinidx) break;
805 
806  linidx = nextlinidx;
807  }
808  if (!allocate) return -1;
809 
810  ++fFilledBins;
811 
812  // allocate bin in chunk
814  Long64_t newidx = chunk ? ((Long64_t) chunk->GetEntries()) : -1;
815  if (!chunk || newidx == (Long64_t)fChunkSize) {
816  chunk = AddChunk();
817  newidx = 0;
818  }
819  chunk->AddBin(newidx, cc->GetBuffer());
820 
821  // store translation between hash and bin
822  newidx += (fBinContent.GetEntriesFast() - 1) * fChunkSize;
823  if (!linidx) {
824  // fBins didn't find it
825  if (2 * GetNbins() > fBins.Capacity())
826  fBins.Expand(3 * GetNbins());
827  fBins.Add(hash, newidx + 1);
828  } else {
829  // fBins contains one, but it's the wrong one;
830  // add entry to fBinsContinued.
831  fBinsContinued.Add(linidx, newidx + 1);
832  }
833  return newidx;
834 }
835 
836 ////////////////////////////////////////////////////////////////////////////////
837 /// Return THnSparseCompactBinCoord object.
838 
839 THnSparseCompactBinCoord* THnSparse::GetCompactCoord() const
840 {
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);
847  delete [] bins;
848  }
849  return fCompactCoord;
850 }
851 
852 ////////////////////////////////////////////////////////////////////////////////
853 /// Return the amount of filled bins over all bins
854 
856  Double_t nbinsTotal = 1.;
857  for (Int_t d = 0; d < fNdimensions; ++d)
858  nbinsTotal *= GetAxis(d)->GetNbins() + 2;
859  return fFilledBins / nbinsTotal;
860 }
861 
862 ////////////////////////////////////////////////////////////////////////////////
863 /// Return the amount of used memory over memory that would be used by a
864 /// non-sparse n-dimensional histogram. The value is approximate.
865 
867  Int_t arrayElementSize = 0;
868  if (fFilledBins) {
869  TClass* clArray = GetChunk(0)->fContent->IsA();
870  TDataMember* dm = clArray ? clArray->GetDataMember("fArray") : 0;
871  arrayElementSize = dm ? dm->GetDataType()->Size() : 0;
872  }
873  if (!arrayElementSize) {
874  Warning("GetSparseFractionMem", "Cannot determine type of elements!");
875  return -1.;
876  }
877 
878  Double_t sizePerChunkElement = arrayElementSize + GetCompactCoord()->GetBufferSize();
879  if (fFilledBins && GetChunk(0)->fSumw2)
880  sizePerChunkElement += sizeof(Double_t); /* fSumw2 */
881 
882  Double_t size = 0.;
883  size += fBinContent.GetEntries() * (GetChunkSize() * sizePerChunkElement + sizeof(THnSparseArrayChunk));
884  size += + 3 * sizeof(Long64_t) * fBins.GetSize() /* TExMap */;
885 
886  Double_t nbinsTotal = 1.;
887  for (Int_t d = 0; d < fNdimensions; ++d)
888  nbinsTotal *= GetAxis(d)->GetNbins() + 2;
889 
890  return size / nbinsTotal / arrayElementSize;
891 }
892 
893 ////////////////////////////////////////////////////////////////////////////////
894 /// Create an iterator over all filled bins of a THnSparse.
895 /// Use THnIter instead.
896 
898 {
899  return new THnSparseBinIter(respectAxisRange, this);
900 }
901 
902 ////////////////////////////////////////////////////////////////////////////////
903 /// Set content of bin with index "bin" to "v"
904 
906 {
907  THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
908  chunk->fContent->SetAt(v, bin % fChunkSize);
909  ++fEntries;
910 }
911 
912 ////////////////////////////////////////////////////////////////////////////////
913 /// Set error of bin with index "bin" to "e", enable errors if needed
914 
916 {
917  THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
918  if (!chunk->fSumw2 ) {
919  // if fSumw2 is zero GetCalculateErrors should return false
920  if (GetCalculateErrors()) {
921  Error("SetBinError", "GetCalculateErrors() logic error!");
922  }
923  Sumw2(); // enable error calculation
924  }
925 
926  chunk->fSumw2->SetAt(e2, bin % fChunkSize);
927 }
928 
929 ////////////////////////////////////////////////////////////////////////////////
930 /// Add "e" to error of bin with index "bin", enable errors if needed
931 
933 {
934  THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
935  if (!chunk->fSumw2 ) {
936  // if fSumw2 is zero GetCalculateErrors should return false
937  if (GetCalculateErrors()) {
938  Error("SetBinError", "GetCalculateErrors() logic error!");
939  }
940  Sumw2(); // enable error calculation
941  }
942 
943  (*chunk->fSumw2)[bin % fChunkSize] += e2;
944 }
945 
946 ////////////////////////////////////////////////////////////////////////////////
947 /// Enable calculation of errors
948 
950 {
951  if (GetCalculateErrors()) return;
952 
953  fTsumw2 = 0.;
954  TIter iChunk(&fBinContent);
955  THnSparseArrayChunk* chunk = 0;
956  while ((chunk = (THnSparseArrayChunk*) iChunk()))
957  chunk->Sumw2();
958 }
959 
960 ////////////////////////////////////////////////////////////////////////////////
961 /// Clear the histogram
962 
963 void THnSparse::Reset(Option_t *option /*= ""*/)
964 {
965  fFilledBins = 0;
966  fBins.Delete();
969  ResetBase(option);
970 }
971 
Abstract array base class.
Definition: TArray.h:33
virtual void Clear(Option_t *="")
Definition: TObject.h:110
THnSparseCompactBinCoord * GetCompactCoord() const
Return THnSparseCompactBinCoord object.
Definition: THnSparse.cxx:839
Bool_t GetCalculateErrors() const
Definition: THnBase.h:147
THnSparseArrayChunk is used internally by THnSparse.
void Add(ULong64_t hash, Long64_t key, Long64_t value)
Add an (key,value) pair to the table. The key should be unique.
Definition: TExMap.cxx:85
void AddBinContent(const Int_t *idx, Double_t v=1.)
Definition: THnSparse.h:124
float xmin
Definition: THbookFile.cxx:93
void SetAt(Double_t v, Int_t i)
Definition: TArrayD.h:53
long long Long64_t
Definition: RtypesCore.h:69
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
void FillExMap()
We have been streamed; set up fBins.
Definition: THnSparse.cxx:655
Double_t fTsumw2
Definition: THnBase.h:60
const char Option_t
Definition: RtypesCore.h:62
THnSparseArrayChunk * AddChunk()
Create a new chunk of bin content.
Definition: THnSparse.cxx:634
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:328
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:33
virtual ~THnSparseArrayChunk()
Destructor.
Definition: THnSparse.cxx:440
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Int_t GetChunkSize() const
Definition: THnSparse.h:102
Long64_t fFilledBins
Definition: THnSparse.h:55
Int_t Capacity() const
Definition: TExMap.h:71
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
void Sumw2()
Turn on support of errors.
Definition: THnSparse.cxx:480
TDataType * GetDataType() const
Definition: TDataMember.h:74
void InitStorage(Int_t *nbins, Int_t chunkSize)
Initialize the storage of a histogram created via Init()
Definition: THnSparse.cxx:646
Int_t GetEntriesFast() const
Definition: TObjArray.h:66
const TKDTreeBinning * bins
Long64_t GetNbins() const
Definition: THnSparse.h:107
THnSparseCompactBinCoord * fCompactCoord
filled bins for non-unique hashes, containing pairs of (bin index 0, bin index 1) ...
Definition: THnSparse.h:59
Double_t fEntries
browser-helpers for each axis
Definition: THnBase.h:58
ClassImp(THnSparseArrayChunk)
Double_t x[n]
Definition: legend1.C:17
Int_t GetNdimensions() const
Definition: THnBase.h:146
virtual void SetAt(Double_t v, Int_t i)=0
Efficient multidimensional histogram.
Definition: THnSparse.h:52
virtual TArray * GenerateArray() const =0
Double_t GetAt(Int_t i) const
Definition: TArrayD.h:47
Double_t GetSparseFractionBins() const
Return the amount of filled bins over all bins.
Definition: THnSparse.cxx:855
Double_t * fArray
Definition: TArrayD.h:32
Int_t fSingleCoordinateSize
size of the allocated coordinate buffer; -1 means none or fCoordinatesSize
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
virtual Int_t GetCoord(Int_t dim) const =0
Long64_t GetBin(const Int_t *idx) const
Definition: THnSparse.h:110
Int_t GetSize() const
Definition: TExMap.h:73
virtual ~THnSparse()
Destruct a THnSparse.
Definition: THnSparse.cxx:616
void SetBinError2(Long64_t bin, Double_t e2)
Set error of bin with index "bin" to "e", enable errors if needed.
Definition: THnSparse.cxx:915
TExMap fBinsContinued
filled bins
Definition: THnSparse.h:58
void Reset(Option_t *option="")
Clear the histogram.
Definition: THnSparse.cxx:963
Long64_t GetValue(ULong64_t hash, Long64_t key)
Return the value belonging to specified key and hash value.
Definition: TExMap.cxx:171
ROOT::R::TRInterface & r
Definition: Object.C:4
TExMap fBins
Definition: THnSparse.h:57
Int_t GetEntries() const
SVector< double, 2 > v
Definition: Dict.h:5
THnSparseArrayChunk * GetChunk(Int_t idx) const
Definition: THnSparse.h:71
Int_t GetNbins() const
Definition: TAxis.h:125
Iterator over THnBase bins (internal implementation).
Definition: THnBase.h:294
ROOT::Internal::THnBaseBinIter * CreateIter(Bool_t respectAxisRange) const
Create an iterator over all filled bins of a THnSparse.
Definition: THnSparse.cxx:897
void Sumw2()
Enable calculation of errors.
Definition: THnSparse.cxx:949
unsigned int UInt_t
Definition: RtypesCore.h:42
Double_t GetBinError2(Long64_t linidx) const
Get square of the error of bin addressed by linidx as BEGIN_LATEX #sum weight^{2} END_LATEX If errors...
Definition: THnSparse.cxx:772
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
float xmax
Definition: THbookFile.cxx:93
TAxis * GetAxis(Int_t dim) const
Definition: THnBase.h:136
void SetBinContent(const Int_t *idx, Double_t v)
Definition: THnSparse.h:117
void Delete(Option_t *opt="")
Delete all entries stored in the TExMap.
Definition: TExMap.cxx:161
Int_t GetSize() const
Definition: TArray.h:49
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition: TAxis.cxx:264
void Reserve(Long64_t nbins)
Initialize storage for nbins.
Definition: THnSparse.cxx:689
virtual Int_t GetSize() const
Definition: TCollection.h:95
double Double_t
Definition: RtypesCore.h:55
unsigned long long ULong64_t
Definition: RtypesCore.h:70
void AddBinError2(Long64_t bin, Double_t e2)
Add "e" to error of bin with index "bin", enable errors if needed.
Definition: THnSparse.cxx:932
Double_t GetBinContent(const Int_t *idx) const
Definition: THnSparse.h:132
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:493
THnSparse()
Construct an empty THnSparse.
Definition: THnSparse.cxx:589
Array of doubles (64 bits per element).
Definition: TArrayD.h:29
#define name(a, b)
Definition: linkTestLib0.cpp:5
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3221
Binding & operator=(OUT(*fun)(void))
Int_t Size() const
Get size of basic typedef'ed type.
Definition: TDataType.cxx:366
Double_t GetSparseFractionMem() const
Return the amount of used memory over memory that would be used by a non-sparse n-dimensional histogr...
Definition: THnSparse.cxx:866
void AddBin(Int_t idx, const Char_t *idxbuf)
Create a new bin in this chunk.
Definition: THnSparse.cxx:450
char Char_t
Definition: RtypesCore.h:29
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:478
Bool_t Matches(Int_t idx, const Char_t *idxbuf) const
virtual Double_t GetAt(Int_t i) const =0
Int_t fNdimensions
Definition: THnBase.h:55
int GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, Bool_t check=kTRUE)
Retrieve a linear buffer pointer from the given pyobject.
Definition: Utility.cxx:533
Int_t fChunkSize
Definition: THnSparse.h:54
virtual void AddLast(TObject *obj)
Add object in the next empty slot in the array.
Definition: TObjArray.cxx:168
Multidimensional histogram base.
Definition: THnBase.h:53
unsigned char UChar_t
Definition: RtypesCore.h:34
const Bool_t kTRUE
Definition: Rtypes.h:91
Long64_t GetBinIndexForCurrentBin(Bool_t allocate)
Return the index for fCurrentBinIndex.
Definition: THnSparse.cxx:790
const Int_t n
Definition: legend1.C:16
virtual Long64_t Next(Int_t *coord=0)=0
TObjArray fBinContent
Definition: THnSparse.h:56
void ResetBase(Option_t *option="")
Clear the histogram.
Definition: THnBase.cxx:1149
void Expand(Int_t newsize)
Expand the TExMap.
Definition: TExMap.cxx:276
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:904