TUnfold.cxx

Go to the documentation of this file.
00001 // @(#)root/hist:$Id: TUnfold.cxx 37440 2010-12-09 15:13:46Z moneta $
00002 // Author: Stefan Schmitt
00003 // DESY, 13/10/08
00004 
00005 // Version 16, fix calculation of global correlations, improved error messages
00006 //
00007 //  History:
00008 //    Version 15, simplified L-curve scan, new tau definition, new error calc., area preservation
00009 //    Version 14, with changes in TUnfoldSys.cxx
00010 //    Version 13, new methods for derived classes and small bug fix
00011 //    Version 12, report singular matrices
00012 //    Version 11, reduce the amount of printout
00013 //    Version 10, more correct definition of the L curve, update references
00014 //    Version 9, faster matrix inversion and skip edge points for L-curve scan
00015 //    Version 8, replace all TMatrixSparse matrix operations by private code
00016 //    Version 7, fix problem with TMatrixDSparse,TMatrixD multiplication
00017 //    Version 6, replace class XY by std::pair
00018 //    Version 5, replace run-time dynamic arrays by new and delete[]
00019 //    Version 4, fix new bug from V3 with initial regularisation condition
00020 //    Version 3, fix bug with initial regularisation condition
00021 //    Version 2, with improved ScanLcurve() algorithm
00022 //    Version 1, added ScanLcurve() method
00023 //    Version 0, stable version of basic unfolding algorithm
00024 
00025 ////////////////////////////////////////////////////////////////////////
00026 //
00027 // TUnfold solves the inverse problem
00028 //
00029 //   chi**2 = (y-Ax)# Vyy^-1 (y-Ax) + tau^2 (L(x-x0))# L(x-x0) + lambda sum_i(y_i -(Ax)_i)
00030 //
00031 // where # means that the matrix is transposed
00032 //
00033 // Monte Carlo input
00034 // -----------------
00035 //   y: vector of measured quantities  (dimension ny)
00036 //   Vyy: covariance matrix for y (dimension ny x ny)
00037 //        in many cases V is diagonal and calculated from the errors of y
00038 //   A: migration matrix               (dimension ny x nx)
00039 //   x: unknown underlying distribution (dimension nx)
00040 //
00041 // Regularisation
00042 // --------------
00043 //   tau: parameter, defining the regularisation strength
00044 //   L: matrix of regularisation conditions (dimension nl x nx)
00045 //   x0: bias distribution
00046 //
00047 // Preservation of the area
00048 // ------------------------
00049 //   lambda: lagrangian multiplier
00050 //   y_i: one component of the vector y
00051 //   (Ax)_i: one component of the vector Ax
00052 //                                                                     
00053 // and chi**2 is minimized
00054 //   (a) not constrained: minimisation is performed a function of x for fixed lambda=0
00055 //  or
00056 //   (b) constrained: minimisation is performed a function of x and lambda
00057 //                                                                      
00058 // This applies to a very large number of problems, where the measured
00059 // distribution y is a linear superposition of several Monte Carlo shapes
00060 // and the sum of these shapes gives the output distribution x
00061 //
00062 // The constraint can be useful to reduce biases on the result x
00063 // in cases where the vector y follows non-Gaussian probability densities
00064 // (example: Poisson statistics at counting experiments in particle physics)
00065 //
00066 // Some random examples:
00067 // ======================
00068 //   (1) measure a cross-section as a function of, say, E_T(detector)
00069 //        and unfold it to obtain the underlying distribution E_T(generator)
00070 //   (2) measure a lifetime distribution and unfold the contributions from
00071 //        different flavours
00072 //   (3) measure the transverse mass and decay angle
00073 //        and unfold for the true mass distribution plus background
00074 //
00075 // Documentation
00076 // =============
00077 // Some technical documentation is available here:
00078 //   http://www.desy.de/~sschmitt
00079 //
00080 // References:
00081 // ===========
00082 // A nice overview of the method is given in:
00083 //  The L-curve and Its Use in the Numerical Treatment of Inverse Problems
00084 //  (2000) by P. C. Hansen, in Computational Inverse Problems in
00085 //  Electrocardiology, ed. P. Johnston,
00086 //  Advances in Computational Bioengineering
00087 //  http://www.imm.dtu.dk/~pch/TR/Lcurve.ps 
00088 // The relevant equations are (1), (2) for the unfolding
00089 // and (14) for the L-curve curvature definition
00090 //
00091 // Related literature on unfolding:
00092 //  The program package RUN and the web-page by V.Blobel
00093 //    http://www.desy.de/~blobel/unfold.html
00094 //  Talk by V. Blobel, Terascale Statistics school
00095 //    https://indico.desy.de/contributionDisplay.py?contribId=23&confId=1149
00096 //  References quoted in Blobel's talk:
00097 //   Per Chistian Hansen, Rank-Deficient and Discrete Ill-posed Problems,
00098 //        Siam (1998)
00099 //   Jari Kaipio and Erkki Somersalo, Statistical and Computational 
00100 //        Inverse problems, Springer (2005)
00101 //
00102 //
00103 //
00104 // Implementation
00105 // ==============
00106 // The result of the unfolding is calculated as follows:
00107 //
00108 //    Lsquared = L#L            regularisation conditions squared
00109 //
00110 //    epsilon_j = sum_i A_ij    vector of efficiencies
00111 //
00112 //    E^-1  = ((A# Vyy^-1 A)+tau^2 Lsquared) 
00113 //
00114 //    x = E (A# Vyy^-1 y + tau^2 Lsquared x0 +lambda/2 * epsilon) is the result
00115 //
00116 // The derivatives
00117 //    dx_k/dy_i
00118 //    dx_k/dA_ij
00119 //    dx_k/d(tau^2)
00120 // are calculated for further usage.
00121 //
00122 // The covariance matrix V_xx is calculated as:
00123 //    Vxx_ij = sum_kl dx_i/dy_k Vyy_kl dx_j/dy_l
00124 //
00125 // Warning:
00126 // ========
00127 //  The algorithm is based on "standard" matrix inversion, with the
00128 //  known limitations in numerical accuracy and computing cost for
00129 //  matrices with large dimensions.
00130 //
00131 //  Thus the algorithm should not used for large dimensions of x and y
00132 //    nx should not be much larger than 200
00133 //    ny should not be much larger than 1000
00134 //
00135 //
00136 //
00137 // Example of using TUnfold:
00138 // =========================
00139 // imagine a 2-dimensional histogram is filled, named A
00140 //    y-axis: generated quantity (e.g. 10 bins)
00141 //    x-axis: reconstructed quantity (e.g. 20 bin)
00142 // The data are filled in a 1-dimensional histogram, named y
00143 // Note1: ALWAYS choose a higher number of bins on the reconstructed side
00144 //         as compared to the generated size!
00145 // Note2: the events which are generated but not reconstructed
00146 //         have to be added to the appropriate overflow bins of A
00147 // Note3: make sure all bins have sufficient statistics and their error is
00148 //         non-zero. By default, bins with zero error are simply skipped;
00149 //         however, this may cause problems if You try to unfold something
00150 //         which depends on these input bins.
00151 //
00152 // code fragment (with histograms A and y filled):
00153 //
00154 //      TUnfold unfold(A,TUnfold::kHistMapOutputHoriz);
00155 //      Double_t tau=1.E-4;
00156 //      Double_t biasScale=0.0;
00157 //      unfold.DoUnfold(tau,y,biasScale);
00158 //      TH1D *x=unfold.GetOutput("x","myVariable");
00159 //      TH2D *rhoij=unfold.GetRhoIJ("correlation","myVariable");
00160 //
00161 // will create histograms "x" and "correlation" from A and y.
00162 // if tau is very large, the output is biased to the generated distribution scaled by biasScale
00163 // if tau is very small, the output will show oscillations
00164 // and large entries in the correlation matrix
00165 //
00166 //
00167 // Proper choice of tau
00168 // ====================
00169 // One of the difficult questions is about the choice of tau. The most
00170 // common method is the L-curve method: a two-dimensional curve is plotted
00171 //   x-axis: log10(chisquare)
00172 //   y-axis: log10(regularisation condition)
00173 // In many cases this curve has an L-shape. The best choice of tau is in the
00174 // kink of the L
00175 //
00176 // Within TUnfold a simple version of the L-curve analysis is included.
00177 // It tests a given number of points in a predefined tau-range and searches
00178 // for the maximum of the curvature in the L-curve (kink position). 
00179 // if no tau range is given, the range of teh scan is determied automatically
00180 //
00181 // Example: scan tau and produce the L-curve plot
00182 //
00183 // Code fragment: assume A and y are filled
00184 //
00185 //      TUnfold unfold(A,TUnfold::kHistMapOutputHoriz);
00186 //
00187 //      unfold.SetInput(y);
00188 //
00189 //      Int_t nScan=30;
00190 //      Int_t iBest;
00191 //      TSpline *logTauX,*logTauY;
00192 //      TGraph *lCurve;
00193 //
00194 //      iBest=unfold.ScanLcurve(nScan,0.0,0.0,&lCurve);
00195 //
00196 //      std::cout<<"tau="<<unfold.GetTau()<<"\n";
00197 //
00198 //      TH1D *x=unfold.GetOutput("x","myVariable");
00199 //      TH2D *rhoij=unfold.GetRhoIJ("correlation","myVariable");
00200 //
00201 // This creates
00202 //    logTauX: the L-curve's x-coordinate as a function of log(tau) 
00203 //    logTauY: the L-curve's y-coordinate as a function of log(tau) 
00204 //    lCurve: a graph of the L-curve
00205 //    x,rhoij: unfolding result for best choice of tau
00206 //    iBest: the coordinate/spline knot number with the best choice of tau 
00207 //
00208 // Note: always check the L curve after unfolding. The algorithm is not
00209 //    perfect
00210 //
00211 //
00212 // Bin averaging of the output
00213 // ===========================
00214 // Sometimes it is useful to unfold for a fine binning in x and
00215 // calculate the final result with a smaller number of bins. The advantage
00216 // is a reduction in the correlation coefficients if bins are averaged.
00217 // For this type of averaging the full error matrix has to be used.
00218 // There are methods in TUnfold to support this type of calculation
00219 // Example:
00220 //    The vector x has dimension 49, it consists of 7x7 bins
00221 //      in two variables (Pt,Eta)
00222 //    The unfolding result is to be presented as one-dimensional projections
00223 //    in (Pt) and (Eta)
00224 //    The bins of x are mapped as: bins 1..7 the first Eta bin
00225 //                                 bins 2..14 the second Eta bin
00226 //                                 ...
00227 //                                 bins 1,8,15,... the first Pt bin
00228 //                                 ...
00229 // code fragment:
00230 //
00231 //      TUnfold unfold(A,TUnfold::kHistMapOutputHoriz);
00232 //      Double_t tau=1.E-4;
00233 //      Double_t biasScale=0.0;
00234 //      unfold.DoUnfold(tau,y,biasScale);
00235 //      Int_t binMapEta[49+2];
00236 //      Int_t binMapPt[49+2];
00237 //      // overflow and underflow bins are not used
00238 //      binMapEta[0]=-1;
00239 //      binMapEta[49+1]=-1;
00240 //      binMapPt[0]=-1;
00241 //      binMapPt[49+1]=-1;
00242 //      for(Int_t i=1;i<=49;i++) {
00243 //         // all bins (i) with the same (i-1)/7 are added
00244 //         binMapEta[i] = (i-1)/7 +1;
00245 //         // all bins (i) with the same (i-1)%7 are added
00246 //         binMapPt[i]  = (i-1)%7 +1;
00247 //      }
00248 //      TH1D *etaHist=new TH1D("eta(unfolded)",";eta",7,etamin,etamax);
00249 //      TH1D *etaCorr=new TH2D("eta(unfolded)",";eta;eta",7,etamin,etamax,7,etamin,etamax);
00250 //      TH1D *ptHist=new TH1D("pt(unfolded)",";pt",7,ptmin,ptmax);
00251 //      TH1D *ptCorr=new TH2D("pt(unfolded)",";pt;pt",7,ptmin,ptmax,7,ptmin,ptmax);
00252 //      unfold.GetOutput(etaHist,binMapEta);
00253 //      unfold.GetRhoIJ(etaCorrt,binMapEta);
00254 //      unfold.GetOutput(ptHist,binMapPt);
00255 //      unfold.GetRhoIJ(ptCorrt,binMapPt);
00256 //
00257 //
00258 //
00259 // Alternative Regularisation conditions
00260 // =====================================
00261 // Regularisation is needed for most unfolding problems, in order to avoid
00262 // large oscillations and large correlations on the output bins.
00263 // It means that some extra conditions are applied on the output bins
00264 //
00265 // Within TUnfold these conditions are posed on the difference (x-x0), where
00266 //    x:  unfolding output
00267 //    x0: the bias distribution, by default calculated from
00268 //        the input matrix A. There is a method SetBias() to change the
00269 //        bias distribution. 
00270 //        The 3rd argument to DoUnfold() is a scale factor applied to the bias
00271 //          bias_default[j] = sum_i A[i][j]
00272 //          x0[j] = scaleBias*bias[j]
00273 //        The scale factor can be used to
00274 //         (a) completely suppress the bias by setting it to zero
00275 //         (b) compensate differences in the normalisation between data
00276 //             and Monte Carlo
00277 //
00278 // If the regularisation is strong, i.e. large parameter tau,
00279 // then the distribution x or its derivatives will look like the bias 
00280 // distribution. If the parameter tau is small, the distribution x is 
00281 // independent of the bias.
00282 //
00283 // Three basic types of regularisation are implemented in TUnfold
00284 //
00285 //    condition            regularisation
00286 //  ------------------------------------------------------
00287 //    kRegModeNone         none
00288 //    kRegModeSize         minimize the size of (x-x0)
00289 //    kRegModeDerivative   minimize the 1st derivative of (x-x0)
00290 //    kRegModeCurvature    minimize the 2nd derivative of (x-x0)
00291 //
00292 // kRegModeSize is the regularisation scheme which usually is found in
00293 // literature. In addition, the bias usually is not present
00294 // (bias scale factor is zero).
00295 //
00296 // The non-standard regularisation schemes kRegModeDerivative and 
00297 // kRegModeCurvature have the nice feature that they create correlations
00298 // between x-bins, whereas the non-regularized unfolding tends to create 
00299 // negative correlations between bins. For these regularisation schemes the
00300 // parameter tau could be tuned such that the correlations are smallest, 
00301 // as an alternative to the L-curve method.
00302 //
00303 // If kRegModeSize is chosen or if x is a smooth function through all bins,
00304 // the regularisation condition can be set on all bins together by giving
00305 // the appropriate argument in the constructor (see examples above).
00306 //
00307 // If x is composed of independent groups of bins (for example,
00308 // signal and background binning in two variables), it may be necessary to
00309 // set regularisation conditions for the individual groups of bins.
00310 // In this case,  give  kRegModeNone  in the constructor and specify
00311 // the bin grouping with calls to
00312 //          RegularizeBins()   specify a 1-dimensional group of bins
00313 //          RegularizeBins2D() specify a 2-dimensional group of bins
00314 //
00315 // For ultimate flexibility, the regularisation condition can be set on each
00316 // bin individually
00317 //  -> give  kRegModeNone  in the constructor and use
00318 //      RegularizeSize()        regularize one bin   
00319 //      RegularizeDerivative()  regularize the slope given by two bins
00320 //      RegularizeCurvature()   regularize the curvature given by three bins
00321 
00322 
00323 #include <iostream>
00324 #include <TMatrixD.h>
00325 #include <TMatrixDSparse.h>
00326 #include <TMatrixDSym.h>
00327 #include <TMath.h>
00328 #include <TDecompBK.h>
00329 
00330 #include <TUnfold.h>
00331 
00332 #include <map>
00333 #include <vector>
00334 
00335 
00336 // this option enables the use of Schur complement for matrix inversion
00337 // with large diagonal sub-matrices
00338 #define SCHUR_COMPLEMENT_MATRIX_INVERSION
00339 
00340 // this option enables pre-conditioning of matrices prior to inversion
00341 // This type of preconditioning is expected to improve the numerical
00342 // accuracy for the symmetric and positive definite matrices connected
00343 // to unfolding problems. Also, the determinant is more likely to be non-zero
00344 // in case of non-singular matrices
00345 #define INVERT_WITH_CONDITIONING
00346 
00347 // this option saves the spline of the L curve curvature to a file 
00348 // named splinec.ps for debugging
00349 
00350 //#define DEBUG_LCURVE
00351 
00352 #ifdef DEBUG_LCURVE
00353 #include <TCanvas.h>
00354 #endif
00355 
00356 ClassImp(TUnfold)
00357 //______________________________________________________________________________
00358 
00359 const char *TUnfold::GetTUnfoldVersion(void) {
00360    return TUnfold_VERSION;
00361 }
00362 
00363 
00364 void TUnfold::InitTUnfold(void)
00365 {
00366    // reset all data members
00367    fXToHist.Set(0);
00368    fHistToX.Set(0);
00369    fSumOverY.Set(0);
00370    fA = 0;
00371    fLsquared = 0;
00372    fVyy = 0;
00373    fY = 0;
00374    fX0 = 0;
00375    fTauSquared = 0.0;
00376    fBiasScale = 0.0;
00377    fNdf = 0;
00378    fConstraint = kEConstraintNone;
00379    fRegMode = kRegModeNone;
00380    // output
00381    fVxx = 0;
00382    fX = 0;
00383    fAx = 0;
00384    fChi2A = 0.0;
00385    fLXsquared = 0.0;
00386    fRhoMax = 999.0;
00387    fRhoAvg = -1.0;
00388    fDXDAM[0] = 0;
00389    fDXDAZ[0] = 0;
00390    fDXDAM[1] = 0;
00391    fDXDAZ[1] = 0;
00392    fDXDtauSquared = 0;
00393    fDXDY = 0;
00394    fEinv = 0;
00395    fE = 0;
00396    fVxxInv = 0;
00397 }
00398 
00399 void TUnfold::DeleteMatrix(TMatrixD **m) {
00400    if(*m) delete *m;
00401    *m=0;
00402 }
00403 
00404 void TUnfold::DeleteMatrix(TMatrixDSparse **m) {
00405    if(*m) delete *m;
00406    *m=0;
00407 }
00408 
00409 void TUnfold::ClearResults(void) {
00410    // delete old results (if any)
00411    // this function is virtual, so derived classes may flag their results
00412    // ad non-valid as well
00413    DeleteMatrix(&fVxx);
00414    DeleteMatrix(&fX);
00415    DeleteMatrix(&fAx);
00416    for(Int_t i=0;i<2;i++) {
00417       DeleteMatrix(fDXDAM+i);
00418       DeleteMatrix(fDXDAZ+i);
00419    }
00420    DeleteMatrix(&fDXDtauSquared);
00421    DeleteMatrix(&fDXDY);
00422    DeleteMatrix(&fEinv);
00423    DeleteMatrix(&fE);
00424    DeleteMatrix(&fVxxInv);
00425    fChi2A = 0.0;
00426    fLXsquared = 0.0;
00427    fRhoMax = 999.0;
00428    fRhoAvg = -1.0;
00429 }
00430 
00431 TUnfold::TUnfold(void)
00432 {
00433    // set all matrix pointers to zero
00434    InitTUnfold();
00435 }
00436 
00437 Double_t TUnfold::DoUnfold(void)
00438 {
00439    // main unfolding algorithm. Declared virtual, because other algorithms
00440    // could be implemented
00441    //
00442    // Purpose: unfold y -> x
00443    // Data members required:
00444    //     fA:  matrix to relate x and y
00445    //     fY:  measured data points
00446    //     fX0: bias on x
00447    //     fBiasScale: scale factor for fX0
00448    //     fVyy:  covariance matrix for y
00449    //     fLsquared: regularisation conditions
00450    //     fTauSquared: regularisation strength
00451    //     fConstraint: whether the constraint is applied
00452    // Data members modified:
00453    //     fEinv: inverse of the covariance matrix of x
00454    //     fE:    covariance matrix of x
00455    //     fX:    unfolded data points
00456    //     fDXDY: derivative of x wrt y (for error propagation)
00457    //     fVxx:  error matrix (covariance matrix) on x
00458    //     fAx:   estimate of distribution y from unfolded data
00459    //     fChi2A:  contribution to chi**2 from y-Ax
00460    //     fChi2L:  contribution to chi**2 from L*(x-x0)
00461    //     fDXDtauSquared: derivative of x wrt tau
00462    //     fDXDAM[0,1]: matrix parts of derivative x wrt A
00463    //     fDXDAZ[0,1]: vector parts of derivative x wrt A
00464    //     fRhoMax: maximum global correlation coefficient
00465    //     fRhoAvg: average global correlation coefficient
00466    // return code:
00467    //     fRhoMax   if(fRhoMax>=1.0) then the unfolding has failed!
00468 
00469    ClearResults();
00470 
00471    // get inverse matrix Vyyinv
00472    //   (1) create mapping for data bins, excluding bins with zero error
00473    Int_t ny=fVyy->GetNrows();
00474    const Int_t *vyy_rows=fVyy->GetRowIndexArray();
00475    const Int_t *vyy_cols=fVyy->GetColIndexArray();
00476    const Double_t *vyy_data=fVyy->GetMatrixArray();
00477    Int_t *usedBin=new Int_t[ny];
00478    for(Int_t i=0;i<ny;i++) {
00479       usedBin[i]=0;
00480    }
00481    for(Int_t i=0;i<ny;i++) {
00482       for(Int_t k=vyy_rows[i];k<vyy_rows[i+1];k++) {
00483          if(vyy_data[k]>0.0) {
00484             usedBin[i]++;
00485             usedBin[vyy_cols[k]]++;
00486          }
00487       }
00488    }
00489    Int_t n=0;
00490    Int_t *yToI=new Int_t[ny];
00491    Int_t *iToY=new Int_t[ny];
00492    for(Int_t i=0;i<ny;i++) {
00493       if(usedBin[i]) {
00494          yToI[i]=n;
00495          iToY[n]=i;
00496          n++;
00497       } else {
00498          yToI[i]=-1;
00499       }
00500    }
00501    delete[] usedBin;
00502    // here:
00503    //   n: dimension of non-degenerate error matrix
00504    //   yToI: return non-degenerate bin number (or -1)
00505    //   iToY: convert non-degenerate bin number to original bin number
00506 
00507    //  (2) create copy of Vyy, with unused bins removed
00508    Int_t nn=vyy_rows[ny];
00509    Int_t *vyyred_rows=new Int_t[nn];
00510    Int_t *vyyred_cols=new Int_t[nn];
00511    Double_t *vyyred_data=new Double_t[nn];
00512    nn=0;
00513    for(Int_t i=0;i<ny;i++) {
00514       for(Int_t k=vyy_rows[i];k<vyy_rows[i+1];k++) {
00515          if(vyy_data[k]>0.0) {
00516             vyyred_rows[nn]=yToI[i];
00517             vyyred_cols[nn]=yToI[vyy_cols[k]];
00518             vyyred_data[nn]=vyy_data[k];
00519             nn++;
00520          }
00521       }
00522    }
00523    TMatrixDSparse *vyyred=CreateSparseMatrix
00524       (n,n,nn,vyyred_rows,vyyred_cols,vyyred_data);
00525    delete[] vyyred_rows;
00526    delete[] vyyred_cols;
00527    delete[] vyyred_data;
00528    //   (3) invert this copy of Vyy
00529    TMatrixD *vyyredinv=InvertMSparse(vyyred);
00530    DeleteMatrix(&vyyred);
00531    //   (4) create sparse inverted matrix
00532    nn=ny*ny;
00533    Int_t *vyyinv_rows=new Int_t[nn];
00534    Int_t *vyyinv_cols=new Int_t[nn];
00535    Double_t *vyyinv_data=new Double_t[nn];
00536    nn=0;
00537    for(Int_t ix=0;ix<n;ix++) {
00538       for(Int_t iy=0;iy<n;iy++) {
00539          Double_t d=(*vyyredinv)(ix,iy);
00540          if(d != 0.0) {
00541             vyyinv_rows[nn]=iToY[ix];
00542             vyyinv_cols[nn]=iToY[iy];
00543             vyyinv_data[nn]=d;
00544             nn++;
00545          }
00546       }
00547    }
00548    DeleteMatrix(&vyyredinv);
00549    TMatrixDSparse *Vyyinv=CreateSparseMatrix
00550       (ny,ny,nn,vyyinv_rows,vyyinv_cols,vyyinv_data);
00551 
00552    delete[] vyyinv_rows;
00553    delete[] vyyinv_cols;
00554    delete[] vyyinv_data;
00555 
00556    delete[] yToI;
00557    delete[] iToY;
00558 
00559    //
00560    // get matrix
00561    //              T
00562    //            fA fV  = mAt_V
00563    //
00564    TMatrixDSparse *AtVyyinv=MultiplyMSparseTranspMSparse(fA,Vyyinv);
00565    //
00566    // get
00567    //       T
00568    //     fA fVyyinv fY + fTauSquared fBiasScale Lsquared fX0 = rhs
00569    //
00570    TMatrixDSparse *rhs=MultiplyMSparseM(AtVyyinv,fY);
00571    if (fBiasScale != 0.0) {
00572      TMatrixDSparse *rhs2=MultiplyMSparseM(fLsquared,fX0);
00573       AddMSparse(rhs, fTauSquared * fBiasScale ,rhs2);
00574       DeleteMatrix(&rhs2);
00575    }
00576 
00577    //
00578    // get matrix
00579    //              T
00580    //           (fA fV)fA + fTauSquared*fLsquared  = fEinv
00581    fEinv=MultiplyMSparseMSparse(AtVyyinv,fA);
00582    AddMSparse(fEinv,fTauSquared,fLsquared);
00583 
00584    //
00585    // get matrix
00586    //             -1
00587    //        fEinv    = fE
00588    //
00589    TMatrixD *EE = InvertMSparse(fEinv);
00590    fE=new TMatrixDSparse(*EE);
00591 
00592    //
00593    // get result
00594    //        fE rhs  = x
00595    //
00596    fX = new TMatrixD(*EE, TMatrixD::kMult, *rhs);
00597    DeleteMatrix(&rhs);
00598 
00599    // additional correction for constraint
00600    Double_t lambda_half=0.0;
00601    Double_t one_over_epsEeps=0.0;
00602    TMatrixDSparse *epsilon=0;
00603    TMatrixDSparse *Eepsilon=0;
00604    if(fConstraint != kEConstraintNone) {
00605       // calculate epsilon: verctor of efficiencies
00606       const Int_t *A_rows=fA->GetRowIndexArray();
00607       const Int_t *A_cols=fA->GetColIndexArray();
00608       const Double_t *A_data=fA->GetMatrixArray();
00609       TMatrixD epsilonNosparse(fA->GetNcols(),1);
00610       for(Int_t i=0;i<A_rows[fA->GetNrows()];i++) {
00611          epsilonNosparse(A_cols[i],0) += A_data[i];
00612       }
00613       epsilon=new TMatrixDSparse(epsilonNosparse);
00614       // calculate vector EE*epsilon
00615       Eepsilon=MultiplyMSparseMSparse(fE,epsilon);
00616       // calculate scalar product epsilon#*Eepsilon
00617       TMatrixDSparse *epsilonEepsilon=MultiplyMSparseTranspMSparse(epsilon,
00618                                                                    Eepsilon);
00619       // if epsilonEepsilon is zero, nothing works...
00620       if(epsilonEepsilon->GetRowIndexArray()[1]==1) {
00621          one_over_epsEeps=1./epsilonEepsilon->GetMatrixArray()[0];
00622       } else {
00623          Fatal("TUnfold::Unfold","epsilon#Eepsilon has dimension %d != 1",
00624                epsilonEepsilon->GetRowIndexArray()[1]);
00625       }
00626       DeleteMatrix(&epsilonEepsilon);
00627       // calculate sum(Y)
00628       Double_t y_minus_epsx=0.0;
00629       for(Int_t iy=0;iy<fY->GetNrows();iy++) {
00630          y_minus_epsx += (*fY)(iy,0);
00631       }
00632       // calculate sum(Y)-epsilon#*X
00633       for(Int_t ix=0;ix<epsilonNosparse.GetNrows();ix++) {
00634          y_minus_epsx -=  epsilonNosparse(ix,0) * (*fX)(ix,0);
00635       }
00636       // calculate lambda_half
00637       lambda_half=y_minus_epsx*one_over_epsEeps;
00638       // calculate final vector X
00639       const Int_t *EEpsilon_rows=Eepsilon->GetRowIndexArray();
00640       const Double_t *EEpsilon_data=Eepsilon->GetMatrixArray();
00641       for(Int_t ix=0;ix<Eepsilon->GetNrows();ix++) {
00642          if(EEpsilon_rows[ix]<EEpsilon_rows[ix+1]) {
00643             (*fX)(ix,0) += lambda_half * EEpsilon_data[EEpsilon_rows[ix]];
00644          }
00645       }
00646    }
00647    //
00648    // get derivative dx/dy
00649    // for error propagation
00650    //     dx/dy = E A# Vyy^-1  ( = B )
00651    fDXDY = MultiplyMSparseMSparse(fE,AtVyyinv);
00652 
00653    // additional correction for constraint
00654    if(fConstraint != kEConstraintNone) {
00655       // transposed vector of dimension GetNy() all elements equal 1/epseEeps
00656       Int_t *rows=new Int_t[GetNy()];
00657       Int_t *cols=new Int_t[GetNy()];
00658       Double_t *data=new Double_t[GetNy()];
00659       for(Int_t i=0;i<GetNy();i++) {
00660          rows[i]=0;
00661          cols[i]=i;
00662          data[i]=one_over_epsEeps;
00663       } 
00664       TMatrixDSparse *temp=CreateSparseMatrix
00665          (1,GetNy(),GetNy(),rows,cols,data);
00666       delete[] data;
00667       delete[] rows;
00668       delete[] cols;
00669       // B# * epsilon
00670       TMatrixDSparse *epsilonB=MultiplyMSparseTranspMSparse(epsilon,fDXDY);
00671       // temp- one_over_epsEeps*Bepsilon
00672       AddMSparse(temp, -one_over_epsEeps, epsilonB);
00673       DeleteMatrix(&epsilonB);
00674       // correction matrix
00675       TMatrixDSparse *corr=MultiplyMSparseMSparse(Eepsilon,temp);
00676       DeleteMatrix(&temp);
00677       // determine new derivative
00678       AddMSparse(fDXDY,1.0,corr);
00679       DeleteMatrix(&corr);
00680    }
00681 
00682    DeleteMatrix(&AtVyyinv);
00683 
00684    //
00685    // get error matrix on x
00686    //   fDXDY * Vyy * fDXDY# = fDXDY * A * E    (Note: E# = E)
00687    TMatrixDSparse *AE = MultiplyMSparseMSparse(fA,fE);
00688    fVxx = MultiplyMSparseMSparse(fDXDY,AE);
00689 
00690    DeleteMatrix(&AE);
00691 
00692    //
00693    // get result
00694    //        fA x  =  fAx
00695    //
00696    fAx = MultiplyMSparseM(fA,fX);
00697 
00698    //
00699    // calculate chi**2 etc
00700 
00701    // chi**2 contribution from (y-Ax)V(y-Ax)
00702    TMatrixD dy(*fY, TMatrixD::kMinus, *fAx);
00703    TMatrixDSparse *VyyinvDy=MultiplyMSparseM(Vyyinv,&dy);
00704    DeleteMatrix(&Vyyinv);
00705 
00706    const Int_t *VyyinvDy_rows=VyyinvDy->GetRowIndexArray();
00707    const Double_t *VyyinvDy_data=VyyinvDy->GetMatrixArray();
00708    fChi2A=0.0;
00709    for(Int_t iy=0;iy<VyyinvDy->GetNrows();iy++) {
00710       if(VyyinvDy_rows[iy]<VyyinvDy_rows[iy+1]) {
00711          fChi2A += VyyinvDy_data[VyyinvDy_rows[iy]]*dy(iy,0);
00712       }
00713    }
00714    TMatrixD dx( fBiasScale * (*fX0), TMatrixD::kMinus,(*fX));
00715    TMatrixDSparse *LsquaredDx=MultiplyMSparseM(fLsquared,&dx);
00716    const Int_t *LsquaredDx_rows=LsquaredDx->GetRowIndexArray();
00717    const Double_t *LsquaredDx_data=LsquaredDx->GetMatrixArray();
00718    fLXsquared = 0.0;
00719    for(Int_t ix=0;ix<LsquaredDx->GetNrows();ix++) {
00720       if(LsquaredDx_rows[ix]<LsquaredDx_rows[ix+1]) {
00721          fLXsquared += LsquaredDx_data[LsquaredDx_rows[ix]]*dx(ix,0);
00722       }
00723    }
00724 
00725    //
00726    // get derivative dx/dtau
00727    fDXDtauSquared=MultiplyMSparseMSparse(fE,LsquaredDx);
00728 
00729    if(fConstraint != kEConstraintNone) {
00730       TMatrixDSparse *temp=MultiplyMSparseTranspMSparse(epsilon,fDXDtauSquared);
00731       Double_t f=0.0;
00732       if(temp->GetRowIndexArray()[1]==1) {
00733          f=temp->GetMatrixArray()[0]*one_over_epsEeps;
00734       } else if(temp->GetRowIndexArray()[1]>1) {
00735          Fatal("TUnfold::Unfold",
00736                "epsilon#fDXDtauSquared has dimension %d != 1",
00737                temp->GetRowIndexArray()[1]);
00738       }
00739       if(f!=0.0) {
00740          AddMSparse(fDXDtauSquared, -f,Eepsilon);
00741       }
00742       DeleteMatrix(&temp);
00743    }
00744    DeleteMatrix(&epsilon);
00745 
00746    DeleteMatrix(&LsquaredDx);
00747 
00748    // calculate/store matrices defining the derivatives dx/dA
00749    fDXDAM[0]=new TMatrixDSparse(*fE);
00750    fDXDAM[1]=new TMatrixDSparse(*fDXDY); // create a copy
00751    fDXDAZ[0]=VyyinvDy; // instead of deleting VyyinvDy
00752    VyyinvDy=0;
00753    fDXDAZ[1]=new TMatrixDSparse(*fX); // create a copy
00754 
00755    if(fConstraint != kEConstraintNone) {
00756       // add correction to fDXDAM[0]
00757       TMatrixDSparse *temp1=MultiplyMSparseMSparseTranspVector
00758          (Eepsilon,Eepsilon,0);
00759       AddMSparse(fDXDAM[0], -one_over_epsEeps,temp1);
00760       DeleteMatrix(&temp1);
00761       // add correction to fDXDAZ[0]
00762       Int_t *rows=new Int_t[GetNy()];
00763       Int_t *cols=new Int_t[GetNy()];
00764       Double_t *data=new Double_t[GetNy()];
00765       for(Int_t i=0;i<GetNy();i++) {
00766          rows[i]=i;
00767          cols[i]=0;
00768          data[i]=lambda_half;
00769       }
00770       TMatrixDSparse *temp2=CreateSparseMatrix
00771          (GetNy(),1,GetNy(),rows,cols,data);
00772       delete[] data;
00773       delete[] rows;
00774       delete[] cols;
00775       AddMSparse(fDXDAZ[0],1.0,temp2);
00776       DeleteMatrix(&temp2);
00777    }
00778 
00779    DeleteMatrix(&Eepsilon);
00780    DeleteMatrix(&EE);
00781 
00782    TMatrixD *VxxINV = InvertMSparse(fVxx);
00783    fVxxInv=new TMatrixDSparse(*VxxINV);
00784 
00785    // maximum global correlation coefficient
00786    const Int_t *Vxx_rows=fVxx->GetRowIndexArray();
00787    const Int_t *Vxx_cols=fVxx->GetColIndexArray();
00788    const Double_t *Vxx_data=fVxx->GetMatrixArray();
00789 
00790    Double_t rho_squared_max = 0.0;
00791    Double_t rho_sum = 0.0;
00792    Int_t n_rho=0;
00793    for (int ix = 0; ix < fVxx->GetNrows(); ix++) {
00794       for(int ik=Vxx_rows[ix];ik<Vxx_rows[ix+1];ik++) {
00795          if(ix==Vxx_cols[ik]) {
00796             Double_t rho_squared =
00797                1. - 1. / ((*VxxINV) (ix, ix) * Vxx_data[ik]);
00798             if (rho_squared > rho_squared_max)
00799                rho_squared_max = rho_squared;
00800             if(rho_squared>0.0) {
00801                rho_sum += TMath::Sqrt(rho_squared);
00802                n_rho++;               
00803             }
00804             break;
00805          }
00806       }
00807    }
00808    fRhoMax = TMath::Sqrt(rho_squared_max);
00809    fRhoAvg = (n_rho>0) ? (rho_sum/n_rho) : -1.0;
00810 
00811    delete VxxINV;
00812 
00813    return fRhoMax;
00814 }
00815 
00816 TMatrixDSparse *TUnfold::CreateSparseMatrix
00817 (Int_t nrow,Int_t ncol,Int_t nel,Int_t *row,Int_t *col,Double_t *data) const {
00818    TMatrixDSparse *A=new TMatrixDSparse(nrow,ncol);
00819    if(nel>0) {
00820       A->SetMatrixArray(nel,row,col,data);
00821    }
00822    return A;
00823 }
00824 
00825 TMatrixDSparse *TUnfold::MultiplyMSparseMSparse(const TMatrixDSparse *a,
00826                                                 const TMatrixDSparse *b) const
00827 {
00828    // calculate the product of two sparse matrices
00829    //    a,b: pointers to sparse matrices, where a->GetNcols()==b->GetNrows()
00830    // this is a replacement for the call
00831    //    new TMatrixDSparse(*a,TMatrixDSparse::kMult,*b);
00832    if(a->GetNcols()!=b->GetNrows()) {
00833       Fatal("MultiplyMSparseMSparse",
00834             "inconsistent matrix col/ matrix row %d !=%d",
00835             a->GetNcols(),b->GetNrows());
00836    }
00837 
00838    TMatrixDSparse *r=new TMatrixDSparse(a->GetNrows(),b->GetNcols());
00839    const Int_t *a_rows=a->GetRowIndexArray();
00840    const Int_t *a_cols=a->GetColIndexArray();
00841    const Double_t *a_data=a->GetMatrixArray();
00842    const Int_t *b_rows=b->GetRowIndexArray();
00843    const Int_t *b_cols=b->GetColIndexArray();
00844    const Double_t *b_data=b->GetMatrixArray();
00845    // maximum size of the output matrix
00846    int nMax=0;
00847    for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
00848       if(a_rows[irow+1]>a_rows[irow]) nMax += b->GetNcols();
00849    }
00850    if((nMax>0)&&(a_cols)&&(b_cols)) {
00851       Int_t *r_rows=new Int_t[nMax];
00852       Int_t *r_cols=new Int_t[nMax];
00853       Double_t *r_data=new Double_t[nMax];
00854       Double_t *row_data=new Double_t[b->GetNcols()];
00855       Int_t n=0;
00856       for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
00857          if(a_rows[irow+1]<=a_rows[irow]) continue;
00858          // clear row data
00859          for(Int_t icol=0;icol<b->GetNcols();icol++) {
00860             row_data[icol]=0.0;
00861          }
00862          // loop over a-columns in this a-row
00863          for(Int_t ia=a_rows[irow];ia<a_rows[irow+1];ia++) {
00864             Int_t k=a_cols[ia];
00865             // loop over b-columns in b-row k
00866             for(Int_t ib=b_rows[k];ib<b_rows[k+1];ib++) {
00867                row_data[b_cols[ib]] += a_data[ia]*b_data[ib];
00868             }
00869          }
00870          // store nonzero elements
00871          for(Int_t icol=0;icol<b->GetNcols();icol++) {
00872             if(row_data[icol] != 0.0) {
00873                r_rows[n]=irow;
00874                r_cols[n]=icol;
00875                r_data[n]=row_data[icol];
00876                n++;
00877             }
00878          }
00879       }
00880       if(n>0) {
00881          r->SetMatrixArray(n,r_rows,r_cols,r_data);
00882       }
00883       delete[] r_rows;
00884       delete[] r_cols;
00885       delete[] r_data;
00886       delete[] row_data;
00887    }
00888 
00889    return r;
00890 }
00891 
00892 
00893 TMatrixDSparse *TUnfold::MultiplyMSparseTranspMSparse(const TMatrixDSparse *a,
00894                                                       const TMatrixDSparse *b) const
00895 {
00896    // multiply a transposed Sparse matrix with another Sparse matrix
00897    //    a:  pointer to sparse matrix (to be transposed)
00898    //    b:  pointer to sparse matrix
00899    // this is a replacement for the call
00900    //    new TMatrixDSparse(TMatrixDSparse(TMatrixDSparse::kTransposed,*a),
00901    //                       TMatrixDSparse::kMult,*b)
00902    if(a->GetNrows() != b->GetNrows()) {
00903       Fatal("MultiplyMSparseTranspMSparse",
00904             "inconsistent matrix row numbers %d!=%d",
00905             a->GetNrows(),b->GetNrows());
00906    }
00907 
00908    TMatrixDSparse *r=new TMatrixDSparse(a->GetNcols(),b->GetNcols());
00909    const Int_t *a_rows=a->GetRowIndexArray();
00910    const Int_t *a_cols=a->GetColIndexArray();
00911    const Double_t *a_data=a->GetMatrixArray();
00912    const Int_t *b_rows=b->GetRowIndexArray();
00913    const Int_t *b_cols=b->GetColIndexArray();
00914    const Double_t *b_data=b->GetMatrixArray();
00915    // maximum size of the output matrix
00916 
00917    // matrix multiplication
00918    typedef std::map<Int_t,Double_t> MMatrixRow_t;
00919    typedef std::map<Int_t, MMatrixRow_t > MMatrix_t;
00920    MMatrix_t matrix;
00921 
00922    for(Int_t iRowAB=0;iRowAB<a->GetNrows();iRowAB++) {
00923       for(Int_t ia=a_rows[iRowAB];ia<a_rows[iRowAB+1];ia++) {
00924          for(Int_t ib=b_rows[iRowAB];ib<b_rows[iRowAB+1];ib++) {
00925             // this creates a new row if necessary
00926             MMatrixRow_t &row=matrix[a_cols[ia]];
00927             MMatrixRow_t::iterator icol=row.find(b_cols[ib]);
00928             if(icol!=row.end()) {
00929                // update existing row
00930                (*icol).second += a_data[ia]*b_data[ib];
00931             } else {
00932                // create new row
00933                row[b_cols[ib]] = a_data[ia]*b_data[ib];
00934             }
00935          }
00936       }
00937    }
00938 
00939    Int_t n=0;
00940    for(MMatrix_t::const_iterator irow=matrix.begin();
00941        irow!=matrix.end();irow++) {
00942       n += (*irow).second.size();
00943    }
00944    if(n>0) {
00945       // pack matrix into arrays
00946       Int_t *r_rows=new Int_t[n];
00947       Int_t *r_cols=new Int_t[n];
00948       Double_t *r_data=new Double_t[n];
00949       n=0;
00950       for(MMatrix_t::const_iterator irow=matrix.begin();
00951           irow!=matrix.end();irow++) {
00952          for(MMatrixRow_t::const_iterator icol=(*irow).second.begin();
00953              icol!=(*irow).second.end();icol++) {
00954             r_rows[n]=(*irow).first;
00955             r_cols[n]=(*icol).first;
00956             r_data[n]=(*icol).second;
00957             n++;
00958          }
00959       }
00960       // pack arrays into TMatrixDSparse
00961       if(n>0) {
00962          r->SetMatrixArray(n,r_rows,r_cols,r_data);
00963       }
00964       delete[] r_rows;
00965       delete[] r_cols;
00966       delete[] r_data;
00967    }
00968 
00969    return r;
00970 }
00971 
00972 TMatrixDSparse *TUnfold::MultiplyMSparseM(const TMatrixDSparse *a,
00973                                           const TMatrixD *b) const
00974 {
00975    // multiply a Sparse matrix with a non-sparse matrix
00976    //    a:  pointer to sparse matrix
00977    //    b:  pointer to non-sparse matrix
00978    // this is a replacement for the call
00979    //    new TMatrixDSparse(*a,TMatrixDSparse::kMult,*b);
00980    if(a->GetNcols()!=b->GetNrows()) {
00981       Fatal("MultiplyMSparseM","inconsistent matrix col /matrix row %d!=%d",
00982             a->GetNcols(),b->GetNrows());
00983    }
00984 
00985    TMatrixDSparse *r=new TMatrixDSparse(a->GetNrows(),b->GetNcols());
00986    const Int_t *a_rows=a->GetRowIndexArray();
00987    const Int_t *a_cols=a->GetColIndexArray();
00988    const Double_t *a_data=a->GetMatrixArray();
00989    // maximum size of the output matrix
00990    int nMax=0;
00991    for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
00992       if(a_rows[irow+1]-a_rows[irow]>0) nMax += b->GetNcols();
00993    }
00994    if(nMax>0) {
00995       Int_t *r_rows=new Int_t[nMax];
00996       Int_t *r_cols=new Int_t[nMax];
00997       Double_t *r_data=new Double_t[nMax];
00998 
00999       Int_t n=0;
01000       // fill matrix r
01001       for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
01002          if(a_rows[irow+1]-a_rows[irow]<=0) continue;
01003          for(Int_t icol=0;icol<b->GetNcols();icol++) {
01004             r_rows[n]=irow;
01005             r_cols[n]=icol;
01006             r_data[n]=0.0;
01007             for(Int_t i=a_rows[irow];i<a_rows[irow+1];i++) {
01008                Int_t j=a_cols[i];
01009                r_data[n] += a_data[i]*(*b)(j,icol);
01010             }
01011             if(r_data[n]!=0.0) n++;
01012          }
01013       }
01014       if(n>0) {
01015          r->SetMatrixArray(n,r_rows,r_cols,r_data);
01016       }
01017       delete[] r_rows;
01018       delete[] r_cols;
01019       delete[] r_data;
01020    }
01021    return r;
01022 }
01023 
01024 TMatrixDSparse *TUnfold::MultiplyMSparseMSparseTranspVector
01025 (const TMatrixDSparse *m1,const TMatrixDSparse *m2,
01026  const TMatrixTBase<Double_t> *v) const {
01027    // calculate M_ij = sum_k [m1_ik*m2_jk*v[k] ].
01028    //    m1: pointer to sparse matrix with dimension I*K
01029    //    m2: pointer to sparse matrix with dimension J*K
01030    //    v: pointer to vector (matrix) with dimension K*1
01031    if((m1->GetNcols() != m2->GetNcols())||
01032       (v && ((m1->GetNcols()!=v->GetNrows())||(v->GetNcols()!=1)))) {
01033       if(v) {
01034          Fatal("MultiplyMSparseMSparseTranspVector",
01035                "matrix cols/vector rows %d!=%d!=%d or vector rows %d!=1\n",
01036                m1->GetNcols(),m2->GetNcols(),v->GetNrows(),v->GetNcols());
01037       } else {
01038          Fatal("MultiplyMSparseMSparseTranspVector",
01039                "matrix cols %d!=%d\n",m1->GetNcols(),m2->GetNcols());
01040       }
01041    }
01042    const Int_t *rows_m1=m1->GetRowIndexArray();
01043    const Int_t *cols_m1=m1->GetColIndexArray();
01044    const Double_t *data_m1=m1->GetMatrixArray();
01045    Int_t num_m1=0;
01046    for(Int_t i=0;i<m1->GetNrows();i++) {
01047       if(rows_m1[i]<rows_m1[i+1]) num_m1++;
01048    }
01049    const Int_t *rows_m2=m2->GetRowIndexArray();
01050    const Int_t *cols_m2=m2->GetColIndexArray();
01051    const Double_t *data_m2=m2->GetMatrixArray();
01052    Int_t num_m2=0;
01053    for(Int_t j=0;j<m2->GetNrows();j++) {
01054       if(rows_m2[j]<rows_m2[j+1]) num_m2++;
01055    }
01056    const TMatrixDSparse *v_sparse=dynamic_cast<const TMatrixDSparse *>(v);
01057    const Int_t *v_rows=0;
01058    const Double_t *v_data=0;
01059    if(v_sparse) {
01060       v_rows=v_sparse->GetRowIndexArray();
01061       v_data=v_sparse->GetMatrixArray();
01062    }
01063    Int_t num_r=num_m1*num_m2+1;
01064    Int_t *row_r=new Int_t[num_r];
01065    Int_t *col_r=new Int_t[num_r];
01066    Double_t *data_r=new Double_t[num_r];
01067    num_r=0;
01068    for(Int_t i=0;i<m1->GetNrows();i++) {
01069       for(Int_t j=0;j<m2->GetNrows();j++) {
01070          data_r[num_r]=0.0;
01071          Int_t index_m1=rows_m1[i];
01072          Int_t index_m2=rows_m2[j];
01073          while((index_m1<rows_m1[i+1])&&(index_m2<rows_m2[j+1])) {
01074             Int_t k1=cols_m1[index_m1];
01075             Int_t k2=cols_m2[index_m2];
01076             if(k1<k2) {
01077                index_m1++;
01078             } else if(k1>k2) {
01079                index_m2++;
01080             } else {
01081                if(v_sparse) {
01082                   Int_t v_index=v_rows[k1];
01083                   if(v_index<v_rows[k1+1]) {
01084                      data_r[num_r] += data_m1[index_m1] * data_m2[index_m2]
01085                         * v_data[v_index];
01086                   } else {
01087                      data_r[num_r] =0.0;
01088                   }
01089                } else if(v) {
01090                   data_r[num_r] += data_m1[index_m1] * data_m2[index_m2]
01091                      * (*v)(k1,0);
01092                } else {
01093                   data_r[num_r] += data_m1[index_m1] * data_m2[index_m2];
01094                }
01095                index_m1++;
01096                index_m2++;
01097             }
01098          }
01099          if(data_r[num_r] !=0.0) {
01100             row_r[num_r]=i;
01101             col_r[num_r]=j;
01102             num_r++;
01103          }
01104       }
01105    }
01106    TMatrixDSparse *r=CreateSparseMatrix(m1->GetNrows(),m2->GetNrows(),
01107                                         num_r,row_r,col_r,data_r);
01108    delete[] row_r;
01109    delete[] col_r;
01110    delete[] data_r;
01111    return r;
01112 }
01113 
01114 void TUnfold::AddMSparse(TMatrixDSparse *dest,Double_t f,
01115                          const TMatrixDSparse *src) {
01116    // a replacement for
01117    //     (*dest) += f*(*src)
01118    const Int_t *dest_rows=dest->GetRowIndexArray();
01119    const Int_t *dest_cols=dest->GetColIndexArray();
01120    const Double_t *dest_data=dest->GetMatrixArray();
01121    const Int_t *src_rows=src->GetRowIndexArray();
01122    const Int_t *src_cols=src->GetColIndexArray();
01123    const Double_t *src_data=src->GetMatrixArray();
01124 
01125    if((dest->GetNrows()!=src->GetNrows())||
01126       (dest->GetNcols()!=src->GetNcols())) {
01127       Fatal("AddMSparse","inconsistent matrix rows %d!=%d OR cols %d!=%d",
01128             src->GetNrows(),dest->GetNrows(),src->GetNcols(),dest->GetNcols());
01129    }
01130    Int_t nmax=dest->GetNrows()*dest->GetNcols();
01131    Double_t *result_data=new Double_t[nmax];
01132    Int_t *result_rows=new Int_t[nmax];
01133    Int_t *result_cols=new Int_t[nmax];
01134    Int_t n=0;
01135    for(Int_t row=0;row<dest->GetNrows();row++) {
01136       Int_t i_dest=dest_rows[row];
01137       Int_t i_src=src_rows[row];
01138       while((i_dest<dest_rows[row+1])||(i_src<src_rows[row+1])) {
01139          Int_t col_dest=(i_dest<dest_rows[row+1]) ? 
01140             dest_cols[i_dest] : dest->GetNcols();
01141          Int_t col_src =(i_src <src_rows[row+1] ) ?
01142             src_cols [i_src] :  src->GetNcols();
01143          result_rows[n]=row;
01144          if(col_dest<col_src) {
01145             result_cols[n]=col_dest;
01146             result_data[n]=dest_data[i_dest++];
01147          } else if(col_dest>col_src) {
01148             result_cols[n]=col_src;
01149             result_data[n]=f*src_data[i_src++];
01150          } else {
01151             result_cols[n]=col_dest;
01152             result_data[n]=dest_data[i_dest++]+f*src_data[i_src++];
01153          }
01154          if(result_data[n] !=0.0) n++;
01155       }
01156    }
01157    if(n<=0) {
01158       n=1;
01159       result_rows[0]=0;
01160       result_cols[0]=0;
01161       result_data[0]=0.0;
01162    }
01163    dest->SetMatrixArray(n,result_rows,result_cols,result_data);
01164    delete[] result_data;
01165    delete[] result_rows;
01166    delete[] result_cols;
01167 }
01168 
01169 TMatrixD *TUnfold::InvertMSparse(const TMatrixDSparse *A) const {
01170    // get the inverse of a sparse matrix
01171    //    A: the original matrix
01172    // this is a replacement of the call
01173    //    new TMatrixD(TMatrixD::kInverted, a);
01174    // the matrix inversion is optimized for the case
01175    // where a large submatrix of A is diagonal
01176 
01177    if(A->GetNcols()!=A->GetNrows()) {
01178       Fatal("InvertMSparse","inconsistent matrix row/col %d!=%d",
01179             A->GetNcols(),A->GetNrows());
01180    }
01181 
01182 #ifdef SCHUR_COMPLEMENT_MATRIX_INVERSION
01183 
01184    const Int_t *a_rows=A->GetRowIndexArray();
01185    const Int_t *a_cols=A->GetColIndexArray();
01186    const Double_t *a_data=A->GetMatrixArray();
01187 
01188    Int_t nmin=0,nmax=0;
01189    // find largest diagonal submatrix
01190    for(Int_t imin=0;imin<A->GetNrows();imin++) {
01191       Int_t imax=A->GetNrows();
01192       for(Int_t i2=imin;i2<imax;i2++) {
01193          for(Int_t i=a_rows[i2];i<a_rows[i2+1];i++) {
01194             if(a_data[i]==0.0) continue;
01195             Int_t icol=a_cols[i];
01196             if(icol<imin) continue; // ignore first part of the matrix
01197             if(icol==i2) continue; // ignore diagonals
01198             if(icol<i2) {
01199                // this row spoils the diagonal matrix, so do not use
01200                imax=i2;
01201                break;
01202             } else {
01203                // this entry limits imax
01204                imax=icol;
01205                break;
01206             }
01207          }
01208       }
01209       if(imax-imin>nmax-nmin) {
01210          nmin=imin;
01211          nmax=imax;
01212       }
01213    }
01214    // if the diagonal part has size zero or one, use standard matrix inversion
01215    if(nmin>=nmax-1) {
01216       TMatrixD *r=new TMatrixD(*A);
01217       if(!InvertMConditioned(r)) {
01218          Fatal("InvertMSparse","InvertMConditioned(full matrix) failed");
01219       }
01220       return r;
01221    } else if((nmin==0)&&(nmax==A->GetNrows())) {
01222       // if the diagonal part spans the whole matrix,
01223       //   just set the diagomal elements
01224       TMatrixD *r=new TMatrixD(A->GetNrows(),A->GetNcols());
01225       Int_t error=0;
01226       for(Int_t irow=nmin;irow<nmax;irow++) {
01227          for(Int_t i=a_rows[irow];i<a_rows[irow+1];i++) {
01228             if(a_cols[i]==irow) {
01229                if(a_data[i] !=0.0) (*r)(irow,irow)=1./a_data[i];
01230                else error++;
01231             }
01232          }
01233       }
01234       if(error) {
01235          Error("InvertMSparse",
01236                "inversion failed (diagonal matrix) nerror=%d",error);
01237       }
01238       return r;
01239    }
01240 
01241    //  A  B
01242    // (    )
01243    //  C  D
01244    //
01245    // get inverse of diagonal part
01246    std::vector<Double_t> Dinv;
01247    Dinv.resize(nmax-nmin);
01248    Int_t error=0;
01249    for(Int_t irow=nmin;irow<nmax;irow++) {
01250       for(Int_t i=a_rows[irow];i<a_rows[irow+1];i++) {
01251          if(a_cols[i]==irow) {
01252             if(a_data[i]!=0.0) {
01253                Dinv[irow-nmin]=1./a_data[i];
01254             } else {
01255                Dinv[irow-nmin]=0.0;
01256                error++;
01257             }
01258             break;
01259          }
01260       }
01261    }
01262    if(error) {
01263       Error("InvertMSparse",
01264             "inversion failed (diagonal part) nerror=%d",error);      
01265    }
01266    // B*Dinv and C
01267    Int_t nBDinv=0,nC=0;
01268    for(Int_t irow_a=0;irow_a<A->GetNrows();irow_a++) {
01269       if((irow_a<nmin)||(irow_a>=nmax)) {
01270          for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
01271             Int_t icol=a_cols[i];
01272             if((icol>=nmin)&&(icol<nmax)) nBDinv++;
01273          }
01274       } else {
01275          for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
01276             Int_t icol = a_cols[i];
01277             if((icol<nmin)||(icol>=nmax)) nC++;
01278          }
01279       }
01280    }
01281    Int_t *row_BDinv=new Int_t[nBDinv+1];
01282    Int_t *col_BDinv=new Int_t[nBDinv+1];
01283    Double_t *data_BDinv=new Double_t[nBDinv+1];
01284 
01285    Int_t *row_C=new Int_t[nC+1];
01286    Int_t *col_C=new Int_t[nC+1];
01287    Double_t *data_C=new Double_t[nC+1];
01288 
01289    TMatrixD Aschur(A->GetNrows()-(nmax-nmin),A->GetNcols()-(nmax-nmin));
01290 
01291    nBDinv=0;
01292    nC=0;
01293    for(Int_t irow_a=0;irow_a<A->GetNrows();irow_a++) {
01294       if((irow_a<nmin)||(irow_a>=nmax)) {
01295          Int_t row=(irow_a<nmin) ? irow_a : (irow_a-(nmax-nmin));
01296          for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
01297             Int_t icol_a=a_cols[i];
01298             if(icol_a<nmin) {
01299                Aschur(row,icol_a)=a_data[i];
01300             } else if(icol_a>=nmax) {
01301                Aschur(row,icol_a-(nmax-nmin))=a_data[i];
01302             } else {
01303                row_BDinv[nBDinv]=row;
01304                col_BDinv[nBDinv]=icol_a-nmin;
01305                data_BDinv[nBDinv]=a_data[i]*Dinv[icol_a-nmin];
01306                nBDinv++;
01307             }
01308          }
01309       } else {
01310          for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
01311             Int_t icol_a=a_cols[i];
01312             if(icol_a<nmin) {
01313                row_C[nC]=irow_a-nmin;
01314                col_C[nC]=icol_a;
01315                data_C[nC]=a_data[i];
01316                nC++;
01317             } else if(icol_a>=nmax) {
01318                row_C[nC]=irow_a-nmin;
01319                col_C[nC]=icol_a-(nmax-nmin);
01320                data_C[nC]=a_data[i];
01321                nC++;
01322             }
01323          }
01324       }
01325    }
01326    TMatrixDSparse *BDinv=CreateSparseMatrix
01327       (A->GetNrows()-(nmax-nmin),nmax-nmin,
01328        nBDinv,row_BDinv,col_BDinv,data_BDinv);
01329    delete[] row_BDinv;
01330    delete[] col_BDinv;
01331    delete[] data_BDinv;
01332 
01333 
01334    TMatrixDSparse *C=CreateSparseMatrix(nmax-nmin,A->GetNcols()-(nmax-nmin),
01335                                         nC,row_C,col_C,data_C);
01336    delete[] row_C;
01337    delete[] col_C;
01338    delete[] data_C;
01339 
01340    TMatrixDSparse *BDinvC=MultiplyMSparseMSparse(BDinv,C);
01341 
01342    Aschur -= *BDinvC;
01343    if(!InvertMConditioned(&Aschur)) {
01344       Fatal("InvertMSparse","InvertMConditioned failed (part of matrix)");
01345    }
01346 
01347    DeleteMatrix(&BDinvC);
01348 
01349    TMatrixD *r=new TMatrixD(A->GetNrows(),A->GetNcols());
01350 
01351    for(Int_t row_a=0;row_a<Aschur.GetNrows();row_a++) {
01352       for(Int_t col_a=0;col_a<Aschur.GetNcols();col_a++) {
01353          (*r)((row_a<nmin) ? row_a : (row_a+nmax-nmin),
01354               (col_a<nmin) ? col_a : (col_a+nmax-nmin))=Aschur(row_a,col_a);
01355       }
01356    }
01357 
01358    TMatrixDSparse *CAschur=MultiplyMSparseM(C,&Aschur);
01359    TMatrixDSparse *CAschurBDinv=MultiplyMSparseMSparse(CAschur,BDinv);
01360 
01361    DeleteMatrix(&C);
01362 
01363    const Int_t *CAschurBDinv_row=CAschurBDinv->GetRowIndexArray();
01364    const Int_t *CAschurBDinv_col=CAschurBDinv->GetColIndexArray();
01365    const Double_t *CAschurBDinv_data=CAschurBDinv->GetMatrixArray();
01366    for(Int_t row=0;row<CAschurBDinv->GetNrows();row++) {
01367       for(Int_t i=CAschurBDinv_row[row];i<CAschurBDinv_row[row+1];i++) {
01368          Int_t col=CAschurBDinv_col[i];
01369          (*r)(row+nmin,col+nmin)=CAschurBDinv_data[i]*Dinv[row];
01370       }
01371       (*r)(row+nmin,row+nmin) += Dinv[row];
01372    }
01373 
01374    DeleteMatrix(&CAschurBDinv);
01375 
01376    const Int_t *CAschur_row=CAschur->GetRowIndexArray();
01377    const Int_t *CAschur_col=CAschur->GetColIndexArray();
01378    const Double_t *CAschur_data=CAschur->GetMatrixArray();
01379    for(Int_t row=0;row<CAschur->GetNrows();row++) {
01380       for(Int_t i=CAschur_row[row];i<CAschur_row[row+1];i++) {
01381          Int_t col=CAschur_col[i];
01382          (*r)(row+nmin,
01383               (col<nmin) ? col : (col+nmax-nmin))= -CAschur_data[i]*Dinv[row];
01384       }
01385    }
01386    DeleteMatrix(&CAschur);
01387 
01388    const Int_t *BDinv_row=BDinv->GetRowIndexArray();
01389    const Int_t *BDinv_col=BDinv->GetColIndexArray();
01390    const Double_t *BDinv_data=BDinv->GetMatrixArray();  
01391    for(Int_t row_aschur=0;row_aschur<Aschur.GetNrows();row_aschur++) {
01392       Int_t row=(row_aschur<nmin) ? row_aschur : (row_aschur+nmax-nmin);
01393       for(Int_t row_bdinv=0;row_bdinv<BDinv->GetNrows();row_bdinv++) {
01394          for(Int_t i=BDinv_row[row_bdinv];i<BDinv_row[row_bdinv+1];i++) {
01395             (*r)(row,BDinv_col[i]+nmin) -= Aschur(row_aschur,row_bdinv)*
01396                BDinv_data[i];
01397          }
01398       }
01399    }
01400    DeleteMatrix(&BDinv);
01401 
01402    return r;
01403 #else
01404    TMatrixD *r=new TMatrixD(A);
01405    if(!InvertMConditioned(*r)) {
01406       Fatal("InvertMSparse","InvertMConditioned failed (full matrix)";
01407       print_backtrace();
01408    }
01409    return r;
01410 #endif
01411 }
01412 
01413 Bool_t TUnfold::InvertMConditioned(TMatrixD *A) {
01414    // invert the matrix A
01415    // the inversion is done with pre-conditioning
01416    // all rows and columns are normalized to sqrt(abs(a_ii*a_jj))
01417    // such that the diagonals are equal to 1.0
01418    // This type of preconditioning improves the numerival results
01419    // for the symmetric, positive definite matrices which are
01420    // treated here in the context of unfolding
01421 #ifdef INVERT_WITH_CONDITIONING
01422    // divide matrix by the square-root of its diagonals
01423    Double_t *A_diagonals=new Double_t[A->GetNrows()];
01424    for(Int_t i=0;i<A->GetNrows();i++) {
01425       A_diagonals[i]=TMath::Sqrt(TMath::Abs((*A)(i,i)));
01426       if(A_diagonals[i]>0.0) A_diagonals[i]=1./A_diagonals[i];
01427       else A_diagonals[i]=1.0;
01428    }
01429    // condition the matrix prior to inversion
01430    for(Int_t i=0;i<A->GetNrows();i++) {
01431       for(Int_t j=0;j<A->GetNcols();j++) {
01432          (*A)(i,j) *= A_diagonals[i]*A_diagonals[j];
01433       }
01434    }
01435 #endif
01436    Double_t det=0.0;
01437    A->Invert(&det);
01438 #ifdef INVERT_WITH_CONDITIONING
01439    // revert conditioning on the inverted matrix
01440    for(Int_t i=0;i<A->GetNrows();i++) {
01441       for(Int_t j=0;j<A->GetNcols();j++) {
01442          (*A)(i,j) *= A_diagonals[i]*A_diagonals[j];
01443       }
01444    }
01445    delete[] A_diagonals;
01446 #endif
01447    return (det !=0.0);
01448 }
01449 
01450 TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
01451                  TUnfold::EConstraint constraint)
01452 {
01453    // set up unfolding matrix and initial regularisation scheme
01454    //    hist_A:  matrix that describes the migrations
01455    //    histmap: mapping of the histogram axes to the unfolding output 
01456    //    regmode: global regularisation mode
01457    //    constraint: type of constraint to use
01458    // data members initialized to something different from zero:
01459    //    fA: filled from hist_A
01460    //    fDA: filled from hist_A
01461    //    fX0: filled from hist_A
01462    //    fLsquared: filled depending on the regularisation scheme
01463    // Treatment of overflow bins
01464    //    Bins where the unfolding input (Detector level) is in overflow
01465    //    are used for the efficiency correction. They have to be filled
01466    //    properly!
01467    //    Bins where the unfolding output (Generator level) is in overflow
01468    //    are treated as a part of the generator level distribution.
01469    //    I.e. the unfolding output could have non-zero overflow bins if the
01470    //    input matrix does have such bins.
01471 
01472    InitTUnfold();
01473    SetConstraint(constraint);
01474    Int_t nx0, nx, ny;
01475    if (histmap == kHistMapOutputHoriz) {
01476       // include overflow bins on the X axis
01477       nx0 = hist_A->GetNbinsX()+2;
01478       ny = hist_A->GetNbinsY();
01479    } else {
01480       // include overflow bins on the X axis
01481       nx0 = hist_A->GetNbinsY()+2;
01482       ny = hist_A->GetNbinsX();
01483    }
01484    nx = 0;
01485    // fNx is expected to be nx0, but the input matrix may be ill-formed
01486    // -> all columns with zero events have to be removed
01487    //    (because y does not contain any information on that bin in x)
01488    fSumOverY.Set(nx0);
01489    fXToHist.Set(nx0);
01490    fHistToX.Set(nx0);
01491    Int_t nonzeroA=0;
01492    // loop
01493    //  - calculate bias distribution
01494    //      sum_over_y
01495    //  - count those generator bins which can be unfolded
01496    //      fNx
01497    //  - histogram bins are added to the lookup-tables
01498    //      fHistToX[] and fXToHist[]
01499    //    these convert histogram bins to matrix indices and vice versa
01500    //  - the number of non-zero elements is counted
01501    //      nonzeroA
01502    Int_t nskipped=0;
01503    for (Int_t ix = 0; ix < nx0; ix++) {
01504       // calculate sum over all detector bins
01505       // excluding the overflow bins
01506       Double_t sum = 0.0;
01507       for (Int_t iy = 0; iy < ny; iy++) {
01508          Double_t z;
01509          if (histmap == kHistMapOutputHoriz) {
01510             z = hist_A->GetBinContent(ix, iy + 1);
01511          } else {
01512             z = hist_A->GetBinContent(iy + 1, ix);
01513          }
01514          if (z > 0.0) {
01515             nonzeroA++;
01516             sum += z;
01517          }
01518       }
01519       // check whether there is any sensitivity to this generator bin
01520       if (sum > 0.0) {
01521          // update mapping tables to convert bin number to matrix index
01522          fXToHist[nx] = ix;
01523          fHistToX[ix] = nx;
01524          // add overflow bins -> important to keep track of the
01525          // non-reconstructed events
01526          fSumOverY[nx] = sum;
01527          if (histmap == kHistMapOutputHoriz) {
01528             fSumOverY[nx] +=
01529                hist_A->GetBinContent(ix, 0) +
01530                hist_A->GetBinContent(ix, ny + 1);
01531          } else {
01532             fSumOverY[nx] +=
01533                hist_A->GetBinContent(0, ix) +
01534                hist_A->GetBinContent(ny + 1, ix);
01535          }
01536          nx++;
01537       } else {
01538          nskipped++;
01539          // histogram bin pointing to -1 (non-existing matrix entry)
01540          fHistToX[ix] = -1;
01541       }
01542    }
01543    Int_t underflowBin=0,overflowBin=0;
01544    for (Int_t ix = 0; ix < nx; ix++) {
01545       Int_t ibinx = fXToHist[ix];
01546       if(ibinx<1) underflowBin=1;
01547       if (histmap == kHistMapOutputHoriz) {
01548          if(ibinx>hist_A->GetNbinsX()) overflowBin=1;
01549       } else {
01550          if(ibinx>hist_A->GetNbinsY()) overflowBin=1;
01551       }
01552    }
01553    if(nskipped) {
01554       Int_t nprint=0;
01555       Int_t ixfirst=-1,ixlast=-1;
01556       TString binlist;
01557       for (Int_t ix = 0; ix < nx0; ix++) {
01558          if(fHistToX[ix]<0) {
01559             nprint++;
01560             if(ixlast<0) {
01561                binlist +=" ";
01562                binlist +=ix;
01563                ixfirst=ix;
01564             }
01565             ixlast=ix;
01566          }
01567          if(((fHistToX[ix]>=0)&&(ixlast>=0))||
01568             (nprint==nskipped)) {
01569             if(ixlast>ixfirst) {
01570                binlist += "-";
01571                binlist += ixlast;
01572             }
01573             ixfirst=-1;
01574             ixlast=-1;
01575          }
01576          if(nprint==nskipped) {
01577             break;
01578          }
01579       }
01580       if(nskipped==(2-underflowBin-overflowBin)) {
01581          Info("TUnfold","the following output bins "
01582               "are not connected to the input side %s",
01583               static_cast<const char *>(binlist));
01584       } else {
01585          Warning("TUnfold","the following output bins "
01586                  "are not connected to the input side %s",
01587                  static_cast<const char *>(binlist));
01588       }
01589    }
01590    // store bias as matrix
01591    fX0 = new TMatrixD(nx, 1, fSumOverY.GetArray());
01592    // store non-zero elements in sparse matrix fA
01593    // construct sparse matrix fA
01594    Int_t *rowA = new Int_t[nonzeroA];
01595    Int_t *colA = new Int_t[nonzeroA];
01596    Double_t *dataA = new Double_t[nonzeroA];
01597    Int_t index=0;
01598    for (Int_t iy = 0; iy < ny; iy++) {
01599       for (Int_t ix = 0; ix < nx; ix++) {
01600          Int_t ibinx = fXToHist[ix];
01601          Double_t z;
01602          if (histmap == kHistMapOutputHoriz) {
01603             z = hist_A->GetBinContent(ibinx, iy + 1);
01604          } else {
01605             z = hist_A->GetBinContent(iy + 1, ibinx);
01606          }
01607          if (z > 0.0) {
01608             rowA[index]=iy;
01609             colA[index] = ix;
01610             dataA[index] = z / fSumOverY[ix];
01611             index++;
01612          }
01613       }
01614    }
01615    if(underflowBin && overflowBin) {
01616       Info("TUnfold","%d input bins and %d output bins (includes 2 underflow/overflow bins)",ny,nx);
01617    } else if(underflowBin) {
01618       Info("TUnfold","%d input bins and %d output bins (includes 1 underflow bin)",ny,nx);
01619    } else if(overflowBin) {
01620       Info("TUnfold","%d input bins and %d output bins (includes 1 overflow bin)",ny,nx);
01621    } else {
01622       Info("TUnfold","%d input bins and %d output bins",ny,nx);
01623    }
01624    fA = CreateSparseMatrix(ny,nx,index,rowA,colA,dataA);
01625    if(ny<nx) {
01626       Error("TUnfold","too few (ny=%d) input bins for nx=%d output bins",ny,nx);
01627    } else if(ny==nx) {
01628       Warning("TUnfold","too few (ny=%d) input bins for nx=%d output bins",ny,nx);
01629    }
01630    delete[] rowA;
01631    delete[] colA;
01632    delete[] dataA;
01633    // regularisation conditions squared
01634    fLsquared = new TMatrixDSparse(GetNx(), GetNx());
01635    if (regmode != kRegModeNone) {
01636       Int_t nError=RegularizeBins(0, 1, nx0, regmode);
01637       if(nError>0) {
01638          if(nError>1) {
01639             Info("TUnfold",
01640                  "%d regularisation conditions have been skipped",nError);
01641          } else {
01642             Info("TUnfold",
01643                  "One regularisation condition has been skipped");
01644          }
01645       }
01646    }
01647 }
01648 
01649 TUnfold::~TUnfold(void)
01650 {
01651    // delete all data members
01652 
01653    DeleteMatrix(&fA);
01654    DeleteMatrix(&fLsquared);
01655    DeleteMatrix(&fVyy);
01656    DeleteMatrix(&fY);
01657    DeleteMatrix(&fX0);
01658 
01659    ClearResults();
01660 }
01661 
01662 void TUnfold::SetBias(const TH1 *bias)
01663 {
01664    // initialize alternative bias from histogram
01665    // modifies data member fX0
01666    DeleteMatrix(&fX0);
01667    fX0 = new TMatrixD(GetNx(), 1);
01668    for (Int_t i = 0; i < GetNx(); i++) {
01669       (*fX0) (i, 0) = bias->GetBinContent(fXToHist[i]);
01670    }
01671 }
01672 
01673 Int_t TUnfold::RegularizeSize(int bin, Double_t scale)
01674 {
01675    // add regularisation on the size of bin i
01676    //    bin: bin number
01677    //    scale: size of the regularisation
01678    // return value: number of conditions which have been skipped
01679    // modifies data member fLsquared
01680 
01681    if(fRegMode==kRegModeNone) fRegMode=kRegModeSize;
01682    if(fRegMode!=kRegModeSize) fRegMode=kRegModeMixed;
01683 
01684    Int_t i = fHistToX[bin];
01685    if (i < 0) {
01686       return 1;
01687    }
01688    (*fLsquared) (i, i) = scale * scale;
01689    return 0;
01690 }
01691 
01692 Int_t TUnfold::RegularizeDerivative(int left_bin, int right_bin,
01693                                    Double_t scale)
01694 {
01695    // add regularisation on the difference of two bins
01696    //   left_bin: 1st bin
01697    //   right_bin: 2nd bin
01698    //   scale: size of the regularisation
01699    // return value: number of conditions which have been skipped
01700    // modifies data member fLsquared
01701 
01702    if(fRegMode==kRegModeNone) fRegMode=kRegModeDerivative;
01703    if(fRegMode!=kRegModeDerivative) fRegMode=kRegModeMixed;
01704 
01705    Int_t il = fHistToX[left_bin];
01706    Int_t ir = fHistToX[right_bin];
01707    if ((il < 0) || (ir < 0)) {
01708       return 1;
01709    }
01710    Double_t scale_squared = scale * scale;
01711    (*fLsquared) (il, il) += scale_squared;
01712    (*fLsquared) (il, ir) -= scale_squared;
01713    (*fLsquared) (ir, il) -= scale_squared;
01714    (*fLsquared) (ir, ir) += scale_squared;
01715    return 0;
01716 }
01717 
01718 Int_t TUnfold::RegularizeCurvature(int left_bin, int center_bin,
01719                                   int right_bin,
01720                                   Double_t scale_left,
01721                                   Double_t scale_right)
01722 {
01723    // add regularisation on the curvature through 3 bins (2nd derivative)
01724    //   left_bin: 1st bin
01725    //   center_bin: 2nd bin
01726    //   right_bin: 3rd bin
01727    //   scale_left: scale factor on center-left difference
01728    //   scale_right: scale factor on right-center difference
01729    // return value: number of conditions which have been skipped
01730    // modifies data member fLsquared
01731 
01732    if(fRegMode==kRegModeNone) fRegMode=kRegModeCurvature;
01733    if(fRegMode!=kRegModeCurvature) fRegMode=kRegModeMixed;
01734 
01735    Int_t il, ic, ir;
01736    il = fHistToX[left_bin];
01737    ic = fHistToX[center_bin];
01738    ir = fHistToX[right_bin];
01739    if ((il < 0) || (ic < 0) || (ir < 0)) {
01740       return 1;
01741    }
01742    Double_t r[3];
01743    r[0] = -scale_left;
01744    r[2] = -scale_right;
01745    r[1] = -r[0] - r[2];
01746    // diagonal elements
01747    (*fLsquared) (il, il) += r[0] * r[0];
01748    (*fLsquared) (il, ic) += r[0] * r[1];
01749    (*fLsquared) (il, ir) += r[0] * r[2];
01750    (*fLsquared) (ic, il) += r[1] * r[0];
01751    (*fLsquared) (ic, ic) += r[1] * r[1];
01752    (*fLsquared) (ic, ir) += r[1] * r[2];
01753    (*fLsquared) (ir, il) += r[2] * r[0];
01754    (*fLsquared) (ir, ic) += r[2] * r[1];
01755    (*fLsquared) (ir, ir) += r[2] * r[2];
01756    return 0;
01757 }
01758 
01759 Int_t TUnfold::RegularizeBins(int start, int step, int nbin,
01760                              ERegMode regmode)
01761 {
01762    // set regulatisation on a 1-dimensional curve
01763    //   start: first bin
01764    //   step:  distance between neighbouring bins
01765    //   nbin:  total number of bins
01766    //   regmode:  regularisation mode
01767    // return value:
01768    //   number of errors (i.e. conditions which have been skipped)
01769    // modifies data member fLsquared
01770 
01771    Int_t i0, i1, i2;
01772    i0 = start;
01773    i1 = i0 + step;
01774    i2 = i1 + step;
01775    Int_t nSkip = 0;
01776    Int_t nError= 0;
01777    if (regmode == kRegModeDerivative) {
01778       nSkip = 1;
01779    } else if (regmode == kRegModeCurvature) {
01780       nSkip = 2;
01781    } else if(regmode != kRegModeSize) {
01782       Error("TUnfold::RegularizeBins","regmode = %d is not valid",regmode);
01783    }
01784    for (Int_t i = nSkip; i < nbin; i++) {
01785       if (regmode == kRegModeSize) {
01786          nError += RegularizeSize(i0);
01787       } else if (regmode == kRegModeDerivative) {
01788          nError += RegularizeDerivative(i0, i1);
01789       } else if (regmode == kRegModeCurvature) {
01790          nError += RegularizeCurvature(i0, i1, i2);
01791       }
01792       i0 = i1;
01793       i1 = i2;
01794       i2 += step;
01795    }
01796    return nError;
01797 }
01798 
01799 Int_t TUnfold::RegularizeBins2D(int start_bin, int step1, int nbin1,
01800                                int step2, int nbin2, ERegMode regmode)
01801 {
01802    // set regularisation on a 2-dimensional grid of bins
01803    //     start: first bin
01804    //     step1: distance between bins in 1st direction
01805    //     nbin1: number of bins in 1st direction
01806    //     step2: distance between bins in 2nd direction
01807    //     nbin2: number of bins in 2nd direction
01808     // return value:
01809    //   number of errors (i.e. conditions which have been skipped)
01810   // modifies data member fLsquared
01811 
01812    Int_t nError = 0;
01813    for (Int_t i1 = 0; i1 < nbin1; i1++) {
01814       nError += RegularizeBins(start_bin + step1 * i1, step2, nbin2, regmode);
01815    }
01816    for (Int_t i2 = 0; i2 < nbin2; i2++) {
01817       nError += RegularizeBins(start_bin + step2 * i2, step1, nbin1, regmode);
01818    }
01819    return nError;
01820 }
01821 
01822 Double_t TUnfold::DoUnfold(Double_t tau_reg,const TH1 *input,
01823                            Double_t scaleBias)
01824 {
01825    // Do unfolding of an input histogram
01826    //   tau_reg: regularisation parameter
01827    //   input:   input distribution with errors
01828    //   scaleBias:  scale factor applied to the bias
01829    // Data members required:
01830    //   fA, fX0, fLsquared
01831    // Data members modified:
01832    //   those documented in SetInput()
01833    //   and those documented in DoUnfold(Double_t)
01834    // Return value:
01835    //   maximum global correlation coefficient
01836    //   NOTE!!! return value >=1.0 means error, and the result is junk
01837    //
01838    // Overflow bins of the input distribution are ignored!
01839 
01840    SetInput(input,scaleBias);
01841    return DoUnfold(tau_reg);
01842 }
01843 
01844 Int_t TUnfold::SetInput(const TH1 *input, Double_t scaleBias,
01845                         Double_t oneOverZeroError) {
01846   // Define the input data for subsequent calls to DoUnfold(Double_t)
01847   //   input:   input distribution with errors
01848   //   scaleBias:  scale factor applied to the bias
01849   //   oneOverZeroError: for bins with zero error, this number defines 1/error.
01850   // Return value: number of bins with bad error
01851   //                 +10000*number of unconstrained output bins
01852   //         Note: return values>=10000 are fatal errors, 
01853   //               for the given input, the unfolding can not be done!
01854   // Data members modified:
01855   //   fY, fVyy, fVyyinv, fBiasScale, fNdf
01856   // Data members cleared
01857   //   see ClearResults
01858   fBiasScale = scaleBias;
01859 
01860    // delete old results (if any)
01861   ClearResults();
01862 
01863   // construct error matrix and inverted error matrix of measured quantities
01864   // from errors of input histogram
01865   // and count number of degrees of freedom
01866   fNdf = -GetNpar();
01867   Int_t *rowColVyy=new Int_t[GetNy()];
01868   Int_t *col1Vyy=new Int_t[GetNy()];
01869   Double_t *dataVyy=new Double_t[GetNy()];
01870   Int_t nError=0;
01871   for (Int_t iy = 0; iy < GetNy(); iy++) {
01872      Double_t dy = input->GetBinError(iy + 1);
01873      rowColVyy[iy] = iy;
01874      col1Vyy[iy] = 0;
01875      if (dy <= 0.0) {
01876         nError++;
01877         if(oneOverZeroError>0.0) {
01878            dataVyy[iy] = 1./ ( oneOverZeroError*oneOverZeroError);
01879         } else {
01880            dataVyy[iy] = 0.0;
01881         }
01882      } else {
01883         dataVyy[iy] = dy * dy;
01884      }
01885      if( dataVyy[iy]>0.0) fNdf ++;
01886   }
01887   DeleteMatrix(&fVyy);
01888   fVyy = CreateSparseMatrix
01889      (GetNy(),GetNy(),GetNy(),rowColVyy,rowColVyy,dataVyy);
01890 
01891   TMatrixDSparse *vecV=CreateSparseMatrix
01892      (GetNy(),1,GetNy(),rowColVyy,col1Vyy, dataVyy);
01893   delete[] rowColVyy;
01894   delete[] col1Vyy;
01895   delete[] dataVyy;
01896 
01897   //
01898   // get input vector
01899   DeleteMatrix(&fY);
01900   fY = new TMatrixD(GetNy(), 1);
01901   for (Int_t i = 0; i < GetNy(); i++) {
01902      (*fY) (i, 0) = input->GetBinContent(i + 1);
01903   }
01904   // simple check whether unfolding is possible, given the matrices fA and  fV
01905   TMatrixDSparse *mAtV=MultiplyMSparseTranspMSparse(fA,vecV);
01906   DeleteMatrix(&vecV);
01907   Int_t nError2=0;
01908   for (Int_t i = 0; i <mAtV->GetNrows();i++) {
01909      if(mAtV->GetRowIndexArray()[i]==
01910         mAtV->GetRowIndexArray()[i+1]) {
01911         nError2 ++;
01912      }
01913   }
01914   if(nError>0) {
01915      if(oneOverZeroError !=0.0) {
01916         if(nError>1) {
01917            Warning("SetInput","%d input bins have zero error,"
01918                    " 1/error set to %lf.",nError,oneOverZeroError);
01919         } else {
01920            Warning("SetInput","One input bin has zero error,"
01921                    " 1/error set to %lf.",oneOverZeroError);
01922         }
01923      } else {
01924         if(nError>1) {
01925            Warning("SetInput","%d input bins have zero error,"
01926                    " and are ignored.",nError);
01927         } else {
01928            Warning("SetInput","One input bin has zero error,"
01929                    " and is ignored.");
01930         }
01931      }
01932   }
01933   if(nError2>0) {
01934      if(nError2>1) {
01935         Warning("SetInput","%d output bins are not constrained by any data.",
01936                 nError2);
01937      } else {
01938         Warning("SetInput","One output bins is not constrained by any data.");
01939      }
01940      // check whether data points with zero error are responsible
01941      if(oneOverZeroError<=0.0) {
01942         const Int_t *a_rows=fA->GetRowIndexArray();
01943         const Int_t *a_cols=fA->GetColIndexArray();
01944         for (Int_t col = 0; col <mAtV->GetNrows();col++) {
01945            if(mAtV->GetRowIndexArray()[col]==
01946               mAtV->GetRowIndexArray()[col+1]) {
01947               TString binlist("output bin ");
01948               binlist += fXToHist[col];
01949               binlist +=" depends on ignored input bins ";
01950               for(Int_t row=0;row<fA->GetNrows();row++) {
01951                  if(input->GetBinError(row + 1)>0.0) continue;
01952                  for(Int_t i=a_rows[row];i<a_rows[row+1];i++) {
01953                     if(a_cols[i]!=col) continue;
01954                     binlist +=" ";
01955                     binlist +=row;
01956                  }
01957               }
01958               Warning("SetInput","%s",binlist.Data());
01959            }
01960         }
01961      }
01962   }
01963   DeleteMatrix(&mAtV);
01964 
01965   return nError+10000*nError2;
01966 }
01967 
01968 Double_t TUnfold::DoUnfold(Double_t tau) {
01969    // Unfold with given value of regularisation parameter tau
01970    //     tau: new tau parameter
01971    // required data members:
01972    //     fA:  matrix to relate x and y
01973    //     fY:  measured data points
01974    //     fX0: bias on x
01975    //     fBiasScale: scale factor for fX0
01976    //     fV:  inverse of covariance matrix for y
01977    //     fLsquared: regularisation conditions
01978    // modified data members:
01979    //     fTauSquared and those documented in DoUnfold(void)
01980    fTauSquared=tau*tau;
01981    return DoUnfold();
01982 }
01983 
01984 Int_t TUnfold::ScanLcurve(Int_t nPoint,
01985                           Double_t tauMin,Double_t tauMax,
01986                           TGraph **lCurve,TSpline **logTauX,
01987                           TSpline **logTauY) {
01988   // scan the L curve
01989   //   nPoint: number of points on the resulting curve
01990   //   tauMin: smallest tau value to study
01991   //   tauMax: largest tau value to study
01992   //   lCurve: the L curve as graph
01993   //   logTauX: output spline of x-coordinates vs tau for the L curve
01994   //   logTauY: output spline of y-coordinates vs tau for the L curve
01995   // return value: the coordinate number (0..nPoint-1) with the "best" choice
01996   //     of tau
01997   typedef std::map<Double_t,std::pair<Double_t,Double_t> > XYtau_t;
01998   XYtau_t curve;
01999 
02000   //==========================================================
02001   // algorithm:
02002   //  (1) do the unfolding for nPoint-1 points
02003   //      and store the results in the map
02004   //        curve
02005   //    (1a) store minimum and maximum tau to curve
02006   //    (1b) insert additional points, until nPoint-1 values
02007   //          have been calculated
02008   //
02009   //  (2) determine the best choice of tau
02010   //      do the unfolding for this point
02011   //      and store the result in
02012   //        curve
02013   //  (3) return the result in
02014   //       lCurve logTauX logTauY
02015 
02016   //==========================================================
02017   //  (1) do the unfolding for nPoint-1 points
02018   //      and store the results in
02019   //        curve
02020   //    (1a) store minimum and maximum tau to curve
02021 
02022   if((tauMin<=0)||(tauMax<=0.0)||(tauMin>=tauMax)) {
02023      // if the number of degrees of freedom is too small, create an error
02024      if(GetNdf()<=0) {
02025         Error("ScanLcurve","too few input bins, NDF<=0");  
02026      }
02027      // here no range is given, has to be determined automatically
02028      // the maximum tau is determined from the chi**2 values 
02029      // observed from unfolding without regulatisation
02030 
02031      // first unfolding, without regularisation
02032      DoUnfold(0.0);
02033      Double_t x0=GetLcurveX();
02034      Double_t y0=GetLcurveY();
02035      Info("ScanLcurve","logtau=-Infinity X=%lf Y=%lf",x0,y0);
02036      {
02037         // unfolding guess maximum tau and store it
02038         Double_t logTau=
02039            0.5*(TMath::Log10(fChi2A+3.*TMath::Sqrt(GetNdf()+1.0))
02040                 -GetLcurveY());
02041         DoUnfold(TMath::Power(10.,logTau));
02042         curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
02043         Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
02044              logTau,GetLcurveX(),GetLcurveY());
02045      }
02046      if((*curve.begin()).second.first<x0) {
02047         // if the point at tau==0 seems numerically unstable,
02048         // try to find the minimum chi**2 as start value
02049         //
02050         // "unstable" means that there is a finite tau where the
02051         // unfolding chi**2 is smaller than for the case of no
02052         // regularisation. Ideally this shoukld never happen
02053         do {
02054            x0=GetLcurveX();
02055            Double_t logTau=(*curve.begin()).first-0.5;
02056            DoUnfold(TMath::Power(10.,logTau));
02057            curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
02058            Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
02059                 logTau,GetLcurveX(),GetLcurveY());
02060         }
02061         while(((int)curve.size()<(nPoint-1)/2)&&
02062               ((*curve.begin()).second.first<x0));
02063      } else {
02064         // minimum tau is chosen such that it is less than
02065         // 1% different from the case of no regularusation
02066         // log10(1.01) = 0.00432
02067 
02068         // here, more than one point are insetred in necessary
02069         while(((int)curve.size()<nPoint-1)&&
02070               (((*curve.begin()).second.first-x0>0.00432)||
02071                ((*curve.begin()).second.second-y0>0.00432)||
02072                (curve.size()<2))) {
02073            Double_t logTau=(*curve.begin()).first-0.5;
02074            DoUnfold(TMath::Power(10.,logTau));
02075            curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
02076            Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
02077                 logTau,GetLcurveX(),GetLcurveY());
02078         }
02079      }
02080   } else {
02081      Double_t logTauMin=TMath::Log10(tauMin);
02082      Double_t logTauMax=TMath::Log10(tauMax);
02083      if(nPoint>1) {
02084         // insert maximum tau
02085         DoUnfold(TMath::Power(10.,logTauMax));
02086         Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
02087              logTauMax,GetLcurveX(),GetLcurveY());
02088         curve[logTauMax]=std::make_pair(GetLcurveX(),GetLcurveY());
02089      }
02090      // insert minimum tau
02091      DoUnfold(TMath::Power(10.,logTauMin));
02092      Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
02093           logTauMin,GetLcurveX(),GetLcurveY());
02094      curve[logTauMin]=std::make_pair(GetLcurveX(),GetLcurveY());
02095   }
02096 
02097 
02098   //==========================================================
02099   //    (1b) insert additional points, until nPoint-1 values
02100   //          have been calculated
02101 
02102   while(int(curve.size())<nPoint-1) {
02103     // insert additional points, such that the sizes of the delta(XY) vectors
02104     // are getting smaller and smaller
02105     XYtau_t::const_iterator i0,i1;
02106     i0=curve.begin();
02107     i1=i0;
02108     Double_t logTau=(*i0).first;
02109     Double_t distMax=0.0;
02110     for(i1++;i1!=curve.end();i1++) {
02111       const std::pair<Double_t,Double_t> &xy0=(*i0).second;
02112       const std::pair<Double_t,Double_t> &xy1=(*i1).second;
02113       Double_t dx=xy1.first-xy0.first;
02114       Double_t dy=xy1.second-xy0.second;
02115       Double_t d=TMath::Sqrt(dx*dx+dy*dy);
02116       if(d>=distMax) {
02117         distMax=d;
02118         logTau=0.5*((*i0).first+(*i1).first);
02119       }
02120       i0=i1;
02121     }
02122     DoUnfold(TMath::Power(10.,logTau));
02123     Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",logTau,GetLcurveX(),GetLcurveY());
02124     curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
02125   }
02126 
02127   //==========================================================
02128   //  (2) determine the best choice of tau
02129   //      do the unfolding for this point
02130   //      and store the result in
02131   //        curve
02132   XYtau_t::const_iterator i0,i1;
02133   i0=curve.begin();
02134   i1=i0;
02135   i1++;
02136   Double_t logTauFin=(*i0).first;
02137   if( ((int)curve.size())<nPoint) {
02138     // set up splines and determine (x,y) curvature in each point
02139     Double_t *cTi=new Double_t[curve.size()-1];
02140     Double_t *cCi=new Double_t[curve.size()-1];
02141     Int_t n=0;
02142     {
02143       Double_t *lXi=new Double_t[curve.size()];
02144       Double_t *lYi=new Double_t[curve.size()];
02145       Double_t *lTi=new Double_t[curve.size()];
02146       for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
02147         lXi[n]=(*i).second.first;
02148         lYi[n]=(*i).second.second;
02149         lTi[n]=(*i).first;
02150         n++;
02151       }
02152       TSpline3 *splineX=new TSpline3("x vs tau",lTi,lXi,n);
02153       TSpline3 *splineY=new TSpline3("y vs tau",lTi,lYi,n);
02154       // calculate (x,y) curvature for all points
02155       // the curvature is stored in the array cCi[] as a function of cTi[] 
02156       for(Int_t i=0;i<n-1;i++) {
02157         Double_t ltau,xy,bi,ci,di;
02158         splineX->GetCoeff(i,ltau,xy,bi,ci,di);
02159         Double_t tauBar=0.5*(lTi[i]+lTi[i+1]);
02160         Double_t dTau=0.5*(lTi[i+1]-lTi[i]);
02161         Double_t dx1=bi+dTau*(2.*ci+3.*di*dTau);
02162         Double_t dx2=2.*ci+6.*di*dTau;
02163         splineY->GetCoeff(i,ltau,xy,bi,ci,di);
02164         Double_t dy1=bi+dTau*(2.*ci+3.*di*dTau);
02165         Double_t dy2=2.*ci+6.*di*dTau;
02166         cTi[i]=tauBar;
02167         cCi[i]=(dy2*dx1-dy1*dx2)/TMath::Power(dx1*dx1+dy1*dy1,1.5);
02168       }
02169       delete splineX;
02170       delete splineY;
02171       delete[] lXi;
02172       delete[] lYi;
02173       delete[] lTi;
02174     }
02175     // create curvature Spline
02176     TSpline3 *splineC=new TSpline3("L curve curvature",cTi,cCi,n-1);
02177     // find the maximum of the curvature
02178     // if the parameter iskip is non-zero, then iskip points are
02179     // ignored when looking for the largest curvature
02180     // (there are problems with the curvature determined from the first
02181     //  few points of splineX,splineY in the algorithm above)
02182     Int_t iskip=0;
02183     if(n>4) iskip=1;
02184     if(n>7) iskip=2;
02185     Double_t cCmax=cCi[iskip];
02186     Double_t cTmax=cTi[iskip];
02187     for(Int_t i=iskip;i<n-2-iskip;i++) {
02188       // find maximum on this spline section
02189       // check boundary conditions for x[i+1]
02190       Double_t xMax=cTi[i+1];
02191       Double_t yMax=cCi[i+1];
02192       if(cCi[i]>yMax) {
02193         yMax=cCi[i];
02194         xMax=cTi[i];
02195       }
02196       // find maximum for x[i]<x<x[i+1]
02197       // get spline coefficiencts and solve equation
02198       //   derivative(x)==0
02199       Double_t x,y,b,c,d;
02200       splineC->GetCoeff(i,x,y,b,c,d);
02201       // coefficiencts of quadratic equation
02202       Double_t m_p_half=-c/(3.*d);
02203       Double_t q=b/(3.*d);
02204       Double_t discr=m_p_half*m_p_half-q;
02205       if(discr>=0.0) {
02206         // solution found
02207         discr=TMath::Sqrt(discr);
02208         Double_t xx;
02209         if(m_p_half>0.0) {
02210           xx = m_p_half + discr;
02211         } else {
02212           xx = m_p_half - discr;
02213         }
02214         Double_t dx=cTi[i+1]-x;
02215         // check first solution
02216         if((xx>0.0)&&(xx<dx)) {
02217           y=splineC->Eval(x+xx);
02218           if(y>yMax) {
02219             yMax=y;
02220             xMax=x+xx;
02221           }
02222         }
02223         // second solution
02224         if(xx !=0.0) {
02225           xx= q/xx;
02226         } else {
02227           xx=0.0;
02228         }
02229         // check second solution
02230         if((xx>0.0)&&(xx<dx)) {
02231           y=splineC->Eval(x+xx);
02232           if(y>yMax) {
02233             yMax=y;
02234             xMax=x+xx;
02235           }
02236         }
02237       }
02238       // check whether this local minimum is a global minimum
02239       if(yMax>cCmax) {
02240         cCmax=yMax;
02241         cTmax=xMax;
02242       }
02243     }
02244 #ifdef DEBUG_LCURVE
02245     {
02246       TCanvas lcc;
02247       lcc.Divide(1,1);
02248       lcc.cd(1);
02249       splineC->Draw();
02250       lcc.SaveAs("splinec.ps");
02251     }
02252 #endif
02253     delete splineC;
02254     delete[] cTi;
02255     delete[] cCi;
02256     logTauFin=cTmax;
02257     DoUnfold(TMath::Power(10.,logTauFin));
02258     Info("ScanLcurve","Result logtau=%lf X=%lf Y=%lf",
02259          logTauFin,GetLcurveX(),GetLcurveY());
02260     curve[logTauFin]=std::make_pair(GetLcurveX(),GetLcurveY());
02261   }
02262 
02263 
02264   //==========================================================
02265   //  (3) return the result in
02266   //       lCurve logTauX logTauY
02267 
02268   Int_t bestChoice=-1;
02269   if(curve.size()>0) {
02270     Double_t *x=new Double_t[curve.size()];
02271     Double_t *y=new Double_t[curve.size()];
02272     Double_t *logT=new Double_t[curve.size()];
02273     int n=0;
02274     for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
02275       if(logTauFin==(*i).first) {
02276         bestChoice=n;
02277       }
02278       x[n]=(*i).second.first;
02279       y[n]=(*i).second.second;
02280       logT[n]=(*i).first;
02281       n++;
02282     }
02283     if(lCurve) {
02284        (*lCurve)=new TGraph(n,x,y); 
02285        (*lCurve)->SetTitle("L curve");
02286    }
02287     if(logTauX) (*logTauX)=new TSpline3("log(chi**2)%log(tau)",logT,x,n);
02288     if(logTauY) (*logTauY)=new TSpline3("log(reg.cond)%log(tau)",logT,y,n);
02289     delete[] x;
02290     delete[] y;
02291     delete[] logT;
02292   }
02293 
02294   return bestChoice;
02295 }
02296 
02297 
02298 TH1D *TUnfold::GetOutput(const char *name,const char *title,
02299                          Double_t xmin, Double_t xmax) const
02300 {
02301    // retreive unfolding result as histogram
02302    //   name:  name of the histogram
02303    //   title: title of the histogram
02304    //   x0,x1: lower/upper edge of histogram.
02305    //          if (x0>=x1) then x0=0 and x1=nbin are used
02306 
02307    int nbins = fHistToX.GetSize() - 2;
02308    if (xmin >= xmax) {
02309       xmin = 0.0;
02310       xmax = nbins;
02311    }
02312    TH1D *out = new TH1D(name, title, nbins, xmin, xmax);
02313    GetOutput(out);
02314 
02315    return out;
02316 }
02317 
02318 TH1D *TUnfold::GetBias(const char *name,const char *title,
02319                        Double_t xmin, Double_t xmax) const
02320 {
02321    // retreive bias as histogram
02322    //   name:  name of the histogram
02323    //   title: title of the histogram
02324    //   x0,x1: lower/upper edge of histogram.
02325    //          if (x0>=x1) then x0=0 and x1=nbin are used
02326 
02327    int nbins = fHistToX.GetSize() - 2;
02328    if (xmin >= xmax) {
02329       xmin = 0.0;
02330       xmax = nbins;
02331    }
02332    TH1D *out = new TH1D(name, title, nbins, xmin, xmax);
02333    for (Int_t i = 0; i < GetNx(); i++) {
02334       out->SetBinContent(fXToHist[i], (*fX0) (i, 0));
02335    }
02336    return out;
02337 }
02338 
02339 TH1D *TUnfold::GetFoldedOutput(const char *name,const char *title,
02340                                Double_t y0, Double_t y1) const
02341 {
02342    // retreive unfolding result folded back by the matrix
02343    //   name:  name of the histogram
02344    //   title: title of the histogram
02345    //   y0,y1: lower/upper edge of histogram.
02346    //          if (y0>=y1) then y0=0 and y1=nbin are used
02347 
02348    if (y0 >= y1) {
02349       y0 = 0.0;
02350       y1 = GetNy();
02351    }
02352    TH1D *out = new TH1D(name, title, GetNy(), y0, y1);
02353 
02354    TMatrixDSparse *AVxx=MultiplyMSparseMSparse(fA,fVxx);
02355 
02356 
02357    const Int_t *rows_A=fA->GetRowIndexArray();
02358    const Int_t *cols_A=fA->GetColIndexArray();
02359    const Double_t *data_A=fA->GetMatrixArray();
02360    const Int_t *rows_AVxx=AVxx->GetRowIndexArray();
02361    const Int_t *cols_AVxx=AVxx->GetColIndexArray();
02362    const Double_t *data_AVxx=AVxx->GetMatrixArray();
02363    
02364    for (Int_t i = 0; i < GetNy(); i++) {
02365       out->SetBinContent(i + 1, (*fAx) (i, 0));
02366       Double_t e2=0.0;
02367       Int_t index_a=rows_A[i];
02368       Int_t index_av=rows_AVxx[i];
02369       while((index_a<rows_A[i+1])&&(index_av<rows_AVxx[i])) {
02370          Int_t j_a=cols_A[index_a];
02371          Int_t j_av=cols_AVxx[index_av];
02372          if(j_a<j_av) {
02373             index_a++;
02374          } else if(j_a>j_av) {
02375             index_av++;
02376          } else {
02377             e2 += data_AVxx[index_av] * data_A[index_a];
02378             index_a++;
02379             index_av++;
02380          }
02381       }
02382       out->SetBinError(i + 1,TMath::Sqrt(e2));
02383    }
02384    DeleteMatrix(&AVxx);
02385    return out;
02386 }
02387 
02388 TH1D *TUnfold::GetInput(const char *name,const char *title,
02389                         Double_t y0, Double_t y1) const
02390 {
02391    // retreive input distribution
02392    //   name:  name of the histogram
02393    //   title: title of the histogram
02394    //   y0,y1: lower/upper edge of histogram.
02395    //          if (y0>=y1) then y0=0 and y1=nbin are used
02396 
02397    if (y0 >= y1) {
02398       y0 = 0.0;
02399       y1 = GetNy();
02400    }
02401    TH1D *out = new TH1D(name, title, GetNy(), y0, y1);
02402 
02403    const Int_t *rows_Vyy=fVyy->GetRowIndexArray();
02404    const Int_t *cols_Vyy=fVyy->GetColIndexArray();
02405    const Double_t *data_Vyy=fVyy->GetMatrixArray();
02406 
02407 
02408    for (Int_t i = 0; i < GetNy(); i++) {
02409       out->SetBinContent(i + 1, (*fY) (i, 0));
02410       Double_t e=0.0;
02411       for(int index=rows_Vyy[i];index<rows_Vyy[i+1];index++) {
02412          if(cols_Vyy[index]==i) {
02413             e=TMath::Sqrt(data_Vyy[index]);
02414          }
02415       }
02416       out->SetBinError(i + 1, e);
02417    }
02418    return out;
02419 }
02420 
02421 TH2D *TUnfold::GetRhoIJ(const char *name,const char *title,
02422                         Double_t xmin, Double_t xmax) const
02423 {
02424    // retreive full matrix of correlation coefficients
02425    //   name:  name of the histogram
02426    //   title: title of the histogram
02427    //   x0,x1: lower/upper edge of histogram.
02428    //          if (x0>=x1) then x0=0 and x1=nbin are used
02429 
02430    int nbins = fHistToX.GetSize() - 2;
02431    if (xmin >= xmax) {
02432       xmin = 0.0;
02433       xmax = nbins;
02434    }
02435    TH2D *out = new TH2D(name, title, nbins, xmin, xmax, nbins, xmin, xmax);
02436    GetRhoIJ(out);
02437    return out;
02438 }
02439 
02440 TH2D *TUnfold::GetEmatrix(const char *name,const char *title,
02441                           Double_t xmin, Double_t xmax) const
02442 {
02443    // retreive full error matrix
02444    //   name:  name of the histogram
02445    //   title: title of the histogram
02446    //   x0,x1: lower/upper edge of histogram.
02447    //          if (x0>=x1) then x0=0 and x1=nbin are used
02448 
02449    int nbins = fHistToX.GetSize() - 2;
02450    if (xmin >= xmax) {
02451       xmin = 0.0;
02452       xmax = nbins;
02453    }
02454    TH2D *out = new TH2D(name, title, nbins, xmin, xmax, nbins, xmin, xmax);
02455    GetEmatrix(out);
02456 
02457    return out;
02458 }
02459 
02460 TH1D *TUnfold::GetRhoI(const char *name,const char *title,
02461                        Double_t xmin, Double_t xmax) const
02462 {
02463    // retreive matrix of global correlation coefficients
02464    //   name:  name of the histogram
02465    //   title: title of the histogram
02466    //   x0,x1: lower/upper edge of histogram.
02467    //          if (x0>=x1) then x0=0 and x1=nbin are used
02468 
02469    int nbins = fHistToX.GetSize() - 2;
02470    if (xmin >= xmax) {
02471       xmin = 0.0;
02472       xmax = nbins;
02473    }
02474    TH1D *out = new TH1D(name, title, nbins, xmin, xmax);
02475    GetRhoI(out);
02476 
02477    return out;
02478 }
02479 
02480 TH2D *TUnfold::GetLsquared(const char *name,const char *title,
02481                            Double_t xmin, Double_t xmax) const
02482 {
02483    // retreive ix of regularisation conditions squared
02484    //   name:  name of the histogram
02485    //   title: title of the histogram
02486    //   x0,x1: lower/upper edge of histogram.
02487    //            if (x0>=x1) then x0=0 and x1=nbin are used
02488 
02489    int nbins = fHistToX.GetSize() - 2;
02490    if (xmin >= xmax) {
02491       xmin = 0.0;
02492       xmax = nbins;
02493    }
02494    TH2D *out = new TH2D(name, title, nbins, xmin, xmax, nbins, xmin, xmax);
02495    out->SetOption("BOX");
02496    // loop over sparse matrix
02497    const Int_t *rows=fLsquared->GetRowIndexArray();
02498    const Int_t *cols=fLsquared->GetColIndexArray();
02499    const Double_t *data=fLsquared->GetMatrixArray();
02500    for (Int_t i = 0; i < GetNx(); i++) {
02501       for (Int_t cindex = rows[i]; cindex < rows[i+1]; cindex++) {
02502         Int_t j=cols[cindex];
02503         out->SetBinContent(fXToHist[i], fXToHist[j], fTauSquared * data[cindex]);
02504       }
02505    }
02506 
02507   return out;
02508 }
02509 
02510 void TUnfold::SetConstraint(TUnfold::EConstraint constraint) {
02511    // set type of constraint for the next unfolding
02512    if(fConstraint !=constraint) ClearResults();
02513    fConstraint=constraint;
02514    Info("TUnfold::SetConstraint","fConstraint=%d",fConstraint);
02515 }
02516 
02517 Double_t TUnfold::GetTau(void) const
02518 {
02519    // return regularisation parameter
02520    return TMath::Sqrt(fTauSquared);
02521 }
02522 
02523 Double_t TUnfold::GetChi2L(void) const
02524 {
02525    // return chi**2 contribution from regularisation conditions
02526    return fLXsquared*fTauSquared;
02527 }
02528 
02529 Int_t TUnfold::GetNpar(void) const
02530 {
02531    // return number of parameters
02532    return GetNx();
02533 }
02534 
02535 Double_t TUnfold::GetLcurveX(void) const {
02536   // return value on x axis of L curve
02537   return TMath::Log10(fChi2A);
02538 }
02539 
02540 Double_t TUnfold::GetLcurveY(void) const {
02541   // return value on y axis of L curve
02542   return TMath::Log10(fLXsquared);
02543 }
02544 
02545 void TUnfold::GetOutput(TH1 *output,const Int_t *binMap) const {
02546    // get output distribution, cumulated over several bins
02547    //   output: output histogram
02548    //   binMap: for each bin of the original output distribution
02549    //           specify the destination bin. A value of -1 means that the bin
02550    //           is discarded. 0 means underflow bin, 1 first bin, ...
02551    //        binMap[0] : destination of underflow bin
02552    //        binMap[1] : destination of first bin
02553    //          ...
02554    Int_t nbin=output->GetNbinsX();
02555    Double_t *c=new Double_t[nbin+2];
02556    Double_t *e2=new Double_t[nbin+2];
02557    for(Int_t i=0;i<nbin+2;i++) {
02558       c[i]=0.0;
02559       e2[i]=0.0;
02560    }
02561 
02562    const Int_t *rows_Vxx=fVxx->GetRowIndexArray();
02563    const Int_t *cols_Vxx=fVxx->GetColIndexArray();
02564    const Double_t *data_Vxx=fVxx->GetMatrixArray();
02565 
02566    Int_t binMapSize = fHistToX.GetSize();
02567    for(Int_t i=0;i<binMapSize;i++) {
02568       Int_t destBinI=binMap ? binMap[i] : i;
02569       Int_t srcBinI=fHistToX[i];
02570       if((destBinI>=0)&&(destBinI<nbin+2)&&(srcBinI>=0)) {
02571          c[destBinI]+=(*fX)(srcBinI,0);
02572          // here we loop over the columns of the error matrix
02573          //   j: counts histogram bins
02574          //   index: counts sparse matrix index
02575          // the algorithm makes use of the fact that fHistToX is ordered
02576          Int_t j=0;
02577          Int_t index_vxx=rows_Vxx[srcBinI];
02578          while((j<binMapSize)&&(index_vxx<rows_Vxx[srcBinI+1])) {
02579             Int_t destBinJ=binMap ? binMap[j] : j;
02580             if(destBinI!=destBinJ) {
02581                // only diagonal elements are calculated
02582                j++;
02583             } else {
02584                Int_t srcBinJ=fHistToX[j];
02585                if(srcBinJ<0) {
02586                   // bin is not used, check next bin
02587                   j++;
02588                } else {
02589                   if(cols_Vxx[index_vxx]<srcBinJ) {
02590                      // index is too small
02591                      index_vxx++;
02592                   } else if(cols_Vxx[index_vxx]>srcBinJ) {
02593                      // index is too large, skip bin
02594                      j++;
02595                   } else {
02596                      // add this bin
02597                      e2[destBinI]+= data_Vxx[index_vxx];
02598                      j++;
02599                      index_vxx++;
02600                   }
02601                }
02602             }
02603          }
02604       }
02605    }
02606    for(Int_t i=0;i<nbin+2;i++) {
02607       output->SetBinContent(i,c[i]);
02608       output->SetBinError(i,TMath::Sqrt(e2[i]));
02609    }
02610    delete[] c;
02611    delete[] e2;
02612 }
02613 
02614 void TUnfold::ErrorMatrixToHist(TH2 *ematrix,const TMatrixDSparse *emat,
02615                                 const Int_t *binMap,Bool_t doClear) const {
02616 
02617    // get an error matrix, cumulated over several bins
02618    //   ematrix: output error matrix histogram
02619    //   emat: error matrix
02620    //   binMap: for each bin of the original output distribution
02621    //           specify the destination bin. A value of -1 means that the bin
02622    //           is discarded. 0 means underflow bin, 1 first bin, ...
02623    //        binMap[0] : destination of underflow bin
02624    //        binMap[1] : destination of first bin
02625    //          ...
02626    Int_t nbin=ematrix->GetNbinsX();
02627    if(doClear) {
02628       for(Int_t i=0;i<nbin+2;i++) {
02629          for(Int_t j=0;j<nbin+2;j++) {
02630             ematrix->SetBinContent(i,j,0.0);
02631             ematrix->SetBinError(i,j,0.0);
02632          }
02633       }
02634    }
02635 
02636    if(emat) {
02637       const Int_t *rows_emat=emat->GetRowIndexArray();
02638       const Int_t *cols_emat=emat->GetColIndexArray();
02639       const Double_t *data_emat=emat->GetMatrixArray();
02640 
02641       Int_t binMapSize = fHistToX.GetSize();
02642       for(Int_t i=0;i<binMapSize;i++) {
02643          Int_t destBinI=binMap ? binMap[i] : i;
02644          Int_t srcBinI=fHistToX[i];
02645          if((destBinI>=0)&&(destBinI<nbin+2)&&(srcBinI>=0)) {
02646             // here we loop over the columns of the source matrix
02647             //   j: counts histogram bins
02648             //   index: counts sparse matrix index
02649             // the algorithm makes use of the fact that fHistToX is ordered
02650             Int_t j=0;
02651             Int_t index_vxx=rows_emat[srcBinI];
02652             while((j<binMapSize)&&(index_vxx<rows_emat[srcBinI+1])) {
02653                Int_t destBinJ=binMap ? binMap[j] : j;
02654                Int_t srcBinJ=fHistToX[j];
02655                if((destBinJ<0)||(destBinJ>=nbin+2)||(srcBinJ<0)) {
02656                   // check next bin
02657                   j++;
02658                } else {
02659                   if(cols_emat[index_vxx]<srcBinJ) {
02660                      // index is too small
02661                      index_vxx++;
02662                   } else if(cols_emat[index_vxx]>srcBinJ) {
02663                      // index is too large, skip bin
02664                      j++;
02665                   } else {
02666                      // add this bin
02667                      Double_t e2= ematrix->GetBinContent(destBinI,destBinJ)
02668                         + data_emat[index_vxx];
02669                      ematrix->SetBinContent(destBinI,destBinJ,e2);
02670                      j++;
02671                      index_vxx++;
02672                   }
02673                }
02674             }
02675          }
02676       }
02677    }
02678 }
02679 
02680 void TUnfold::GetEmatrix(TH2 *ematrix,const Int_t *binMap) const {
02681    // get output error matrix, cumulated over several bins
02682    //   ematrix: output error matrix histogram
02683    //   binMap: for each bin of the original output distribution
02684    //           specify the destination bin. A value of -1 means that the bin
02685    //           is discarded. 0 means underflow bin, 1 first bin, ...
02686    //        binMap[0] : destination of underflow bin
02687    //        binMap[1] : destination of first bin
02688    //          ...
02689    ErrorMatrixToHist(ematrix,fVxx,binMap,kTRUE);
02690 }
02691 
02692 Double_t TUnfold::GetRhoI(TH1 *rhoi,TH2 *ematrixinv,const Int_t *binMap) const {
02693    // get global correlation coefficients and inverted error matrix,
02694    // cumulated over several bins
02695    //   rhoi: global correlation histogram
02696    //   ematrixinv: inverse of error matrix (if pointer==0 it is not returned)
02697    //   binMap: for each bin of the original output distribution
02698    //           specify the destination bin. A value of -1 means that the bin
02699    //           is discarded. 0 means underflow bin, 1 first bin, ...
02700    //        binMap[0] : destination of underflow bin
02701    //        binMap[1] : destination of first bin
02702    //          ...
02703    // return value: average global correlation
02704 
02705    Int_t nbin=rhoi->GetNbinsX();  
02706 
02707    // The unfolding is based on a root TH2D histogram.
02708    // Internally, these histogram bins are mapped to Matrix cols:
02709    //    fHistToX[i]   is the matrix-row corresponding to matrix-bin i
02710    //    fXToHist[i]   is the matrix-bin corresponding to matrix-col i
02711    //
02712    // for the output, another level of mapping is added, such that
02713    // a matrix-bin is mapped to one or more output-bins
02714    //    binMap[i]     is the output-bin corresponding to matrix-bin i
02715 
02716    // below, the matrix-rows are summed to emat-rows, then the emat-rows
02717    // are stored to output-bins
02718 
02719    // n counts the number of active bins in the output histogram
02720    Int_t n=0;
02721    Int_t *outputToEmat=new Int_t[nbin+2];
02722    Int_t *ematToOutput=new Int_t[nbin+2];
02723    Int_t *vxxToEmat=new Int_t[GetNx()];
02724    for(Int_t i=0;i<nbin+2;i++) {
02725       outputToEmat[i]=-1;
02726    }
02727    for(Int_t i=0;i<GetNx();i++) {
02728       Int_t matrix_bin=fXToHist[i];
02729       Int_t output_bin=binMap ? binMap[matrix_bin] : matrix_bin;
02730       if((output_bin>=0)&&(output_bin<nbin+2)) {
02731          // matrix-col i will be stored to output_bin
02732          if(outputToEmat[output_bin]<0) {
02733             // new bin n
02734             outputToEmat[output_bin]=n;
02735             ematToOutput[n]=output_bin;
02736             n++;
02737          }
02738          vxxToEmat[i]=outputToEmat[output_bin];
02739       } else {
02740          vxxToEmat[i]=-1;
02741       }
02742    }
02743    delete[] outputToEmat;
02744 
02745    // now:
02746    //   create new error matrix emat(n,n)
02747    //   sum all bins of Vxx into the new matrix, using the mapping
02748    //    vxxToEmat[]
02749    // later:
02750    //   pack emat(n,n) to the histogram, using the mapping
02751    //    ematToOutput
02752 
02753    // set up reduced error matrix
02754    TMatrixD e(n,n);
02755    const Int_t *rows_Vxx=fVxx->GetRowIndexArray();
02756    const Int_t *cols_Vxx=fVxx->GetColIndexArray();
02757    const Double_t *data_Vxx=fVxx->GetMatrixArray();
02758    for(Int_t i=0;i<GetNx();i++) {
02759       Int_t ie=vxxToEmat[i];
02760       if(ie<0) continue;
02761       for(int index_vxx=rows_Vxx[i];index_vxx<rows_Vxx[i+1];index_vxx++) {
02762          Int_t je=vxxToEmat[cols_Vxx[index_vxx]];
02763          if(je<0) continue;
02764          e(ie,je) += data_Vxx[index_vxx];
02765       }
02766    }
02767    delete[] vxxToEmat;
02768 
02769    // invert error matrix
02770    TMatrixD einv(e);
02771    InvertMConditioned(&einv);
02772 
02773    Double_t rhoMax=0.0;
02774    for(Int_t i=0;i<n;i++) {
02775       Int_t i_out=ematToOutput[i];
02776       Double_t rho=1.-1./(einv(i,i)*e(i,i));
02777       if(rho>=0.0) rho=TMath::Sqrt(rho);
02778       else rho=-TMath::Sqrt(-rho);
02779       if(rho>rhoMax) {
02780          rhoMax = rho;
02781       }
02782       rhoi->SetBinContent(i_out,rho);
02783       if(ematrixinv) {
02784          for(Int_t j=0;j<n;j++) {
02785             ematrixinv->SetBinContent(i_out,ematToOutput[j],einv(i,j));
02786          }
02787       }
02788    }
02789    delete[] ematToOutput;
02790 
02791    return rhoMax;
02792 }
02793 
02794 void TUnfold::GetRhoIJ(TH2 *rhoij,const Int_t *binMap) const {
02795    // get correlation coefficient matrix, cumulated over several bins
02796    //   rhoij:  correlation coefficient matrix histogram
02797    //   binMap: for each bin of the original output distribution
02798    //           specify the destination bin. A value of -1 means that the bin
02799    //           is discarded. 0 means underflow bin, 1 first bin, ...
02800    //        binMap[0] : destination of underflow bin
02801    //        binMap[1] : destination of first bin
02802    //          ...
02803    GetEmatrix(rhoij,binMap);
02804    Int_t nbin=rhoij->GetNbinsX();  
02805    Double_t *e=new Double_t[nbin+2];
02806    for(Int_t i=0;i<nbin+2;i++) {
02807       e[i]=TMath::Sqrt(rhoij->GetBinContent(i,i));
02808    }
02809    for(Int_t i=0;i<nbin+2;i++) {
02810       for(Int_t j=0;j<nbin+2;j++) {
02811          if((e[i]>0.0)&&(e[j]>0.0)) {
02812             rhoij->SetBinContent(i,j,rhoij->GetBinContent(i,j)/e[i]/e[j]);
02813          } else {
02814             rhoij->SetBinContent(i,j,0.0);
02815          }
02816       }
02817    }
02818    delete[] e;
02819 }

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