ROOT logo
// Author: Kerstin Tackmann, Andreas Hoecker, Heiko Lacker

/**********************************************************************************
 *                                                                                *
 * Project: TSVDUnfold - data unfolding based on Singular Value Decomposition     *
 * Package: ROOT                                                                  *
 * Class  : TSVDUnfold                                                            *
 *                                                                                *
 * Description:                                                                   *
 *      Single class implementation of SVD data unfolding based on:               *
 *          A. Hoecker, V. Kartvelishvili,                                        *
 *          "SVD approach to data unfolding"                                      *
 *          NIM A372, 469 (1996) [hep-ph/9509307]                                 *
 *                                                                                *
 * Authors:                                                                       *
 *      Kerstin Tackmann <Kerstin.Tackmann@cern.ch>   - CERN, Switzerland         *
 *      Andreas Hoecker  <Andreas.Hoecker@cern.ch>    - CERN, Switzerland         *
 *      Heiko Lacker     <lacker@physik.hu-berlin.de> - Humboldt U, Germany       *
 *                                                                                *
 * Copyright (c) 2010:                                                            *
 *      CERN, Switzerland                                                         *
 *      Humboldt University, Germany                                              *
 *                                                                                *
 **********************************************************************************/

//_______________________________________________________________________
/* Begin_Html
 <center><h2>SVD Approach to Data Unfolding</h2></center>
 <p>
 Reference: <a href="http://arXiv.org/abs/hep-ph/9509307">Nucl. Instrum. Meth. A372, 469 (1996) [hep-ph/9509307]</a>
 <p>
 TSVDUnfold implements the singular value decomposition based unfolding method (see reference). Currently, the unfolding of one-dimensional histograms is supported, with the same number of bins for the measured and the unfolded spectrum.
 <p>
 The unfolding procedure is based on singular value decomposition of the response matrix. The regularisation of the unfolding is implemented via a discrete minimum-curvature condition.
 <p>
 Monte Carlo inputs:
 <ul>
 <li><tt>xini</tt>: true underlying spectrum (TH1D, n bins)
 <li><tt>bini</tt>: reconstructed spectrum (TH1D, n bins)
 <li><tt>Adet</tt>: response matrix (TH2D, nxn bins)
 </ul>
 Consider the unfolding of a measured spectrum <tt>bdat</tt> with covariance matrix <tt>Bcov</tt> (if not passed explicitly, a diagonal covariance will be built given the errors of <tt>bdat</tt>). The corresponding spectrum in the Monte Carlo is given by <tt>bini</tt>, with the true underlying spectrum given by <tt>xini</tt>. The detector response is described by <tt>Adet</tt>, with <tt>Adet</tt> filled with events (not probabilities) with the true observable on the y-axis and the reconstructed observable on the x-axis.
 <p>
 The measured distribution can be unfolded for any combination of resolution, efficiency and acceptance effects, provided an appropriate definition of <tt>xini</tt> and <tt>Adet</tt>.<br><br>
 <p>
 The unfolding can be performed by
 <ul>
 <pre>
 TSVDUnfold *tsvdunf = new TSVDUnfold( bdat, Bcov, bini, xini, Adet );
 TH1D* unfresult = tsvdunf->Unfold( kreg );
 </pre>
 </ul>
 where <tt>kreg</tt> determines the regularisation of the unfolding. In general, overregularisation (too small <tt>kreg</tt>) will bias the unfolded spectrum towards the Monte Carlo input, while underregularisation (too large <tt>kreg</tt>) will lead to large fluctuations in the unfolded spectrum. The optimal regularisation can be determined following guidelines in <a href="http://arXiv.org/abs/hep-ph/9509307">Nucl. Instrum. Meth. A372, 469 (1996) [hep-ph/9509307]</a> using the distribution of the <tt>|d_i|<\tt> that can be obtained by <tt>tsvdunf->GetD()</tt> and/or using pseudo-experiments.
 <p>
 Covariance matrices on the measured spectrum (for either the total uncertainties or individual sources of uncertainties) can be propagated to covariance matrices using the <tt>GetUnfoldCovMatrix</tt> method, which uses pseudo experiments for the propagation. In addition, <tt>GetAdetCovMatrix</tt> allows for the propagation of the statistical uncertainties on the response matrix using pseudo experiments. The covariance matrix corresponding to <tt>Bcov</tt> is also computed as described in <a href="http://arXiv.org/abs/hep-ph/9509307">Nucl. Instrum. Meth. A372, 469 (1996) [hep-ph/9509307]</a> and can be obtained from <tt>tsvdunf->GetXtau()</tt> and its (regularisation independent) inverse from  <tt>tsvdunf->GetXinv()</tt>. The distribution of singular values can be retrieved using <tt>tsvdunf->GetSV()</tt>.
 <p>
 See also the tutorial for a toy example.
 End_Html */
//_______________________________________________________________________


#include <iostream>

#include "TSVDUnfold.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TDecompSVD.h"
#include "TRandom3.h"
#include "TMath.h"

ClassImp(TSVDUnfold)

using namespace std;

//_______________________________________________________________________
TSVDUnfold::TSVDUnfold( const TH1D *bdat, const TH1D *bini, const TH1D *xini, const TH2D *Adet )
: TObject     (),
fNdim       (0),
fDdim       (2),
fNormalize  (kFALSE),
fKReg       (-1),
fDHist      (NULL),
fSVHist     (NULL),
fXtau       (NULL),
fXinv       (NULL),
fBdat       (bdat),
fBini       (bini),
fXini       (xini),
fAdet       (Adet),
fToyhisto   (NULL),
fToymat     (NULL),
fToyMode    (kFALSE),
fMatToyMode (kFALSE)
{
   // Alternative constructor
   // User provides data and MC test spectra, as well as detector response matrix, diagonal covariance matrix of measured spectrum built from the uncertainties on measured spectrum
   if (bdat->GetNbinsX() != bini->GetNbinsX() ||
       bdat->GetNbinsX() != xini->GetNbinsX() ||
       bdat->GetNbinsX() != Adet->GetNbinsX() ||
       bdat->GetNbinsX() != Adet->GetNbinsY()) {
      TString msg = "All histograms must have equal dimension.\n";
      msg += Form( "  Found: dim(bdat)=%i\n",    bdat->GetNbinsX() );
      msg += Form( "  Found: dim(bini)=%i\n",    bini->GetNbinsX() );
      msg += Form( "  Found: dim(xini)=%i\n",    xini->GetNbinsX() );
      msg += Form( "  Found: dim(Adet)=%i,%i\n", Adet->GetNbinsX(), Adet->GetNbinsY() );
      msg += "Please start again!";

      Fatal( "Init", msg, "%s" );
   }

   fBcov = (TH2D*)fAdet->Clone("bcov");

   for(int i=1; i<=fBdat->GetNbinsX(); i++){
      fBcov->SetBinContent(i, i, fBdat->GetBinError(i)*fBdat->GetBinError(i));
      for(int j=1; j<=fBdat->GetNbinsX(); j++){
         if(i==j) continue;
         fBcov->SetBinContent(i,j,0.);
      }
   }
   // Get the input histos
   fNdim = bdat->GetNbinsX();
   fDdim = 2; // This is the derivative used to compute the curvature matrix
}


//_______________________________________________________________________
TSVDUnfold::TSVDUnfold( const TH1D *bdat, TH2D* Bcov, const TH1D *bini, const TH1D *xini, const TH2D *Adet )
: TObject     (),
fNdim       (0),
fDdim       (2),
fNormalize  (kFALSE),
fKReg       (-1),
fDHist      (NULL),
fSVHist     (NULL),
fXtau       (NULL),
fXinv       (NULL),
fBdat       (bdat),
fBcov       (Bcov),
fBini       (bini),
fXini       (xini),
fAdet       (Adet),
fToyhisto   (NULL),
fToymat     (NULL),
fToyMode    (kFALSE),
fMatToyMode (kFALSE)
{
   // Default constructor
   // Initialisation of TSVDUnfold
   // User provides data and MC test spectra, as well as detector response matrix and the covariance matrix of the measured distribution
   if (bdat->GetNbinsX() != bini->GetNbinsX() ||
       bdat->GetNbinsX() != xini->GetNbinsX() ||
       bdat->GetNbinsX() != Bcov->GetNbinsX() ||
       bdat->GetNbinsX() != Bcov->GetNbinsY() ||
       bdat->GetNbinsX() != Adet->GetNbinsX() ||
       bdat->GetNbinsX() != Adet->GetNbinsY()) {
      TString msg = "All histograms must have equal dimension.\n";
      msg += Form( "  Found: dim(bdat)=%i\n",    bdat->GetNbinsX() );
      msg += Form( "  Found: dim(Bcov)=%i,%i\n",    Bcov->GetNbinsX(), Bcov->GetNbinsY() );
      msg += Form( "  Found: dim(bini)=%i\n",    bini->GetNbinsX() );
      msg += Form( "  Found: dim(xini)=%i\n",    xini->GetNbinsX() );
      msg += Form( "  Found: dim(Adet)=%i,%i\n", Adet->GetNbinsX(), Adet->GetNbinsY() );
      msg += "Please start again!";

      Fatal( "Init", msg, "%s" );
   }

   // Get the input histos
   fNdim = bdat->GetNbinsX();
   fDdim = 2; // This is the derivative used to compute the curvature matrix
}

//_______________________________________________________________________
TSVDUnfold::TSVDUnfold( const TSVDUnfold& other )
: TObject     ( other ),
fNdim       (other.fNdim),
fDdim       (other.fDdim),
fNormalize  (other.fNormalize),
fKReg       (other.fKReg),
fDHist      (other.fDHist),
fSVHist     (other.fSVHist),
fXtau       (other.fXtau),
fXinv       (other.fXinv),
fBdat       (other.fBdat),
fBcov       (other.fBcov),
fBini       (other.fBini),
fXini       (other.fXini),
fAdet       (other.fAdet),
fToyhisto   (other.fToyhisto),
fToymat     (other.fToymat),
fToyMode    (other.fToyMode),
fMatToyMode (other.fMatToyMode)
{
   // Copy constructor
}

//_______________________________________________________________________
TSVDUnfold::~TSVDUnfold()
{
   // Destructor
   if(fToyhisto){
      delete fToyhisto;
      fToyhisto = 0;
   }

   if(fToymat){
      delete fToymat;
      fToymat = 0;
   }

   if(fDHist){
      delete fDHist;
      fDHist = 0;
   }

   if(fSVHist){
      delete fSVHist;
      fSVHist = 0;
   }

   if(fXtau){
      delete fXtau;
      fXtau = 0;
   }

   if(fXinv){
      delete fXinv;
      fXinv = 0;
   }

   if(fBcov){
      delete fBcov;
      fBcov = 0;
   }
}

//_______________________________________________________________________
TH1D* TSVDUnfold::Unfold( Int_t kreg )
{
   // Perform the unfolding with regularisation parameter kreg
   fKReg = kreg;

   // Make the histos
   if (!fToyMode && !fMatToyMode) InitHistos( );

   // Create vectors and matrices
   TVectorD vb(fNdim), vbini(fNdim), vxini(fNdim), vberr(fNdim);
   TMatrixD mB(fNdim, fNdim), mA(fNdim, fNdim), mCurv(fNdim, fNdim), mC(fNdim, fNdim);

   Double_t eps = 1e-12;
   Double_t sreg;

   // Copy histogams entries into vector
   if (fToyMode) { H2V( fToyhisto, vb ); H2Verr( fToyhisto, vberr ); }
   else          { H2V( fBdat,     vb ); H2Verr( fBdat,     vberr ); }

   H2M( fBcov, mB);
   H2V( fBini, vbini );
   H2V( fXini, vxini );
   if (fMatToyMode) H2M( fToymat, mA );
   else        H2M( fAdet,   mA );

   // Fill and invert the second derivative matrix
   FillCurvatureMatrix( mCurv, mC );

   // Inversion of mC by help of SVD
   TDecompSVD CSVD(mC);
   TMatrixD CUort = CSVD.GetU();
   TMatrixD CVort = CSVD.GetV();
   TVectorD CSV   = CSVD.GetSig();

   TMatrixD CSVM(fNdim, fNdim);
   for (Int_t i=0; i<fNdim; i++) CSVM(i,i) = 1/CSV(i);

   CUort.Transpose( CUort );
   TMatrixD mCinv = (CVort*CSVM)*CUort;

   //Rescale using the data covariance matrix
   TDecompSVD BSVD( mB );
   TMatrixD QT = BSVD.GetU();
   QT.Transpose(QT);
   TVectorD B2SV = BSVD.GetSig();
   TVectorD BSV(B2SV);

   for(int i=0; i<fNdim; i++){
      BSV(i) = TMath::Sqrt(B2SV(i));
   }
   TMatrixD mAtmp(fNdim,fNdim);
   TVectorD vbtmp(fNdim);
   mAtmp *= 0;
   vbtmp *= 0;
   for(int i=0; i<fNdim; i++){
      for(int j=0; j<fNdim; j++){
         if(BSV(i)){
            vbtmp(i) += QT(i,j)*vb(j)/BSV(i);
         }
         for(int m=0; m<fNdim; m++){
            if(BSV(i)){
               mAtmp(i,j) += QT(i,m)*mA(m,j)/BSV(i);
            }
         }
      }
   }
   mA = mAtmp;
   vb = vbtmp;

   // Singular value decomposition and matrix operations
   TDecompSVD ASVD( mA*mCinv );
   TMatrixD Uort = ASVD.GetU();
   TMatrixD Vort = ASVD.GetV();
   TVectorD ASV  = ASVD.GetSig();

   if (!fToyMode && !fMatToyMode) {
      V2H(ASV, *fSVHist);
   }

   TMatrixD Vreg = mCinv*Vort;

   Uort.Transpose(Uort);
   TVectorD vd    = Uort*vb;

   if (!fToyMode && !fMatToyMode) {
      V2H(vd, *fDHist);
   }

   // Damping coefficient
   Int_t k = GetKReg()-1;

   TVectorD vx(fNdim); // Return variable

   // Damping factors
   TVectorD vdz(fNdim);
   TMatrixD Z(fNdim, fNdim);
   for (Int_t i=0; i<fNdim; i++) {
      if (ASV(i)<ASV(0)*eps) sreg = ASV(0)*eps;
      else                   sreg = ASV(i);
      vdz(i) = sreg/(sreg*sreg + ASV(k)*ASV(k));
      Z(i,i) = vdz(i)*vdz(i);
   }
   TVectorD vz = CompProd( vd, vdz );

   TMatrixD VortT(Vort);
   VortT.Transpose(VortT);
   TMatrixD W = mCinv*Vort*Z*VortT*mCinv;

   TMatrixD Xtau(fNdim, fNdim);
   TMatrixD Xinv(fNdim, fNdim);
   Xtau *= 0;
   Xinv *= 0;
   for (Int_t i=0; i<fNdim; i++) {
      for (Int_t j=0; j<fNdim; j++) {
         Xtau(i,j) =  vxini(i) * vxini(j) * W(i,j);

         double a=0;
         for (Int_t m=0; m<fNdim; m++) {
            a += mA(m,i)*mA(m,j);
         }
         if(vxini(i)*vxini(j))
            Xinv(i,j) = a/vxini(i)/vxini(j);
      }
   }

   // Compute the weights
   TVectorD vw = Vreg*vz;

   // Rescale by xini
   vx = CompProd( vw, vxini );

   if(fNormalize){ // Scale result to unit area
      Double_t scale = vx.Sum();
      if (scale > 0){
         vx *= 1.0/scale;
         Xtau *= 1./scale/scale;
         Xinv *= scale*scale;
      }
   }

   if (!fToyMode && !fMatToyMode) {
      M2H(Xtau, *fXtau);
      M2H(Xinv, *fXinv);
   }

   // Get Curvature and also chi2 in case of MC unfolding
   if (!fToyMode && !fMatToyMode) {
      Info( "Unfold", "Unfolding param: %i",k+1 );
      Info( "Unfold", "Curvature of weight distribution: %f", GetCurvature( vw, mCurv ) );
   }

   TH1D* h = (TH1D*)fBdat->Clone("unfoldingresult");
   for(int i=1; i<=fNdim; i++){
      h->SetBinContent(i,0.);
      h->SetBinError(i,0.);
   }
   V2H( vx, *h );

   return h;
}

//_______________________________________________________________________
TH2D* TSVDUnfold::GetUnfoldCovMatrix( const TH2D* cov, Int_t ntoys, Int_t seed )
{
   // Determine for given input error matrix covariance matrix of unfolded
   // spectrum from toy simulation given the passed covariance matrix on measured spectrum
   // "cov"    - covariance matrix on the measured spectrum, to be propagated
   // "ntoys"  - number of pseudo experiments used for the propagation
   // "seed"   - seed for pseudo experiments
   // Note that this covariance matrix will contain effects of forced normalisation if spectrum is normalised to unit area.

   fToyMode = true;
   TH1D* unfres = 0;
   TH2D* unfcov = (TH2D*)fAdet->Clone("unfcovmat");
   unfcov->SetTitle("Toy covariance matrix");
   for(int i=1; i<=fNdim; i++)
      for(int j=1; j<=fNdim; j++)
         unfcov->SetBinContent(i,j,0.);

   // Code for generation of toys (taken from RooResult and modified)
   // Calculate the elements of the upper-triangular matrix L that
   // gives Lt*L = C, where Lt is the transpose of L (the "square-root method")
   TMatrixD L(fNdim,fNdim); L *= 0;

   for (Int_t iPar= 0; iPar < fNdim; iPar++) {

      // Calculate the diagonal term first
      L(iPar,iPar) = cov->GetBinContent(iPar+1,iPar+1);
      for (Int_t k=0; k<iPar; k++) L(iPar,iPar) -= TMath::Power( L(k,iPar), 2 );
      if (L(iPar,iPar) > 0.0) L(iPar,iPar) = TMath::Sqrt(L(iPar,iPar));
      else                    L(iPar,iPar) = 0.0;

      // ...then the off-diagonal terms
      for (Int_t jPar=iPar+1; jPar<fNdim; jPar++) {
         L(iPar,jPar) = cov->GetBinContent(iPar+1,jPar+1);
         for (Int_t k=0; k<iPar; k++) L(iPar,jPar) -= L(k,iPar)*L(k,jPar);
         if (L(iPar,iPar)!=0.) L(iPar,jPar) /= L(iPar,iPar);
         else                  L(iPar,jPar) = 0;
      }
   }

   // Remember it
   TMatrixD *Lt = new TMatrixD(TMatrixD::kTransposed,L);
   TRandom3 random(seed);

   fToyhisto = (TH1D*)fBdat->Clone("toyhisto");
   TH1D *toymean = (TH1D*)fBdat->Clone("toymean");
   for (Int_t j=1; j<=fNdim; j++) toymean->SetBinContent(j,0.);

   // Get the mean of the toys first
   for (int i=1; i<=ntoys; i++) {

      // create a vector of unit Gaussian variables
      TVectorD g(fNdim);
      for (Int_t k= 0; k < fNdim; k++) g(k) = random.Gaus(0.,1.);

      // Multiply this vector by Lt to introduce the appropriate correlations
      g *= (*Lt);

      // Add the mean value offsets and store the results
      for (int j=1; j<=fNdim; j++) {
         fToyhisto->SetBinContent(j,fBdat->GetBinContent(j)+g(j-1));
         fToyhisto->SetBinError(j,fBdat->GetBinError(j));
      }

      unfres = Unfold(GetKReg());

      for (Int_t j=1; j<=fNdim; j++) {
         toymean->SetBinContent(j, toymean->GetBinContent(j) + unfres->GetBinContent(j)/ntoys);
      }
      delete unfres;
      unfres = 0;
   }

   // Reset the random seed
   random.SetSeed(seed);

   //Now the toys for the covariance matrix
   for (int i=1; i<=ntoys; i++) {

      // Create a vector of unit Gaussian variables
      TVectorD g(fNdim);
      for (Int_t k= 0; k < fNdim; k++) g(k) = random.Gaus(0.,1.);

      // Multiply this vector by Lt to introduce the appropriate correlations
      g *= (*Lt);

      // Add the mean value offsets and store the results
      for (int j=1; j<=fNdim; j++) {
         fToyhisto->SetBinContent( j, fBdat->GetBinContent(j)+g(j-1) );
         fToyhisto->SetBinError  ( j, fBdat->GetBinError(j) );
      }
      unfres = Unfold(GetKReg());

      for (Int_t j=1; j<=fNdim; j++) {
         for (Int_t k=1; k<=fNdim; k++) {
            unfcov->SetBinContent(j,k,unfcov->GetBinContent(j,k) + ( (unfres->GetBinContent(j) - toymean->GetBinContent(j))* (unfres->GetBinContent(k) - toymean->GetBinContent(k))/(ntoys-1)) );
         }
      }
      delete unfres;
      unfres = 0;
   }
   delete Lt;
   delete toymean;
   fToyMode = kFALSE;

   return unfcov;
}

//_______________________________________________________________________
TH2D* TSVDUnfold::GetAdetCovMatrix( Int_t ntoys, Int_t seed )
{
   // Determine covariance matrix of unfolded spectrum from finite statistics in
   // response matrix using pseudo experiments
   // "ntoys"  - number of pseudo experiments used for the propagation
   // "seed"   - seed for pseudo experiments

   fMatToyMode = true;
   TH1D* unfres = 0;
   TH2D* unfcov = (TH2D*)fAdet->Clone("unfcovmat");
   unfcov->SetTitle("Toy covariance matrix");
   for(int i=1; i<=fNdim; i++)
      for(int j=1; j<=fNdim; j++)
         unfcov->SetBinContent(i,j,0.);

   //Now the toys for the detector response matrix
   TRandom3 random(seed);

   fToymat = (TH2D*)fAdet->Clone("toymat");
   TH1D *toymean = (TH1D*)fXini->Clone("toymean");
   for (Int_t j=1; j<=fNdim; j++) toymean->SetBinContent(j,0.);

   for (int i=1; i<=ntoys; i++) {
      for (Int_t k=1; k<=fNdim; k++) {
         for (Int_t m=1; m<=fNdim; m++) {
            if (fAdet->GetBinContent(k,m)) {
               fToymat->SetBinContent(k, m, random.Poisson(fAdet->GetBinContent(k,m)));
            }
         }
      }

      unfres = Unfold(GetKReg());

      for (Int_t j=1; j<=fNdim; j++) {
         toymean->SetBinContent(j, toymean->GetBinContent(j) + unfres->GetBinContent(j)/ntoys);
      }
      delete unfres;
      unfres = 0;
   }

   // Reset the random seed
   random.SetSeed(seed);

   for (int i=1; i<=ntoys; i++) {
      for (Int_t k=1; k<=fNdim; k++) {
         for (Int_t m=1; m<=fNdim; m++) {
            if (fAdet->GetBinContent(k,m))
               fToymat->SetBinContent(k, m, random.Poisson(fAdet->GetBinContent(k,m)));
         }
      }

      unfres = Unfold(GetKReg());

      for (Int_t j=1; j<=fNdim; j++) {
         for (Int_t k=1; k<=fNdim; k++) {
            unfcov->SetBinContent(j,k,unfcov->GetBinContent(j,k) + ( (unfres->GetBinContent(j) - toymean->GetBinContent(j))*(unfres->GetBinContent(k) - toymean->GetBinContent(k))/(ntoys-1)) );
         }
      }
      delete unfres;
      unfres = 0;
   }
   delete toymean;
   fMatToyMode = kFALSE;

   return unfcov;
}

//_______________________________________________________________________
TH1D* TSVDUnfold::GetD() const
{
   // Returns d vector (for choosing appropriate regularisation)
   for (int i=1; i<=fDHist->GetNbinsX(); i++) {
      if (fDHist->GetBinContent(i)<0.) fDHist->SetBinContent(i, TMath::Abs(fDHist->GetBinContent(i)));
   }
   return fDHist;
}

//_______________________________________________________________________
TH1D* TSVDUnfold::GetSV() const
{
   // Returns singular values vector
   return fSVHist;
}

//_______________________________________________________________________
TH2D* TSVDUnfold::GetXtau() const
{
   // Returns the computed regularized covariance matrix corresponding to total uncertainties on measured spectrum as passed in the constructor.
   // Note that this covariance matrix will not contain the effects of forced normalization if spectrum is normalized to unit area.
   return fXtau;
}

//_______________________________________________________________________
TH2D* TSVDUnfold::GetXinv() const
{
   // Returns the computed inverse of the covariance matrix
   return fXinv;
}

//_______________________________________________________________________
TH2D* TSVDUnfold::GetBCov() const
{
   // Returns the covariance matrix
   return fBcov;
}

//_______________________________________________________________________
void TSVDUnfold::H2V( const TH1D* histo, TVectorD& vec )
{
   // Fill 1D histogram into vector
   for (Int_t i=0; i<histo->GetNbinsX(); i++) vec(i) = histo->GetBinContent(i+1);
}

//_______________________________________________________________________
void TSVDUnfold::H2Verr( const TH1D* histo, TVectorD& vec )
{
   // Fill 1D histogram errors into vector
   for (Int_t i=0; i<histo->GetNbinsX(); i++) vec(i) = histo->GetBinError(i+1);
}

//_______________________________________________________________________
void TSVDUnfold::V2H( const TVectorD& vec, TH1D& histo )
{
   // Fill vector into 1D histogram
   for(Int_t i=0; i<vec.GetNrows(); i++) histo.SetBinContent(i+1, vec(i));
}

//_______________________________________________________________________
void TSVDUnfold::H2M( const TH2D* histo, TMatrixD& mat )
{
   // Fill 2D histogram into matrix
   for (Int_t j=0; j<histo->GetNbinsX(); j++) {
      for (Int_t i=0; i<histo->GetNbinsY(); i++) {
         mat(i,j) = histo->GetBinContent(i+1,j+1);
      }
   }
}

//_______________________________________________________________________
void TSVDUnfold::M2H( const TMatrixD& mat, TH2D& histo )
{
   // Fill 2D histogram into matrix
   for (Int_t j=0; j<mat.GetNcols(); j++) {
      for (Int_t i=0; i<mat.GetNrows(); i++) {
         histo.SetBinContent(i+1,j+1, mat(i,j));
      }
   }
}

//_______________________________________________________________________
TVectorD TSVDUnfold::VecDiv( const TVectorD& vec1, const TVectorD& vec2, Int_t zero )
{
   // Divide entries of two vectors
   TVectorD quot(vec1.GetNrows());
   for (Int_t i=0; i<vec1.GetNrows(); i++) {
      if (vec2(i) != 0) quot(i) = vec1(i) / vec2(i);
      else {
         if   (zero) quot(i) = 0;
         else        quot(i) = vec1(i);
      }
   }
   return quot;
}

//_______________________________________________________________________
TMatrixD TSVDUnfold::MatDivVec( const TMatrixD& mat, const TVectorD& vec, Int_t zero )
{
   // Divide matrix entries by vector
   TMatrixD quotmat(mat.GetNrows(), mat.GetNcols());
   for (Int_t i=0; i<mat.GetNrows(); i++) {
      for (Int_t j=0; j<mat.GetNcols(); j++) {
         if (vec(i) != 0) quotmat(i,j) = mat(i,j) / vec(i);
         else {
            if   (zero) quotmat(i,j) = 0;
            else        quotmat(i,j) = mat(i,j);
         }
      }
   }
   return quotmat;
}

//_______________________________________________________________________
TVectorD TSVDUnfold::CompProd( const TVectorD& vec1, const TVectorD& vec2 )
{
   // Multiply entries of two vectors
   TVectorD res(vec1.GetNrows());
   for (Int_t i=0; i<vec1.GetNrows(); i++) res(i) = vec1(i) * vec2(i);
   return res;
}

//_______________________________________________________________________
Double_t TSVDUnfold::GetCurvature(const TVectorD& vec, const TMatrixD& curv)
{
   // Compute curvature of vector
   return vec*(curv*vec);
}

//_______________________________________________________________________
void TSVDUnfold::FillCurvatureMatrix( TMatrixD& tCurv, TMatrixD& tC ) const
{
   Double_t eps = 0.00001;

   Int_t ndim = tCurv.GetNrows();

   // Init
   tCurv *= 0;
   tC    *= 0;

   if (fDdim == 0) for (Int_t i=0; i<ndim; i++) tC(i,i) = 1;
   else if (ndim == 1) {
      for (Int_t i=0; i<ndim; i++) {
         if (i < ndim-1) tC(i,i+1) = 1.0;
         tC(i,i) = 1.0;
      }
   }
   else if (fDdim == 2) {
      for (Int_t i=0; i<ndim; i++) {
         if (i > 0)      tC(i,i-1) = 1.0;
         if (i < ndim-1) tC(i,i+1) = 1.0;
         tC(i,i) = -2.0;
      }
      tC(0,0) = -1.0;
      tC(ndim-1,ndim-1) = -1.0;
   }
   else if (fDdim == 3) {
      for (Int_t i=1; i<ndim-2; i++) {
         tC(i,i-1) =  1.0;
         tC(i,i)   = -3.0;
         tC(i,i+1) =  3.0;
         tC(i,i+2) = -1.0;
      }
   }
   else if (fDdim==4) {
      for (Int_t i=0; i<ndim; i++) {
         if (i > 0)      tC(i,i-1) = -4.0;
         if (i < ndim-1) tC(i,i+1) = -4.0;
         if (i > 1)      tC(i,i-2) =  1.0;
         if (i < ndim-2) tC(i,i+2) =  1.0;
         tC(i,i) = 6.0;
      }
      tC(0,0) = 2.0;
      tC(ndim-1,ndim-1) = 2.0;
      tC(0,1) = -3.0;
      tC(ndim-2,ndim-1) = -3.0;
      tC(1,0) = -3.0;
      tC(ndim-1,ndim-2) = -3.0;
      tC(1,1) =  6.0;
      tC(ndim-2,ndim-2) =  6.0;
   }
   else if (fDdim == 5) {
      for (Int_t i=2; i < ndim-3; i++) {
         tC(i,i-2) = 1.0;
         tC(i,i-1) = -5.0;
         tC(i,i)   = 10.0;
         tC(i,i+1) = -10.0;
         tC(i,i+2) = 5.0;
         tC(i,i+3) = -1.0;
      }
   }
   else if (fDdim == 6) {
      for (Int_t i = 3; i < ndim - 3; i++) {
         tC(i,i-3) = 1.0;
         tC(i,i-2) = -6.0;
         tC(i,i-1) = 15.0;
         tC(i,i)   = -20.0;
         tC(i,i+1) = 15.0;
         tC(i,i+2) = -6.0;
         tC(i,i+3) = 1.0;
      }
   }

   // Add epsilon to avoid singularities
   for (Int_t i=0; i<ndim; i++) tC(i,i) = tC(i,i) + eps;

   //Get curvature matrix
   for (Int_t i=0; i<ndim; i++) {
      for (Int_t j=0; j<ndim; j++) {
         for (Int_t k=0; k<ndim; k++) {
            tCurv(i,j) = tCurv(i,j) + tC(k,i)*tC(k,j);
         }
      }
   }
}

//_______________________________________________________________________
void TSVDUnfold::InitHistos( )
{

   fDHist = new TH1D( "dd", "d vector after orthogonal transformation", fNdim, 0, fNdim );
   fDHist->Sumw2();

   fSVHist = new TH1D( "sv", "Singular values of AC^-1", fNdim, 0, fNdim );
   fSVHist->Sumw2();

   fXtau = (TH2D*)fAdet->Clone("Xtau");
   fXtau->SetTitle("Regularized covariance matrix");
   fXtau->Sumw2();

   fXinv = (TH2D*)fAdet->Clone("Xinv");
   fXinv->SetTitle("Inverse covariance matrix");
   fXinv->Sumw2();
}

//_______________________________________________________________________
void TSVDUnfold::RegularisedSymMatInvert( TMatrixDSym& mat, Double_t eps )
{
   // naive regularised inversion cuts off small elements

   // init reduced matrix
   const UInt_t n = mat.GetNrows();
   UInt_t nn = 0;

   UInt_t *ipos = new UInt_t[n];
   //   UInt_t ipos[n];

   // find max diagonal entries
   Double_t ymax = 0;
   for (UInt_t i=0; i<n; i++) if (TMath::Abs(mat[i][i]) > ymax) ymax = TMath::Abs(mat[i][i]);

   for (UInt_t i=0; i<n; i++) {

      // save position of accepted entries
      if (TMath::Abs(mat[i][i])/ymax > eps) ipos[nn++] = i;
   }

   // effective matrix
   TMatrixDSym matwork( nn );
   for (UInt_t in=0; in<nn; in++) for (UInt_t jn=0; jn<nn; jn++) matwork(in,jn) = 0;

   // fill non-zero effective working matrix
   for (UInt_t in=0; in<nn; in++) {

      matwork[in][in] = mat[ipos[in]][ipos[in]];
      for (UInt_t jn=in+1; jn<nn; jn++) {
         matwork[in][jn] = mat[ipos[in]][ipos[jn]];
         matwork[jn][in] = matwork[in][jn];
      }
   }

   // invert
   matwork.Invert();

   // reinitialise old matrix
   for (UInt_t i=0; i<n; i++) for (UInt_t j=0; j<n; j++) mat[i][j] = 0;

   // refill inverted matrix in old one
   for (UInt_t in=0; in<nn; in++) {
      mat[ipos[in]][ipos[in]] = matwork[in][in];
      for (UInt_t jn=in+1; jn<nn; jn++) {
         mat[ipos[in]][ipos[jn]] = matwork[in][jn];
         mat[ipos[jn]][ipos[in]] = mat[ipos[in]][ipos[jn]];
      }
   }
   delete []  ipos;
}

//_______________________________________________________________________
Double_t TSVDUnfold::ComputeChiSquared( const TH1D& truspec, const TH1D& unfspec)
{
   // Helper routine to compute chi-squared between distributions using the computed inverse of the covariance matrix for the unfolded spectrum as given in paper.
   UInt_t n = truspec.GetNbinsX();

   // compute chi2
   Double_t chi2 = 0;
   for (UInt_t i=0; i<n; i++) {
      for (UInt_t j=0; j<n; j++) {
         chi2 += ( (truspec.GetBinContent( i+1 )-unfspec.GetBinContent( i+1 )) *
                  (truspec.GetBinContent( j+1 )-unfspec.GetBinContent( j+1 )) * fXinv->GetBinContent(i+1,j+1) );
      }
   }
   
   return chi2;
}

 TSVDUnfold.cxx:1
 TSVDUnfold.cxx:2
 TSVDUnfold.cxx:3
 TSVDUnfold.cxx:4
 TSVDUnfold.cxx:5
 TSVDUnfold.cxx:6
 TSVDUnfold.cxx:7
 TSVDUnfold.cxx:8
 TSVDUnfold.cxx:9
 TSVDUnfold.cxx:10
 TSVDUnfold.cxx:11
 TSVDUnfold.cxx:12
 TSVDUnfold.cxx:13
 TSVDUnfold.cxx:14
 TSVDUnfold.cxx:15
 TSVDUnfold.cxx:16
 TSVDUnfold.cxx:17
 TSVDUnfold.cxx:18
 TSVDUnfold.cxx:19
 TSVDUnfold.cxx:20
 TSVDUnfold.cxx:21
 TSVDUnfold.cxx:22
 TSVDUnfold.cxx:23
 TSVDUnfold.cxx:24
 TSVDUnfold.cxx:25
 TSVDUnfold.cxx:26
 TSVDUnfold.cxx:27
 TSVDUnfold.cxx:28
 TSVDUnfold.cxx:29
 TSVDUnfold.cxx:30
 TSVDUnfold.cxx:31
 TSVDUnfold.cxx:32
 TSVDUnfold.cxx:33
 TSVDUnfold.cxx:34
 TSVDUnfold.cxx:35
 TSVDUnfold.cxx:36
 TSVDUnfold.cxx:37
 TSVDUnfold.cxx:38
 TSVDUnfold.cxx:39
 TSVDUnfold.cxx:40
 TSVDUnfold.cxx:41
 TSVDUnfold.cxx:42
 TSVDUnfold.cxx:43
 TSVDUnfold.cxx:44
 TSVDUnfold.cxx:45
 TSVDUnfold.cxx:46
 TSVDUnfold.cxx:47
 TSVDUnfold.cxx:48
 TSVDUnfold.cxx:49
 TSVDUnfold.cxx:50
 TSVDUnfold.cxx:51
 TSVDUnfold.cxx:52
 TSVDUnfold.cxx:53
 TSVDUnfold.cxx:54
 TSVDUnfold.cxx:55
 TSVDUnfold.cxx:56
 TSVDUnfold.cxx:57
 TSVDUnfold.cxx:58
 TSVDUnfold.cxx:59
 TSVDUnfold.cxx:60
 TSVDUnfold.cxx:61
 TSVDUnfold.cxx:62
 TSVDUnfold.cxx:63
 TSVDUnfold.cxx:64
 TSVDUnfold.cxx:65
 TSVDUnfold.cxx:66
 TSVDUnfold.cxx:67
 TSVDUnfold.cxx:68
 TSVDUnfold.cxx:69
 TSVDUnfold.cxx:70
 TSVDUnfold.cxx:71
 TSVDUnfold.cxx:72
 TSVDUnfold.cxx:73
 TSVDUnfold.cxx:74
 TSVDUnfold.cxx:75
 TSVDUnfold.cxx:76
 TSVDUnfold.cxx:77
 TSVDUnfold.cxx:78
 TSVDUnfold.cxx:79
 TSVDUnfold.cxx:80
 TSVDUnfold.cxx:81
 TSVDUnfold.cxx:82
 TSVDUnfold.cxx:83
 TSVDUnfold.cxx:84
 TSVDUnfold.cxx:85
 TSVDUnfold.cxx:86
 TSVDUnfold.cxx:87
 TSVDUnfold.cxx:88
 TSVDUnfold.cxx:89
 TSVDUnfold.cxx:90
 TSVDUnfold.cxx:91
 TSVDUnfold.cxx:92
 TSVDUnfold.cxx:93
 TSVDUnfold.cxx:94
 TSVDUnfold.cxx:95
 TSVDUnfold.cxx:96
 TSVDUnfold.cxx:97
 TSVDUnfold.cxx:98
 TSVDUnfold.cxx:99
 TSVDUnfold.cxx:100
 TSVDUnfold.cxx:101
 TSVDUnfold.cxx:102
 TSVDUnfold.cxx:103
 TSVDUnfold.cxx:104
 TSVDUnfold.cxx:105
 TSVDUnfold.cxx:106
 TSVDUnfold.cxx:107
 TSVDUnfold.cxx:108
 TSVDUnfold.cxx:109
 TSVDUnfold.cxx:110
 TSVDUnfold.cxx:111
 TSVDUnfold.cxx:112
 TSVDUnfold.cxx:113
 TSVDUnfold.cxx:114
 TSVDUnfold.cxx:115
 TSVDUnfold.cxx:116
 TSVDUnfold.cxx:117
 TSVDUnfold.cxx:118
 TSVDUnfold.cxx:119
 TSVDUnfold.cxx:120
 TSVDUnfold.cxx:121
 TSVDUnfold.cxx:122
 TSVDUnfold.cxx:123
 TSVDUnfold.cxx:124
 TSVDUnfold.cxx:125
 TSVDUnfold.cxx:126
 TSVDUnfold.cxx:127
 TSVDUnfold.cxx:128
 TSVDUnfold.cxx:129
 TSVDUnfold.cxx:130
 TSVDUnfold.cxx:131
 TSVDUnfold.cxx:132
 TSVDUnfold.cxx:133
 TSVDUnfold.cxx:134
 TSVDUnfold.cxx:135
 TSVDUnfold.cxx:136
 TSVDUnfold.cxx:137
 TSVDUnfold.cxx:138
 TSVDUnfold.cxx:139
 TSVDUnfold.cxx:140
 TSVDUnfold.cxx:141
 TSVDUnfold.cxx:142
 TSVDUnfold.cxx:143
 TSVDUnfold.cxx:144
 TSVDUnfold.cxx:145
 TSVDUnfold.cxx:146
 TSVDUnfold.cxx:147
 TSVDUnfold.cxx:148
 TSVDUnfold.cxx:149
 TSVDUnfold.cxx:150
 TSVDUnfold.cxx:151
 TSVDUnfold.cxx:152
 TSVDUnfold.cxx:153
 TSVDUnfold.cxx:154
 TSVDUnfold.cxx:155
 TSVDUnfold.cxx:156
 TSVDUnfold.cxx:157
 TSVDUnfold.cxx:158
 TSVDUnfold.cxx:159
 TSVDUnfold.cxx:160
 TSVDUnfold.cxx:161
 TSVDUnfold.cxx:162
 TSVDUnfold.cxx:163
 TSVDUnfold.cxx:164
 TSVDUnfold.cxx:165
 TSVDUnfold.cxx:166
 TSVDUnfold.cxx:167
 TSVDUnfold.cxx:168
 TSVDUnfold.cxx:169
 TSVDUnfold.cxx:170
 TSVDUnfold.cxx:171
 TSVDUnfold.cxx:172
 TSVDUnfold.cxx:173
 TSVDUnfold.cxx:174
 TSVDUnfold.cxx:175
 TSVDUnfold.cxx:176
 TSVDUnfold.cxx:177
 TSVDUnfold.cxx:178
 TSVDUnfold.cxx:179
 TSVDUnfold.cxx:180
 TSVDUnfold.cxx:181
 TSVDUnfold.cxx:182
 TSVDUnfold.cxx:183
 TSVDUnfold.cxx:184
 TSVDUnfold.cxx:185
 TSVDUnfold.cxx:186
 TSVDUnfold.cxx:187
 TSVDUnfold.cxx:188
 TSVDUnfold.cxx:189
 TSVDUnfold.cxx:190
 TSVDUnfold.cxx:191
 TSVDUnfold.cxx:192
 TSVDUnfold.cxx:193
 TSVDUnfold.cxx:194
 TSVDUnfold.cxx:195
 TSVDUnfold.cxx:196
 TSVDUnfold.cxx:197
 TSVDUnfold.cxx:198
 TSVDUnfold.cxx:199
 TSVDUnfold.cxx:200
 TSVDUnfold.cxx:201
 TSVDUnfold.cxx:202
 TSVDUnfold.cxx:203
 TSVDUnfold.cxx:204
 TSVDUnfold.cxx:205
 TSVDUnfold.cxx:206
 TSVDUnfold.cxx:207
 TSVDUnfold.cxx:208
 TSVDUnfold.cxx:209
 TSVDUnfold.cxx:210
 TSVDUnfold.cxx:211
 TSVDUnfold.cxx:212
 TSVDUnfold.cxx:213
 TSVDUnfold.cxx:214
 TSVDUnfold.cxx:215
 TSVDUnfold.cxx:216
 TSVDUnfold.cxx:217
 TSVDUnfold.cxx:218
 TSVDUnfold.cxx:219
 TSVDUnfold.cxx:220
 TSVDUnfold.cxx:221
 TSVDUnfold.cxx:222
 TSVDUnfold.cxx:223
 TSVDUnfold.cxx:224
 TSVDUnfold.cxx:225
 TSVDUnfold.cxx:226
 TSVDUnfold.cxx:227
 TSVDUnfold.cxx:228
 TSVDUnfold.cxx:229
 TSVDUnfold.cxx:230
 TSVDUnfold.cxx:231
 TSVDUnfold.cxx:232
 TSVDUnfold.cxx:233
 TSVDUnfold.cxx:234
 TSVDUnfold.cxx:235
 TSVDUnfold.cxx:236
 TSVDUnfold.cxx:237
 TSVDUnfold.cxx:238
 TSVDUnfold.cxx:239
 TSVDUnfold.cxx:240
 TSVDUnfold.cxx:241
 TSVDUnfold.cxx:242
 TSVDUnfold.cxx:243
 TSVDUnfold.cxx:244
 TSVDUnfold.cxx:245
 TSVDUnfold.cxx:246
 TSVDUnfold.cxx:247
 TSVDUnfold.cxx:248
 TSVDUnfold.cxx:249
 TSVDUnfold.cxx:250
 TSVDUnfold.cxx:251
 TSVDUnfold.cxx:252
 TSVDUnfold.cxx:253
 TSVDUnfold.cxx:254
 TSVDUnfold.cxx:255
 TSVDUnfold.cxx:256
 TSVDUnfold.cxx:257
 TSVDUnfold.cxx:258
 TSVDUnfold.cxx:259
 TSVDUnfold.cxx:260
 TSVDUnfold.cxx:261
 TSVDUnfold.cxx:262
 TSVDUnfold.cxx:263
 TSVDUnfold.cxx:264
 TSVDUnfold.cxx:265
 TSVDUnfold.cxx:266
 TSVDUnfold.cxx:267
 TSVDUnfold.cxx:268
 TSVDUnfold.cxx:269
 TSVDUnfold.cxx:270
 TSVDUnfold.cxx:271
 TSVDUnfold.cxx:272
 TSVDUnfold.cxx:273
 TSVDUnfold.cxx:274
 TSVDUnfold.cxx:275
 TSVDUnfold.cxx:276
 TSVDUnfold.cxx:277
 TSVDUnfold.cxx:278
 TSVDUnfold.cxx:279
 TSVDUnfold.cxx:280
 TSVDUnfold.cxx:281
 TSVDUnfold.cxx:282
 TSVDUnfold.cxx:283
 TSVDUnfold.cxx:284
 TSVDUnfold.cxx:285
 TSVDUnfold.cxx:286
 TSVDUnfold.cxx:287
 TSVDUnfold.cxx:288
 TSVDUnfold.cxx:289
 TSVDUnfold.cxx:290
 TSVDUnfold.cxx:291
 TSVDUnfold.cxx:292
 TSVDUnfold.cxx:293
 TSVDUnfold.cxx:294
 TSVDUnfold.cxx:295
 TSVDUnfold.cxx:296
 TSVDUnfold.cxx:297
 TSVDUnfold.cxx:298
 TSVDUnfold.cxx:299
 TSVDUnfold.cxx:300
 TSVDUnfold.cxx:301
 TSVDUnfold.cxx:302
 TSVDUnfold.cxx:303
 TSVDUnfold.cxx:304
 TSVDUnfold.cxx:305
 TSVDUnfold.cxx:306
 TSVDUnfold.cxx:307
 TSVDUnfold.cxx:308
 TSVDUnfold.cxx:309
 TSVDUnfold.cxx:310
 TSVDUnfold.cxx:311
 TSVDUnfold.cxx:312
 TSVDUnfold.cxx:313
 TSVDUnfold.cxx:314
 TSVDUnfold.cxx:315
 TSVDUnfold.cxx:316
 TSVDUnfold.cxx:317
 TSVDUnfold.cxx:318
 TSVDUnfold.cxx:319
 TSVDUnfold.cxx:320
 TSVDUnfold.cxx:321
 TSVDUnfold.cxx:322
 TSVDUnfold.cxx:323
 TSVDUnfold.cxx:324
 TSVDUnfold.cxx:325
 TSVDUnfold.cxx:326
 TSVDUnfold.cxx:327
 TSVDUnfold.cxx:328
 TSVDUnfold.cxx:329
 TSVDUnfold.cxx:330
 TSVDUnfold.cxx:331
 TSVDUnfold.cxx:332
 TSVDUnfold.cxx:333
 TSVDUnfold.cxx:334
 TSVDUnfold.cxx:335
 TSVDUnfold.cxx:336
 TSVDUnfold.cxx:337
 TSVDUnfold.cxx:338
 TSVDUnfold.cxx:339
 TSVDUnfold.cxx:340
 TSVDUnfold.cxx:341
 TSVDUnfold.cxx:342
 TSVDUnfold.cxx:343
 TSVDUnfold.cxx:344
 TSVDUnfold.cxx:345
 TSVDUnfold.cxx:346
 TSVDUnfold.cxx:347
 TSVDUnfold.cxx:348
 TSVDUnfold.cxx:349
 TSVDUnfold.cxx:350
 TSVDUnfold.cxx:351
 TSVDUnfold.cxx:352
 TSVDUnfold.cxx:353
 TSVDUnfold.cxx:354
 TSVDUnfold.cxx:355
 TSVDUnfold.cxx:356
 TSVDUnfold.cxx:357
 TSVDUnfold.cxx:358
 TSVDUnfold.cxx:359
 TSVDUnfold.cxx:360
 TSVDUnfold.cxx:361
 TSVDUnfold.cxx:362
 TSVDUnfold.cxx:363
 TSVDUnfold.cxx:364
 TSVDUnfold.cxx:365
 TSVDUnfold.cxx:366
 TSVDUnfold.cxx:367
 TSVDUnfold.cxx:368
 TSVDUnfold.cxx:369
 TSVDUnfold.cxx:370
 TSVDUnfold.cxx:371
 TSVDUnfold.cxx:372
 TSVDUnfold.cxx:373
 TSVDUnfold.cxx:374
 TSVDUnfold.cxx:375
 TSVDUnfold.cxx:376
 TSVDUnfold.cxx:377
 TSVDUnfold.cxx:378
 TSVDUnfold.cxx:379
 TSVDUnfold.cxx:380
 TSVDUnfold.cxx:381
 TSVDUnfold.cxx:382
 TSVDUnfold.cxx:383
 TSVDUnfold.cxx:384
 TSVDUnfold.cxx:385
 TSVDUnfold.cxx:386
 TSVDUnfold.cxx:387
 TSVDUnfold.cxx:388
 TSVDUnfold.cxx:389
 TSVDUnfold.cxx:390
 TSVDUnfold.cxx:391
 TSVDUnfold.cxx:392
 TSVDUnfold.cxx:393
 TSVDUnfold.cxx:394
 TSVDUnfold.cxx:395
 TSVDUnfold.cxx:396
 TSVDUnfold.cxx:397
 TSVDUnfold.cxx:398
 TSVDUnfold.cxx:399
 TSVDUnfold.cxx:400
 TSVDUnfold.cxx:401
 TSVDUnfold.cxx:402
 TSVDUnfold.cxx:403
 TSVDUnfold.cxx:404
 TSVDUnfold.cxx:405
 TSVDUnfold.cxx:406
 TSVDUnfold.cxx:407
 TSVDUnfold.cxx:408
 TSVDUnfold.cxx:409
 TSVDUnfold.cxx:410
 TSVDUnfold.cxx:411
 TSVDUnfold.cxx:412
 TSVDUnfold.cxx:413
 TSVDUnfold.cxx:414
 TSVDUnfold.cxx:415
 TSVDUnfold.cxx:416
 TSVDUnfold.cxx:417
 TSVDUnfold.cxx:418
 TSVDUnfold.cxx:419
 TSVDUnfold.cxx:420
 TSVDUnfold.cxx:421
 TSVDUnfold.cxx:422
 TSVDUnfold.cxx:423
 TSVDUnfold.cxx:424
 TSVDUnfold.cxx:425
 TSVDUnfold.cxx:426
 TSVDUnfold.cxx:427
 TSVDUnfold.cxx:428
 TSVDUnfold.cxx:429
 TSVDUnfold.cxx:430
 TSVDUnfold.cxx:431
 TSVDUnfold.cxx:432
 TSVDUnfold.cxx:433
 TSVDUnfold.cxx:434
 TSVDUnfold.cxx:435
 TSVDUnfold.cxx:436
 TSVDUnfold.cxx:437
 TSVDUnfold.cxx:438
 TSVDUnfold.cxx:439
 TSVDUnfold.cxx:440
 TSVDUnfold.cxx:441
 TSVDUnfold.cxx:442
 TSVDUnfold.cxx:443
 TSVDUnfold.cxx:444
 TSVDUnfold.cxx:445
 TSVDUnfold.cxx:446
 TSVDUnfold.cxx:447
 TSVDUnfold.cxx:448
 TSVDUnfold.cxx:449
 TSVDUnfold.cxx:450
 TSVDUnfold.cxx:451
 TSVDUnfold.cxx:452
 TSVDUnfold.cxx:453
 TSVDUnfold.cxx:454
 TSVDUnfold.cxx:455
 TSVDUnfold.cxx:456
 TSVDUnfold.cxx:457
 TSVDUnfold.cxx:458
 TSVDUnfold.cxx:459
 TSVDUnfold.cxx:460
 TSVDUnfold.cxx:461
 TSVDUnfold.cxx:462
 TSVDUnfold.cxx:463
 TSVDUnfold.cxx:464
 TSVDUnfold.cxx:465
 TSVDUnfold.cxx:466
 TSVDUnfold.cxx:467
 TSVDUnfold.cxx:468
 TSVDUnfold.cxx:469
 TSVDUnfold.cxx:470
 TSVDUnfold.cxx:471
 TSVDUnfold.cxx:472
 TSVDUnfold.cxx:473
 TSVDUnfold.cxx:474
 TSVDUnfold.cxx:475
 TSVDUnfold.cxx:476
 TSVDUnfold.cxx:477
 TSVDUnfold.cxx:478
 TSVDUnfold.cxx:479
 TSVDUnfold.cxx:480
 TSVDUnfold.cxx:481
 TSVDUnfold.cxx:482
 TSVDUnfold.cxx:483
 TSVDUnfold.cxx:484
 TSVDUnfold.cxx:485
 TSVDUnfold.cxx:486
 TSVDUnfold.cxx:487
 TSVDUnfold.cxx:488
 TSVDUnfold.cxx:489
 TSVDUnfold.cxx:490
 TSVDUnfold.cxx:491
 TSVDUnfold.cxx:492
 TSVDUnfold.cxx:493
 TSVDUnfold.cxx:494
 TSVDUnfold.cxx:495
 TSVDUnfold.cxx:496
 TSVDUnfold.cxx:497
 TSVDUnfold.cxx:498
 TSVDUnfold.cxx:499
 TSVDUnfold.cxx:500
 TSVDUnfold.cxx:501
 TSVDUnfold.cxx:502
 TSVDUnfold.cxx:503
 TSVDUnfold.cxx:504
 TSVDUnfold.cxx:505
 TSVDUnfold.cxx:506
 TSVDUnfold.cxx:507
 TSVDUnfold.cxx:508
 TSVDUnfold.cxx:509
 TSVDUnfold.cxx:510
 TSVDUnfold.cxx:511
 TSVDUnfold.cxx:512
 TSVDUnfold.cxx:513
 TSVDUnfold.cxx:514
 TSVDUnfold.cxx:515
 TSVDUnfold.cxx:516
 TSVDUnfold.cxx:517
 TSVDUnfold.cxx:518
 TSVDUnfold.cxx:519
 TSVDUnfold.cxx:520
 TSVDUnfold.cxx:521
 TSVDUnfold.cxx:522
 TSVDUnfold.cxx:523
 TSVDUnfold.cxx:524
 TSVDUnfold.cxx:525
 TSVDUnfold.cxx:526
 TSVDUnfold.cxx:527
 TSVDUnfold.cxx:528
 TSVDUnfold.cxx:529
 TSVDUnfold.cxx:530
 TSVDUnfold.cxx:531
 TSVDUnfold.cxx:532
 TSVDUnfold.cxx:533
 TSVDUnfold.cxx:534
 TSVDUnfold.cxx:535
 TSVDUnfold.cxx:536
 TSVDUnfold.cxx:537
 TSVDUnfold.cxx:538
 TSVDUnfold.cxx:539
 TSVDUnfold.cxx:540
 TSVDUnfold.cxx:541
 TSVDUnfold.cxx:542
 TSVDUnfold.cxx:543
 TSVDUnfold.cxx:544
 TSVDUnfold.cxx:545
 TSVDUnfold.cxx:546
 TSVDUnfold.cxx:547
 TSVDUnfold.cxx:548
 TSVDUnfold.cxx:549
 TSVDUnfold.cxx:550
 TSVDUnfold.cxx:551
 TSVDUnfold.cxx:552
 TSVDUnfold.cxx:553
 TSVDUnfold.cxx:554
 TSVDUnfold.cxx:555
 TSVDUnfold.cxx:556
 TSVDUnfold.cxx:557
 TSVDUnfold.cxx:558
 TSVDUnfold.cxx:559
 TSVDUnfold.cxx:560
 TSVDUnfold.cxx:561
 TSVDUnfold.cxx:562
 TSVDUnfold.cxx:563
 TSVDUnfold.cxx:564
 TSVDUnfold.cxx:565
 TSVDUnfold.cxx:566
 TSVDUnfold.cxx:567
 TSVDUnfold.cxx:568
 TSVDUnfold.cxx:569
 TSVDUnfold.cxx:570
 TSVDUnfold.cxx:571
 TSVDUnfold.cxx:572
 TSVDUnfold.cxx:573
 TSVDUnfold.cxx:574
 TSVDUnfold.cxx:575
 TSVDUnfold.cxx:576
 TSVDUnfold.cxx:577
 TSVDUnfold.cxx:578
 TSVDUnfold.cxx:579
 TSVDUnfold.cxx:580
 TSVDUnfold.cxx:581
 TSVDUnfold.cxx:582
 TSVDUnfold.cxx:583
 TSVDUnfold.cxx:584
 TSVDUnfold.cxx:585
 TSVDUnfold.cxx:586
 TSVDUnfold.cxx:587
 TSVDUnfold.cxx:588
 TSVDUnfold.cxx:589
 TSVDUnfold.cxx:590
 TSVDUnfold.cxx:591
 TSVDUnfold.cxx:592
 TSVDUnfold.cxx:593
 TSVDUnfold.cxx:594
 TSVDUnfold.cxx:595
 TSVDUnfold.cxx:596
 TSVDUnfold.cxx:597
 TSVDUnfold.cxx:598
 TSVDUnfold.cxx:599
 TSVDUnfold.cxx:600
 TSVDUnfold.cxx:601
 TSVDUnfold.cxx:602
 TSVDUnfold.cxx:603
 TSVDUnfold.cxx:604
 TSVDUnfold.cxx:605
 TSVDUnfold.cxx:606
 TSVDUnfold.cxx:607
 TSVDUnfold.cxx:608
 TSVDUnfold.cxx:609
 TSVDUnfold.cxx:610
 TSVDUnfold.cxx:611
 TSVDUnfold.cxx:612
 TSVDUnfold.cxx:613
 TSVDUnfold.cxx:614
 TSVDUnfold.cxx:615
 TSVDUnfold.cxx:616
 TSVDUnfold.cxx:617
 TSVDUnfold.cxx:618
 TSVDUnfold.cxx:619
 TSVDUnfold.cxx:620
 TSVDUnfold.cxx:621
 TSVDUnfold.cxx:622
 TSVDUnfold.cxx:623
 TSVDUnfold.cxx:624
 TSVDUnfold.cxx:625
 TSVDUnfold.cxx:626
 TSVDUnfold.cxx:627
 TSVDUnfold.cxx:628
 TSVDUnfold.cxx:629
 TSVDUnfold.cxx:630
 TSVDUnfold.cxx:631
 TSVDUnfold.cxx:632
 TSVDUnfold.cxx:633
 TSVDUnfold.cxx:634
 TSVDUnfold.cxx:635
 TSVDUnfold.cxx:636
 TSVDUnfold.cxx:637
 TSVDUnfold.cxx:638
 TSVDUnfold.cxx:639
 TSVDUnfold.cxx:640
 TSVDUnfold.cxx:641
 TSVDUnfold.cxx:642
 TSVDUnfold.cxx:643
 TSVDUnfold.cxx:644
 TSVDUnfold.cxx:645
 TSVDUnfold.cxx:646
 TSVDUnfold.cxx:647
 TSVDUnfold.cxx:648
 TSVDUnfold.cxx:649
 TSVDUnfold.cxx:650
 TSVDUnfold.cxx:651
 TSVDUnfold.cxx:652
 TSVDUnfold.cxx:653
 TSVDUnfold.cxx:654
 TSVDUnfold.cxx:655
 TSVDUnfold.cxx:656
 TSVDUnfold.cxx:657
 TSVDUnfold.cxx:658
 TSVDUnfold.cxx:659
 TSVDUnfold.cxx:660
 TSVDUnfold.cxx:661
 TSVDUnfold.cxx:662
 TSVDUnfold.cxx:663
 TSVDUnfold.cxx:664
 TSVDUnfold.cxx:665
 TSVDUnfold.cxx:666
 TSVDUnfold.cxx:667
 TSVDUnfold.cxx:668
 TSVDUnfold.cxx:669
 TSVDUnfold.cxx:670
 TSVDUnfold.cxx:671
 TSVDUnfold.cxx:672
 TSVDUnfold.cxx:673
 TSVDUnfold.cxx:674
 TSVDUnfold.cxx:675
 TSVDUnfold.cxx:676
 TSVDUnfold.cxx:677
 TSVDUnfold.cxx:678
 TSVDUnfold.cxx:679
 TSVDUnfold.cxx:680
 TSVDUnfold.cxx:681
 TSVDUnfold.cxx:682
 TSVDUnfold.cxx:683
 TSVDUnfold.cxx:684
 TSVDUnfold.cxx:685
 TSVDUnfold.cxx:686
 TSVDUnfold.cxx:687
 TSVDUnfold.cxx:688
 TSVDUnfold.cxx:689
 TSVDUnfold.cxx:690
 TSVDUnfold.cxx:691
 TSVDUnfold.cxx:692
 TSVDUnfold.cxx:693
 TSVDUnfold.cxx:694
 TSVDUnfold.cxx:695
 TSVDUnfold.cxx:696
 TSVDUnfold.cxx:697
 TSVDUnfold.cxx:698
 TSVDUnfold.cxx:699
 TSVDUnfold.cxx:700
 TSVDUnfold.cxx:701
 TSVDUnfold.cxx:702
 TSVDUnfold.cxx:703
 TSVDUnfold.cxx:704
 TSVDUnfold.cxx:705
 TSVDUnfold.cxx:706
 TSVDUnfold.cxx:707
 TSVDUnfold.cxx:708
 TSVDUnfold.cxx:709
 TSVDUnfold.cxx:710
 TSVDUnfold.cxx:711
 TSVDUnfold.cxx:712
 TSVDUnfold.cxx:713
 TSVDUnfold.cxx:714
 TSVDUnfold.cxx:715
 TSVDUnfold.cxx:716
 TSVDUnfold.cxx:717
 TSVDUnfold.cxx:718
 TSVDUnfold.cxx:719
 TSVDUnfold.cxx:720
 TSVDUnfold.cxx:721
 TSVDUnfold.cxx:722
 TSVDUnfold.cxx:723
 TSVDUnfold.cxx:724
 TSVDUnfold.cxx:725
 TSVDUnfold.cxx:726
 TSVDUnfold.cxx:727
 TSVDUnfold.cxx:728
 TSVDUnfold.cxx:729
 TSVDUnfold.cxx:730
 TSVDUnfold.cxx:731
 TSVDUnfold.cxx:732
 TSVDUnfold.cxx:733
 TSVDUnfold.cxx:734
 TSVDUnfold.cxx:735
 TSVDUnfold.cxx:736
 TSVDUnfold.cxx:737
 TSVDUnfold.cxx:738
 TSVDUnfold.cxx:739
 TSVDUnfold.cxx:740
 TSVDUnfold.cxx:741
 TSVDUnfold.cxx:742
 TSVDUnfold.cxx:743
 TSVDUnfold.cxx:744
 TSVDUnfold.cxx:745
 TSVDUnfold.cxx:746
 TSVDUnfold.cxx:747
 TSVDUnfold.cxx:748
 TSVDUnfold.cxx:749
 TSVDUnfold.cxx:750
 TSVDUnfold.cxx:751
 TSVDUnfold.cxx:752
 TSVDUnfold.cxx:753
 TSVDUnfold.cxx:754
 TSVDUnfold.cxx:755
 TSVDUnfold.cxx:756
 TSVDUnfold.cxx:757
 TSVDUnfold.cxx:758
 TSVDUnfold.cxx:759
 TSVDUnfold.cxx:760
 TSVDUnfold.cxx:761
 TSVDUnfold.cxx:762
 TSVDUnfold.cxx:763
 TSVDUnfold.cxx:764
 TSVDUnfold.cxx:765
 TSVDUnfold.cxx:766
 TSVDUnfold.cxx:767
 TSVDUnfold.cxx:768
 TSVDUnfold.cxx:769
 TSVDUnfold.cxx:770
 TSVDUnfold.cxx:771
 TSVDUnfold.cxx:772
 TSVDUnfold.cxx:773
 TSVDUnfold.cxx:774
 TSVDUnfold.cxx:775
 TSVDUnfold.cxx:776
 TSVDUnfold.cxx:777
 TSVDUnfold.cxx:778
 TSVDUnfold.cxx:779
 TSVDUnfold.cxx:780
 TSVDUnfold.cxx:781
 TSVDUnfold.cxx:782
 TSVDUnfold.cxx:783
 TSVDUnfold.cxx:784
 TSVDUnfold.cxx:785
 TSVDUnfold.cxx:786
 TSVDUnfold.cxx:787
 TSVDUnfold.cxx:788
 TSVDUnfold.cxx:789
 TSVDUnfold.cxx:790
 TSVDUnfold.cxx:791
 TSVDUnfold.cxx:792
 TSVDUnfold.cxx:793
 TSVDUnfold.cxx:794
 TSVDUnfold.cxx:795
 TSVDUnfold.cxx:796
 TSVDUnfold.cxx:797
 TSVDUnfold.cxx:798
 TSVDUnfold.cxx:799
 TSVDUnfold.cxx:800
 TSVDUnfold.cxx:801
 TSVDUnfold.cxx:802
 TSVDUnfold.cxx:803
 TSVDUnfold.cxx:804
 TSVDUnfold.cxx:805
 TSVDUnfold.cxx:806
 TSVDUnfold.cxx:807
 TSVDUnfold.cxx:808
 TSVDUnfold.cxx:809
 TSVDUnfold.cxx:810
 TSVDUnfold.cxx:811
 TSVDUnfold.cxx:812
 TSVDUnfold.cxx:813
 TSVDUnfold.cxx:814
 TSVDUnfold.cxx:815
 TSVDUnfold.cxx:816
 TSVDUnfold.cxx:817
 TSVDUnfold.cxx:818
 TSVDUnfold.cxx:819
 TSVDUnfold.cxx:820
 TSVDUnfold.cxx:821
 TSVDUnfold.cxx:822
 TSVDUnfold.cxx:823
 TSVDUnfold.cxx:824
 TSVDUnfold.cxx:825
 TSVDUnfold.cxx:826
 TSVDUnfold.cxx:827
 TSVDUnfold.cxx:828
 TSVDUnfold.cxx:829
 TSVDUnfold.cxx:830
 TSVDUnfold.cxx:831
 TSVDUnfold.cxx:832
 TSVDUnfold.cxx:833
 TSVDUnfold.cxx:834
 TSVDUnfold.cxx:835
 TSVDUnfold.cxx:836
 TSVDUnfold.cxx:837
 TSVDUnfold.cxx:838
 TSVDUnfold.cxx:839
 TSVDUnfold.cxx:840
 TSVDUnfold.cxx:841
 TSVDUnfold.cxx:842
 TSVDUnfold.cxx:843
 TSVDUnfold.cxx:844
 TSVDUnfold.cxx:845
 TSVDUnfold.cxx:846
 TSVDUnfold.cxx:847
 TSVDUnfold.cxx:848
 TSVDUnfold.cxx:849
 TSVDUnfold.cxx:850
 TSVDUnfold.cxx:851
 TSVDUnfold.cxx:852
 TSVDUnfold.cxx:853
 TSVDUnfold.cxx:854
 TSVDUnfold.cxx:855
 TSVDUnfold.cxx:856
 TSVDUnfold.cxx:857
 TSVDUnfold.cxx:858
 TSVDUnfold.cxx:859
 TSVDUnfold.cxx:860
 TSVDUnfold.cxx:861
 TSVDUnfold.cxx:862
 TSVDUnfold.cxx:863
 TSVDUnfold.cxx:864
 TSVDUnfold.cxx:865
 TSVDUnfold.cxx:866
 TSVDUnfold.cxx:867
 TSVDUnfold.cxx:868
 TSVDUnfold.cxx:869
 TSVDUnfold.cxx:870
 TSVDUnfold.cxx:871
 TSVDUnfold.cxx:872
 TSVDUnfold.cxx:873
 TSVDUnfold.cxx:874
 TSVDUnfold.cxx:875
 TSVDUnfold.cxx:876
 TSVDUnfold.cxx:877
 TSVDUnfold.cxx:878
 TSVDUnfold.cxx:879
 TSVDUnfold.cxx:880