Re: [ROOT] Chisq for 4D histos..

From: Christian Holm Christensen (cholm@hehi03.nbi.dk)
Date: Wed Feb 13 2002 - 13:03:55 MET


Mandeep,

On Tue, 12 Feb 2002 14:34:34 -0800 (PST)
"Mandeep S. Gill" <msgill@SLAC.stanford.edu> wrote
concerning "[ROOT] Chisq for 4D histos..":
> 
> Dear Rootfolk:  i hope this is the right place to send this to, it's my
> first roottalk posting so:  has anyone implemented anything higher than a
> 3D histo in Root?

It's hard to visualise more than 3D histos (heck even a 3D histo is
difficult), so I don't think that's something ROOT really needs. 
 
> (The reason i ask is because i wanted to calculate a chisq/dof value
> for some 2D fits i'm doing (in RooFitCore, based on Root), and since
> chisq is only pre-implemented for 1D in RFC, i wrote the code for
> doing this myself based on the GetBinContents function for a TH2F
> object, but there are only histos predefined up to a TH3F on the
> Root class doc page so i'm wondering if i'll have to either use a
> different method for getting the chisq, or extend the functionality
> myself to higher dim'l TH objects..)

I think a better way to fit a R^4->R mapping is to use the TFitter
class (which uses TMinuit) to do your fit.  Suppose you have M tuples
of (v, x, y, z, d, e) where (v, x, y, z) is the independent variables,
and (d, e) is the dependent variable, and it's error, then you can fit
the function f: (v,x,y,z)->d to the M data points (which we'll assume
we can get from some object data, using the method GetEntry(i)) to the
function f like: 

  // The function we need to minimise, here a Chi^2 function 
  void chiSquare(Int_t& nPar, Double_t* in, Double_t& f, 
  	         Double_t* p, Int_t flag) 
  {
    f = Data::Instance()->ChiSquare(p);
  }
  
  class Data {
  private:
    Int_t        fN;          // Num entries 
    Double_t*    fX;          // [4 * fN] independent points 
    Double_t*    fD;          // [fN] dependent points 
    Double_t*    fE;          // [fN] error dependent points 
    static Data* fgInstance; 
  public:
  
    Data() : fN(0), fX(0), fD(0), fE(0) {}; 
    static Data* Instance() { 
      if (!fgInstance) fgInstance = new Data();
      return fgInstance;
    }
  
    Double_t Function(Int_t i, Double_t* p) { 
      // The parameters are in the array pp. 
      // Here we need to evaluate the function at the point (v,x,y,z).  As
      // an example we'll just add the numbers 
      return p[0] 
        + p[1] * fX[4 * i] 
        + p[2] * fX[4 * i + 1] 
        + p[3] * fX[4 * i + 2] 
        + p[4] * fX[4 * i + 3]; 
    }
    
    Double_t ChiSquare(Double_t* p)
      Double_t chi2 = 0;   
      for (Int_t i = 0; i < fN; i++) {
        chi2 += TMath::Power((fD[i] - f(i, p))/ fE[i], 2);
      return chi2;
    }
  
    void Fit() { 
      TFitter* fitter = new TFitter(5); // Arg is number of params
      fitter->SetFCN(chiSquare); 

      Double_t arguments[] = { 500, 1 }
      fitter->ExecuteCommand("MIGRAD", arguments, 2);   

      Double_t amin, edm, errdef, 
      Int_t    nvpar, nparx; 
      fitter->GetStats(amin, edm, errdef, nvpar, nparx);
      fitter->PrintResults(3, amin); 
    }
  }

If you want to bin that data, you need to implement that. 

Please also refer to the tutorials, HOWTOs, and the Users guide.  A
search on roottalk will probably also give a good number of hits. 

Rene and Fons, couldn't the TFitter have a more intuitive interface,
like for example 

  TFitter::Fit(Option_t* option); 
  TFitter::SetFunction((*)(Int_t npar, Double_t* par, Double_t& f));
  TFitter::Print(Option_t*)

And maybe a special base class, like 


  class TFitObject { 
  protected: 
    Int_t fNParameters; 
    static TFitObject* fgInstance;
  public: 
    TFitObject(Int_t nPar) : fNParameters(nPar) { fgInstance = this; }
    static TFitObject* Instance() { return fgInstance; }
    virtual ~TFitObject() {}
    virtual Double_t MinimisationFunction(Double_t* par) = 0; 
  }; 

  void FitClassFunction(Int_t&, Double_t*, Double_t&f, Double_t*, Int_t) 
  {
    TFitObject* fit = TFitObject::Instance(); 
    if (!fit) {
      Error("FitClassFunction", "no fit object set"); 
      return;
    }
    f = fit->MinimisationFunction(p); 
  }
    
so that one could sub-class the TFitObject class to do various kinds
of fit: 

  class TChiSquare : public TFitObject {
  protected: 
    Int_t fNSample;
    Int_t fNVariables;
  public: 
    virtual Double_t  Function(Double_t* vars, Double_t* pars) = 0;
    virtual Double_t* GetX(Int_t i) = 0;
    virtual Double_t* GetD(Int_t i) = 0;
    virtual Double_t* GetE(Int_t i) = 0;

    Double_t MinimisationFunction(Double_t* p) {
      Double_t chi2 = 0;
      for (Int_t i = 0; i < GetNDataPoints(); i++) 
        chi2 += 
          TMath::Power((GetD() - Function(GetX(i), p)) / GetE(), 2);
      return chi2;
    }
  }; 

and then individual users can subclass these sub-classes, implementing
the abstract member functions.  Just my two-pennies worth. 

Yours, 

Christian Holm Christensen -------------------------------------------
Address: Sankt Hansgade 23, 1. th.           Phone:  (+45) 35 35 96 91 
         DK-2200 Copenhagen N                Cell:   (+45) 28 82 16 23
         Denmark                             Office: (+45) 353  25 305 
Email:   cholm@nbi.dk                        Web:    www.nbi.dk/~cholm



This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:50:41 MET