// @(#)root/hist:$Id$
// Author: Axel Naumann (2011-12-20)

/*************************************************************************
 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_THnBase
#define ROOT_THnBase

/*************************************************************************

 THnBase: Common base class for n-dimensional histogramming.
 Defines interfaces and algorithms.

*************************************************************************/


#ifndef ROOT_TNamed
#include "TNamed.h"
#endif
#ifndef ROOT_TMath
#include "TMath.h"
#endif
#ifndef ROOT_TFitResultPtr
#include "TFitResultPtr.h"
#endif
#ifndef ROOT_TObjArray
#include "TObjArray.h"
#endif
#ifndef ROOT_TArrayD
#include "TArrayD.h"
#endif

class TAxis;
class TH1;
class TH1D;
class TH2D;
class TH3D;
class TF1;
class THnIter;

namespace ROOT {
   class THnBaseBinIter;
}

class THnBase: public TNamed {
protected:
   Int_t      fNdimensions;  // number of dimensions
   TObjArray  fAxes;         // axes of the histogram
   TObjArray  fBrowsables;   //! browser-helpers for each axis
   Double_t   fEntries;      // number of entries, spread over chunks
   Double_t   fTsumw;        // total sum of weights
   Double_t   fTsumw2;       // total sum of weights squared; -1 if no errors are calculated
   TArrayD    fTsumwx;       // total sum of weight*X for each dimension
   TArrayD    fTsumwx2;      // total sum of weight*X*X for each dimension
   Double_t  *fIntegral;     //! array with bin weight sums
   enum {
      kNoInt,
      kValidInt,
      kInvalidInt
   } fIntegralStatus;        //! status of integral

private:
   THnBase(const THnBase&); // Not implemented
   THnBase& operator=(const THnBase&); // Not implemented

 protected:
   THnBase():
      fNdimensions(0), fEntries(0),
      fTsumw(0), fTsumw2(-1.), fIntegral(0), fIntegralStatus(kNoInt)
   {}

   THnBase(const char* name, const char* title, Int_t dim,
           const Int_t* nbins, const Double_t* xmin, const Double_t* xmax);

   void UpdateXStat(const Double_t *x, Double_t w = 1.) {
      if (GetCalculateErrors()) {
         for (Int_t d = 0; d < fNdimensions; ++d) {
            const Double_t xd = x[d];
            fTsumwx[d]  += w * xd;
            fTsumwx2[d] += w * xd * xd;
         }
      }
   }

   virtual void FillBin(Long64_t bin, Double_t w) = 0;
   void FillBinBase(Double_t w) {
      // Increment the statistics due to filled weight "w",
      fEntries += 1;
      if (GetCalculateErrors()) {
         fTsumw += w;
         fTsumw2 += w*w;
      }
      fIntegralStatus = kInvalidInt;
   }

   virtual void InitStorage(Int_t* nbins, Int_t chunkSize) = 0;
   void Init(const char* name, const char* title,
             const TObjArray* axes, Bool_t keepTargetAxis,
             Int_t chunkSize = 1024 * 16);
   THnBase* CloneEmpty(const char* name, const char* title,
                       const TObjArray* axes, Bool_t keepTargetAxis) const;
   virtual void Reserve(Long64_t /*nbins*/) {}
   virtual void SetFilledBins(Long64_t /*nbins*/) {};

   Bool_t CheckConsistency(const THnBase *h, const char *tag) const;
   TH1* CreateHist(const char* name, const char* title,
                   const TObjArray* axes, Bool_t keepTargetAxis) const;
   TObject* ProjectionAny(Int_t ndim, const Int_t* dim,
                          Bool_t wantNDim, Option_t* option = "") const;
   Bool_t PrintBin(Long64_t idx, Int_t* coord, Option_t* options) const;
   void AddInternal(const THnBase* h, Double_t c, Bool_t rebinned);
   THnBase* RebinBase(Int_t group) const;
   THnBase* RebinBase(const Int_t* group) const;
   void ResetBase(Option_t *option= "");

   static THnBase* CreateHnAny(const char* name, const char* title,
                               const TH1* h1, Bool_t sparse,
                               Int_t chunkSize = 1024 * 16);
   static THnBase* CreateHnAny(const char* name, const char* title,
                               const THnBase* hn, Bool_t sparse,
                               Int_t chunkSize = 1024 * 16);

 public:
   virtual ~THnBase();

   TObjArray* GetListOfAxes() { return &fAxes; }
   const TObjArray* GetListOfAxes() const { return &fAxes; }
   TAxis* GetAxis(Int_t dim) const { return (TAxis*)fAxes[dim]; }

   TFitResultPtr Fit(TF1 *f1 ,Option_t *option = "", Option_t *goption = "");
   TList* GetListOfFunctions() { return 0; }

   virtual ROOT::THnBaseBinIter* CreateIter(Bool_t respectAxisRange) const = 0;

   virtual Long64_t GetNbins() const = 0;
   Double_t GetEntries() const { return fEntries; }
   Double_t GetWeightSum() const { return fTsumw; }
   Int_t    GetNdimensions() const { return fNdimensions; }
   Bool_t   GetCalculateErrors() const { return fTsumw2 >= 0.; }
   void     CalculateErrors(Bool_t calc = kTRUE) {
      // Calculate errors (or not if "calc" == kFALSE)
      if (calc) Sumw2();
      else fTsumw2 = -1.;
   }

   Long64_t Fill(const Double_t *x, Double_t w = 1.) {
      UpdateXStat(x, w);
      Long64_t bin = GetBin(x, kTRUE /*alloc*/);
      FillBin(bin, w);
      return bin;
   }
   Long64_t Fill(const char* name[], Double_t w = 1.) {
      Long64_t bin = GetBin(name, kTRUE /*alloc*/);
      FillBin(bin, w);
      return bin;
   }
   void SetBinEdges(Int_t idim, const Double_t* bins);
   Bool_t IsInRange(Int_t *coord) const;
   Double_t GetBinError(const Int_t *idx) const { return GetBinError(GetBin(idx)); }
   Double_t GetBinError(Long64_t linidx) const { return TMath::Sqrt(GetBinError2(linidx)); }
   void SetBinError(const Int_t* idx, Double_t e) { SetBinError(GetBin(idx), e); }
   void SetBinError(Long64_t bin, Double_t e) { SetBinError2(bin, e*e); }
   void AddBinContent(const Int_t* x, Double_t v = 1.) { AddBinContent(GetBin(x), v); }
   void SetEntries(Double_t entries) { fEntries = entries; }
   void SetTitle(const char *title);

   Double_t GetBinContent(const Int_t *idx) const { return GetBinContent(GetBin(idx)); } // intentionally non-virtual
   virtual Double_t GetBinContent(Long64_t bin, Int_t* idx = 0) const = 0;
   virtual Double_t GetBinError2(Long64_t linidx) const = 0;
   virtual Long64_t GetBin(const Int_t* idx) const = 0;
   virtual Long64_t GetBin(const Double_t* x) const = 0;
   virtual Long64_t GetBin(const char* name[]) const = 0;
   virtual Long64_t GetBin(const Int_t* idx, Bool_t /*allocate*/ = kTRUE) = 0;
   virtual Long64_t GetBin(const Double_t* x, Bool_t /*allocate*/ = kTRUE) = 0;
   virtual Long64_t GetBin(const char* name[], Bool_t /*allocate*/ = kTRUE) = 0;

   void SetBinContent(const Int_t* idx, Double_t v) { SetBinContent(GetBin(idx), v); } // intentionally non-virtual
   virtual void SetBinContent(Long64_t bin, Double_t v) = 0;
   virtual void SetBinError2(Long64_t bin, Double_t e2) = 0;
   virtual void AddBinError2(Long64_t bin, Double_t e2) = 0;
   virtual void AddBinContent(Long64_t bin, Double_t v = 1.) = 0;

   Double_t GetSumw() const  { return fTsumw; }
   Double_t GetSumw2() const { return fTsumw2; }
   Double_t GetSumwx(Int_t dim) const  { return fTsumwx[dim]; }
   Double_t GetSumwx2(Int_t dim) const { return fTsumwx2[dim]; }

   TH1D*    Projection(Int_t xDim, Option_t* option = "") const {
      // Project all bins into a 1-dimensional histogram,
      // keeping only axis "xDim".
      // If "option" contains "E" errors will be calculated.
      //                      "A" ranges of the taget axes will be ignored.
      //                      "O" original axis range of the taget axes will be
      //                          kept, but only bins inside the selected range
      //                          will be filled.
      return (TH1D*) ProjectionAny(1, &xDim, false, option);
   }

   TH2D*    Projection(Int_t yDim, Int_t xDim,
                       Option_t* option = "") const {
      // Project all bins into a 2-dimensional histogram,
      // keeping only axes "xDim" and "yDim".
      //
      // WARNING: just like TH3::Project3D("yx") and TTree::Draw("y:x"),
      // Projection(y,x) uses the first argument to define the y-axis and the
      // second for the x-axis!
      //
      // If "option" contains "E" errors will be calculated.
      //                      "A" ranges of the taget axes will be ignored.

      const Int_t dim[2] = {xDim, yDim};
      return (TH2D*) ProjectionAny(2, dim, false, option);
   }

   TH3D*    Projection(Int_t xDim, Int_t yDim, Int_t zDim,
                       Option_t* option = "") const {
      // Project all bins into a 3-dimensional histogram,
      // keeping only axes "xDim", "yDim", and "zDim".
      // If "option" contains "E" errors will be calculated.
      //                      "A" ranges of the taget axes will be ignored.
      //                      "O" original axis range of the taget axes will be
      //                          kept, but only bins inside the selected range
      //                          will be filled.

      const Int_t dim[3] = {xDim, yDim, zDim};
      return (TH3D*) ProjectionAny(3, dim, false, option);
   }

   THnBase* ProjectionND(Int_t ndim, const Int_t* dim,
                         Option_t* option = "") const {
      return (THnBase*)ProjectionAny(ndim, dim, kTRUE /*wantNDim*/, option);
   }

   Long64_t   Merge(TCollection* list);

   void Scale(Double_t c);
   void Add(const THnBase* h, Double_t c=1.);
   void Add(const TH1* hist, Double_t c=1.);
   void Multiply(const THnBase* h);
   void Multiply(TF1* f, Double_t c = 1.);
   void Divide(const THnBase* h);
   void Divide(const THnBase* h1, const THnBase* h2, Double_t c1 = 1., Double_t c2 = 1., Option_t* option="");
   void RebinnedAdd(const THnBase* h, Double_t c=1.);

   virtual void Reset(Option_t* option = "") = 0;
   virtual void Sumw2() = 0;

   Double_t ComputeIntegral();
   void GetRandom(Double_t *rand, Bool_t subBinRandom = kTRUE);

   void Print(Option_t* option = "") const;
   void PrintEntries(Long64_t from = 0, Long64_t howmany = -1, Option_t* options = 0) const;
   void PrintBin(Int_t* coord, Option_t* options) const {
      PrintBin(-1, coord, options);
   }
   void PrintBin(Long64_t idx, Option_t* options) const;

   void Browse(TBrowser *b);
   Bool_t IsFolder() const { return kTRUE; }

   //void Draw(Option_t* option = "");

   ClassDef(THnBase, 1); // Common base for n-dimensional histogram

   friend class THnIter;
};

namespace ROOT {
   // Helper class for browing THnBase objects
   class THnBaseBrowsable: public TNamed {
   public:
      THnBaseBrowsable(THnBase* hist, Int_t axis);
      ~THnBaseBrowsable();
      void Browse(TBrowser *b);
      Bool_t IsFolder() const { return kFALSE; }

   private:
      THnBase* fHist; // Original histogram
      Int_t    fAxis; // Axis to visualize
      TH1*     fProj; // Projection result
      ClassDef(THnBaseBrowsable, 0); // Browser-helper for THnBase
   };

   // Base class for iterating over THnBase bins
   class THnBaseBinIter {
   public:
      THnBaseBinIter(Bool_t respectAxisRange):
         fRespectAxisRange(respectAxisRange), fHaveSkippedBin(kFALSE) {}
      virtual ~THnBaseBinIter();
      Bool_t HaveSkippedBin() const { return fHaveSkippedBin; }
      Bool_t RespectsAxisRange() const { return fRespectAxisRange; }

      virtual Int_t GetCoord(Int_t dim) const = 0;
      virtual Long64_t Next(Int_t* coord = 0) = 0;

   protected:
      Bool_t fRespectAxisRange;
      Bool_t fHaveSkippedBin;
   };
}

class THnIter: public TObject {
public:
   THnIter(const THnBase* hist, Bool_t respectAxisRange = kFALSE):
      fIter(hist->CreateIter(respectAxisRange)) {}
   virtual ~THnIter();

   Long64_t Next(Int_t* coord = 0) {
      // Return the next bin's index.
      // If provided, set coord to that bin's coordinates (bin indexes).
      // I.e. coord must point to Int_t[hist->GetNdimensions()]
      // Returns -1 when all bins have been visited.
      return fIter->Next(coord);
   }

   Int_t GetCoord(Int_t dim) const { return fIter->GetCoord(dim); }
   Bool_t HaveSkippedBin() const { return fIter->HaveSkippedBin(); }
   Bool_t RespectsAxisRange() const { return fIter->RespectsAxisRange(); }

private:
   ROOT::THnBaseBinIter* fIter;
   ClassDef(THnIter, 0); //Iterator over bins of a THnBase.
};

#endif //  ROOT_THnBase
 THnBase.h:1
 THnBase.h:2
 THnBase.h:3
 THnBase.h:4
 THnBase.h:5
 THnBase.h:6
 THnBase.h:7
 THnBase.h:8
 THnBase.h:9
 THnBase.h:10
 THnBase.h:11
 THnBase.h:12
 THnBase.h:13
 THnBase.h:14
 THnBase.h:15
 THnBase.h:16
 THnBase.h:17
 THnBase.h:18
 THnBase.h:19
 THnBase.h:20
 THnBase.h:21
 THnBase.h:22
 THnBase.h:23
 THnBase.h:24
 THnBase.h:25
 THnBase.h:26
 THnBase.h:27
 THnBase.h:28
 THnBase.h:29
 THnBase.h:30
 THnBase.h:31
 THnBase.h:32
 THnBase.h:33
 THnBase.h:34
 THnBase.h:35
 THnBase.h:36
 THnBase.h:37
 THnBase.h:38
 THnBase.h:39
 THnBase.h:40
 THnBase.h:41
 THnBase.h:42
 THnBase.h:43
 THnBase.h:44
 THnBase.h:45
 THnBase.h:46
 THnBase.h:47
 THnBase.h:48
 THnBase.h:49
 THnBase.h:50
 THnBase.h:51
 THnBase.h:52
 THnBase.h:53
 THnBase.h:54
 THnBase.h:55
 THnBase.h:56
 THnBase.h:57
 THnBase.h:58
 THnBase.h:59
 THnBase.h:60
 THnBase.h:61
 THnBase.h:62
 THnBase.h:63
 THnBase.h:64
 THnBase.h:65
 THnBase.h:66
 THnBase.h:67
 THnBase.h:68
 THnBase.h:69
 THnBase.h:70
 THnBase.h:71
 THnBase.h:72
 THnBase.h:73
 THnBase.h:74
 THnBase.h:75
 THnBase.h:76
 THnBase.h:77
 THnBase.h:78
 THnBase.h:79
 THnBase.h:80
 THnBase.h:81
 THnBase.h:82
 THnBase.h:83
 THnBase.h:84
 THnBase.h:85
 THnBase.h:86
 THnBase.h:87
 THnBase.h:88
 THnBase.h:89
 THnBase.h:90
 THnBase.h:91
 THnBase.h:92
 THnBase.h:93
 THnBase.h:94
 THnBase.h:95
 THnBase.h:96
 THnBase.h:97
 THnBase.h:98
 THnBase.h:99
 THnBase.h:100
 THnBase.h:101
 THnBase.h:102
 THnBase.h:103
 THnBase.h:104
 THnBase.h:105
 THnBase.h:106
 THnBase.h:107
 THnBase.h:108
 THnBase.h:109
 THnBase.h:110
 THnBase.h:111
 THnBase.h:112
 THnBase.h:113
 THnBase.h:114
 THnBase.h:115
 THnBase.h:116
 THnBase.h:117
 THnBase.h:118
 THnBase.h:119
 THnBase.h:120
 THnBase.h:121
 THnBase.h:122
 THnBase.h:123
 THnBase.h:124
 THnBase.h:125
 THnBase.h:126
 THnBase.h:127
 THnBase.h:128
 THnBase.h:129
 THnBase.h:130
 THnBase.h:131
 THnBase.h:132
 THnBase.h:133
 THnBase.h:134
 THnBase.h:135
 THnBase.h:136
 THnBase.h:137
 THnBase.h:138
 THnBase.h:139
 THnBase.h:140
 THnBase.h:141
 THnBase.h:142
 THnBase.h:143
 THnBase.h:144
 THnBase.h:145
 THnBase.h:146
 THnBase.h:147
 THnBase.h:148
 THnBase.h:149
 THnBase.h:150
 THnBase.h:151
 THnBase.h:152
 THnBase.h:153
 THnBase.h:154
 THnBase.h:155
 THnBase.h:156
 THnBase.h:157
 THnBase.h:158
 THnBase.h:159
 THnBase.h:160
 THnBase.h:161
 THnBase.h:162
 THnBase.h:163
 THnBase.h:164
 THnBase.h:165
 THnBase.h:166
 THnBase.h:167
 THnBase.h:168
 THnBase.h:169
 THnBase.h:170
 THnBase.h:171
 THnBase.h:172
 THnBase.h:173
 THnBase.h:174
 THnBase.h:175
 THnBase.h:176
 THnBase.h:177
 THnBase.h:178
 THnBase.h:179
 THnBase.h:180
 THnBase.h:181
 THnBase.h:182
 THnBase.h:183
 THnBase.h:184
 THnBase.h:185
 THnBase.h:186
 THnBase.h:187
 THnBase.h:188
 THnBase.h:189
 THnBase.h:190
 THnBase.h:191
 THnBase.h:192
 THnBase.h:193
 THnBase.h:194
 THnBase.h:195
 THnBase.h:196
 THnBase.h:197
 THnBase.h:198
 THnBase.h:199
 THnBase.h:200
 THnBase.h:201
 THnBase.h:202
 THnBase.h:203
 THnBase.h:204
 THnBase.h:205
 THnBase.h:206
 THnBase.h:207
 THnBase.h:208
 THnBase.h:209
 THnBase.h:210
 THnBase.h:211
 THnBase.h:212
 THnBase.h:213
 THnBase.h:214
 THnBase.h:215
 THnBase.h:216
 THnBase.h:217
 THnBase.h:218
 THnBase.h:219
 THnBase.h:220
 THnBase.h:221
 THnBase.h:222
 THnBase.h:223
 THnBase.h:224
 THnBase.h:225
 THnBase.h:226
 THnBase.h:227
 THnBase.h:228
 THnBase.h:229
 THnBase.h:230
 THnBase.h:231
 THnBase.h:232
 THnBase.h:233
 THnBase.h:234
 THnBase.h:235
 THnBase.h:236
 THnBase.h:237
 THnBase.h:238
 THnBase.h:239
 THnBase.h:240
 THnBase.h:241
 THnBase.h:242
 THnBase.h:243
 THnBase.h:244
 THnBase.h:245
 THnBase.h:246
 THnBase.h:247
 THnBase.h:248
 THnBase.h:249
 THnBase.h:250
 THnBase.h:251
 THnBase.h:252
 THnBase.h:253
 THnBase.h:254
 THnBase.h:255
 THnBase.h:256
 THnBase.h:257
 THnBase.h:258
 THnBase.h:259
 THnBase.h:260
 THnBase.h:261
 THnBase.h:262
 THnBase.h:263
 THnBase.h:264
 THnBase.h:265
 THnBase.h:266
 THnBase.h:267
 THnBase.h:268
 THnBase.h:269
 THnBase.h:270
 THnBase.h:271
 THnBase.h:272
 THnBase.h:273
 THnBase.h:274
 THnBase.h:275
 THnBase.h:276
 THnBase.h:277
 THnBase.h:278
 THnBase.h:279
 THnBase.h:280
 THnBase.h:281
 THnBase.h:282
 THnBase.h:283
 THnBase.h:284
 THnBase.h:285
 THnBase.h:286
 THnBase.h:287
 THnBase.h:288
 THnBase.h:289
 THnBase.h:290
 THnBase.h:291
 THnBase.h:292
 THnBase.h:293
 THnBase.h:294
 THnBase.h:295
 THnBase.h:296
 THnBase.h:297
 THnBase.h:298
 THnBase.h:299
 THnBase.h:300
 THnBase.h:301
 THnBase.h:302
 THnBase.h:303
 THnBase.h:304
 THnBase.h:305
 THnBase.h:306
 THnBase.h:307
 THnBase.h:308
 THnBase.h:309
 THnBase.h:310
 THnBase.h:311
 THnBase.h:312
 THnBase.h:313
 THnBase.h:314
 THnBase.h:315
 THnBase.h:316
 THnBase.h:317
 THnBase.h:318
 THnBase.h:319
 THnBase.h:320
 THnBase.h:321
 THnBase.h:322
 THnBase.h:323
 THnBase.h:324
 THnBase.h:325
 THnBase.h:326
 THnBase.h:327
 THnBase.h:328
 THnBase.h:329
 THnBase.h:330
 THnBase.h:331