SparseData.cxx

Go to the documentation of this file.
00001 // @(#)root/mathcore:$Id: SparseData.cxx 31361 2009-11-21 09:14:42Z moneta $
00002 // Author: David Gonzalez Maline Wed Aug 28 15:33:03 2009
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 // Implementation file for class BinData
00012 
00013 #include <iostream>
00014 #include <iterator>
00015 #include <algorithm>
00016 
00017 #include <vector>
00018 #include <list>
00019 
00020 #include <stdexcept>
00021 
00022 #include <cmath>
00023 #include <limits>
00024 
00025 // #include "TMath.h"
00026 #include "Fit/SparseData.h"
00027 
00028 using namespace std;
00029 
00030 namespace ROOT { 
00031 
00032    namespace Fit { 
00033 
00034       //This class is a helper. It represents a bin in N
00035       //dimensions. The change in the name is to avoid name collision.
00036       class Box
00037       {
00038       public:
00039          // Creates a Box with limits specified by the vectors and
00040          // content=value and error=error
00041          Box(const vector<double>& min, const vector<double>& max, 
00042              const double value = 0.0, const double error = 1.0):
00043             fMin(min), fMax(max), fVal(value), fError(error)
00044          { }
00045          
00046          // Compares to Boxes to see if they are equal in all its
00047          // variables. This is to be used by the std::find algorithm
00048          bool operator==(const Box& b)
00049          { return (fMin == b.fMin) && (fMax == b.fMax) 
00050                && (fVal == b.fVal) && (fError == b.fError);  }
00051          
00052          // Get the list of minimum coordinates
00053          const vector<double>& GetMin() const { return fMin; }
00054          // Get the list of maximum coordinates
00055          const vector<double>& GetMax() const { return fMax; }
00056          // Get the value of the Box
00057          double GetVal() const { return fVal; }
00058          // Get the rror of the Box
00059          double GetError() const { return fError; }
00060          
00061          // Add an amount to the content of the Box
00062          void AddVal(const double value) { fVal += value; }
00063          
00064          friend class BoxContainer;
00065          friend ostream& operator <<(ostream& os, const Box& b);
00066          
00067       private:
00068          vector<double> fMin;
00069          vector<double> fMax;
00070          double fVal;
00071          double fError;
00072       };
00073       
00074       // This class is just a helper to be used in std::for_each to
00075       // simplify the code later. It's just a definition of a method
00076       // that will discern whether a Box is included into another one
00077       class BoxContainer
00078       {
00079       private:
00080          const Box& fBox;
00081       public:
00082          //Constructs the BoxContainer object with a Box that is meant
00083          //to include another one that will be provided later
00084          BoxContainer(const Box& b): fBox(b) {}
00085          
00086          bool operator() (const Box& b1)
00087          { return operator()(fBox, b1);  }
00088          
00089          // Looks if b2 is included in b1
00090          bool operator() (const Box& b1, const Box& b2)
00091          {
00092             bool isIn = true;
00093             vector<double>::const_iterator boxit = b2.fMin.begin();
00094             vector<double>::const_iterator bigit = b1.fMax.begin();
00095             while ( isIn && boxit != b2.fMin.end() )
00096             {
00097                if ( (*boxit) >= (*bigit) ) isIn = false;
00098                boxit++;
00099                bigit++;
00100             }
00101             
00102             boxit = b2.fMax.begin();
00103             bigit = b1.fMin.begin();
00104             while ( isIn && boxit != b2.fMax.end() )
00105             {
00106                if ( (*boxit) <= (*bigit) ) isIn = false;
00107                boxit++;
00108                bigit++;
00109             }
00110             
00111             return isIn;
00112          }
00113       };
00114       
00115       // Another helper class to be used in std::for_each to simplify
00116       // the code later. It implements the operator() to know if a
00117       // specified Box is big enough to contain any 'space' inside.
00118       class AreaComparer
00119       {
00120       public:
00121          AreaComparer(vector<double>::iterator iter): 
00122             fThereIsArea(true), 
00123             fIter(iter),
00124             fLimit(8 * std::numeric_limits<double>::epsilon())
00125          {};
00126          
00127          void operator() (double value)
00128          {
00129             if ( fabs(value- (*fIter)) < fLimit )
00130 //             if ( TMath::AreEqualRel(value, (*fIter), fLimit) )
00131                fThereIsArea = false;
00132             
00133             fIter++;
00134          }
00135          
00136          bool IsThereArea() { return fThereIsArea; }
00137          
00138       private:
00139          bool fThereIsArea;
00140          vector<double>::iterator fIter;
00141          double fLimit;
00142       };
00143       
00144 
00145       // This is the key of the SparseData structure. This method
00146       // will, by recursion, divide the area passed as an argument in
00147       // min and max into pieces to insert the Box defined by bmin and
00148       // bmax. It will do so from the highest dimension until it gets
00149       // to 1 and create the corresponding boxes to divide the
00150       // original space.
00151       void DivideBox( const vector<double>& min, const vector<double>& max,
00152                       const vector<double>& bmin, const vector<double>& bmax,
00153                       const unsigned int size, const unsigned int n,
00154                       list<Box>& l, const double val, const double error)
00155       {
00156          vector<double> boxmin(min);
00157          vector<double> boxmax(max);
00158          
00159          boxmin[n] = min[n];
00160          boxmax[n] = bmin[n];
00161          if ( for_each(boxmin.begin(), boxmin.end(), AreaComparer(boxmax.begin())).IsThereArea() )
00162             l.push_back(Box(boxmin, boxmax));
00163          
00164          boxmin[n] = bmin[n];
00165          boxmax[n] = bmax[n];
00166          if ( n == 0 ) 
00167          {
00168             if ( for_each(boxmin.begin(), boxmin.end(), AreaComparer(boxmax.begin())).IsThereArea() )
00169                l.push_back(Box(boxmin, boxmax, val, error));
00170          }
00171          else
00172             DivideBox(boxmin, boxmax, bmin, bmax, size, n-1, l, val, error);
00173          
00174          boxmin[n] = bmax[n];
00175          boxmax[n] = max[n];
00176          if ( for_each(boxmin.begin(), boxmin.end(), AreaComparer(boxmax.begin())).IsThereArea() )
00177             l.push_back(Box(boxmin, boxmax));
00178       }
00179       
00180       class ProxyListBox
00181       {
00182       public:
00183          void PushBack(Box& box) { fProxy.push_back(box); }
00184          list<Box>::iterator Begin() { return fProxy.begin(); }
00185          list<Box>::iterator End() { return fProxy.end(); }
00186          void Remove(list<Box>::iterator it) { fProxy.erase(it); }
00187          list<Box>& GetList() { return fProxy; }
00188       private:
00189          list<Box> fProxy;
00190       };
00191 
00192 
00193       SparseData::SparseData(vector<double>& min, vector<double>& max)
00194       {
00195          // Creates a SparseData convering the range defined by min
00196          // and max. For this it will create an empty Box for that
00197          // range.
00198          Box originalBox(min, max);
00199          fList = new ProxyListBox();
00200          fList->PushBack(originalBox);
00201       }
00202 
00203       SparseData::SparseData(const unsigned int dim, double min[], double max[])
00204       {
00205          // Creates a SparseData convering the range defined by min
00206          // and max. For this it will create an empty Box for that
00207          // range.
00208          vector<double> minv(min,min+dim);
00209          vector<double> maxv(max,max+dim);
00210          Box originalBox(minv, maxv);
00211          fList = new ProxyListBox();
00212          fList->PushBack(originalBox);
00213       }
00214 
00215       SparseData::~SparseData()
00216       { delete fList; }
00217 
00218       unsigned int SparseData::NPoints() const
00219       {
00220          // Returns the number of points stored, including the 0 ones.
00221          return fList->GetList().size();
00222       }
00223       
00224       unsigned int SparseData::NDim() const
00225       {
00226          // Returns the number of dimension of the SparseData object.
00227          return fList->Begin()->GetMin().size();
00228       }
00229 
00230       void SparseData::Add(std::vector<double>& min, std::vector<double>& max, 
00231                            const double content, const double error)
00232       {
00233          // Add a box to the stored ones. For that, it will look for
00234          // the box that contains the new data and either replace it
00235          // or updated it.
00236 
00237          // Little box is the new Bin to be added
00238          Box littleBox(min, max);
00239          list<Box>::iterator it;
00240          // So we look for the Bin already in the list that contains
00241          // littleBox
00242          it = std::find_if(fList->Begin(), fList->End(), BoxContainer(littleBox));
00243          if ( it != fList->End() )
00244 //             cout << "Found: " << *it << endl;
00245             ;
00246          else {
00247             cout << "SparseData::Add -> FAILED! box not found! " << endl;
00248             cout << littleBox << endl;
00249             return; // Does not add the box, as it is part of the
00250                     // underflow/overflow bin
00251          }
00252          // If it happens to have a value, then we add the value,
00253          if ( it->GetVal() )
00254             it->AddVal( content );
00255          else
00256          {
00257             // otherwise, we divide the container!
00258             DivideBox(it->GetMin(), it->GetMax(),
00259                       littleBox.GetMin(), littleBox.GetMax(),
00260                       it->GetMin().size(), it->GetMin().size() - 1,
00261                       fList->GetList(), content, error );
00262             // and remove it from the list
00263             fList->Remove(it);
00264          }
00265       }
00266 
00267       void SparseData::GetPoint(const unsigned int i, 
00268                                 std::vector<double>& min, std::vector<double>&max,
00269                                 double& content, double& error)
00270       {
00271          // Get the point number i. This is a method to explore the
00272          // data stored in the class.
00273 
00274          unsigned int counter = 0;
00275          list<Box>::iterator it = fList->Begin();
00276          while ( it != fList->End() && counter != i ) {
00277             ++it; 
00278             ++counter;
00279          }
00280 
00281          if ( (it == fList->End()) || (counter != i) )
00282             throw std::out_of_range("SparseData::GetPoint");
00283 
00284          min = it->GetMin();
00285          max = it->GetMax();
00286          content = it->GetVal();
00287          error = it->GetError();
00288       }
00289 
00290       void SparseData::PrintList() const
00291       {
00292          // Debug method to print a list with all the data stored.
00293          copy(fList->Begin(), fList->End(), ostream_iterator<Box>(cout, "\n------\n"));
00294       }
00295 
00296 
00297       void SparseData::GetBinData(BinData& bd) const
00298       {
00299          // Created the corresponding BinData
00300 
00301          list<Box>::iterator it = fList->Begin();
00302          const unsigned int dim = it->GetMin().size();
00303 
00304          bd.Initialize(fList->GetList().size(), dim); 
00305          // Visit all the stored Boxes
00306          for ( ; it != fList->End(); ++it )
00307          {
00308             vector<double> mid(dim);
00309             // fill up the vector with the mid point of the Bin
00310             for ( unsigned int i = 0; i < dim; ++i)
00311             {
00312                mid[i] = ((it->GetMax()[i] - it->GetMin()[i]) /2) + it->GetMin()[i];
00313             }
00314             // And store it into the BinData structure
00315             bd.Add(&mid[0], it->GetVal(), it->GetError());
00316          }
00317       }
00318 
00319       void SparseData::GetBinDataIntegral(BinData& bd) const
00320       {
00321          // Created the corresponding BinData as with the Integral
00322          // option.
00323 
00324          list<Box>::iterator it = fList->Begin();
00325 
00326          bd.Initialize(fList->GetList().size(), it->GetMin().size()); 
00327          // Visit all the stored Boxes
00328          for ( ; it != fList->End(); ++it )
00329          {
00330             //Store the minimum value
00331             bd.Add(&(it->GetMin()[0]), it->GetVal(), it->GetError());
00332             //and the maximum
00333             bd.AddBinUpEdge(&(it->GetMax()[0]));
00334          }
00335       }
00336 
00337       void SparseData::GetBinDataNoZeros(BinData& bd) const
00338       {
00339          // Created the corresponding BinData, but it does not include
00340          // all the data with value equal to 0.
00341 
00342          list<Box>::iterator it = fList->Begin();
00343          const unsigned int dim = it->GetMin().size();
00344 
00345          bd.Initialize(fList->GetList().size(), dim);
00346          // Visit all the stored Boxes
00347          for ( ; it != fList->End(); ++it )
00348          {
00349             // if the value is zero, jump to the next
00350             if ( it->GetVal() == 0 ) continue;
00351             vector<double> mid(dim);
00352             // fill up the vector with the mid point of the Bin
00353             for ( unsigned int i = 0; i < dim; ++i)
00354             {
00355                mid[i] = ((it->GetMax()[i] - it->GetMin()[i]) /2) + it->GetMin()[i];
00356             }
00357             // And store it into the BinData structure
00358             bd.Add(&mid[0], it->GetVal(), it->GetError());
00359          }
00360       }
00361 
00362       // Just for debugging pourposes
00363       ostream& operator <<(ostream& os, const ROOT::Fit::Box& b)
00364       {
00365          os << "min: ";
00366          copy(b.GetMin().begin(), b.GetMin().end(), ostream_iterator<double>(os, " "));
00367          os << "max: ";
00368          copy(b.GetMax().begin(), b.GetMax().end(), ostream_iterator<double>(os, " "));
00369          os << "val: " << b.GetVal();
00370          
00371          return os;
00372       }     
00373    } // end namespace Fit
00374 
00375 } // end namespace ROOT

Generated on Tue Jul 5 14:34:26 2011 for ROOT_528-00b_version by  doxygen 1.5.1