#include <iostream>
#include <TMatrixD.h>
#include <TMatrixDSparse.h>
#include <TMatrixDSym.h>
#include <TMatrixDSymEigen.h>
#include <TMath.h>
#include "TUnfold.h"
#include <map>
#include <vector>
#ifdef DEBUG_LCURVE
#include <TCanvas.h>
#endif
ClassImp(TUnfold)
const char *TUnfold::GetTUnfoldVersion(void)
{
return TUnfold_VERSION;
}
void TUnfold::InitTUnfold(void)
{
fXToHist.Set(0);
fHistToX.Set(0);
fSumOverY.Set(0);
fA = 0;
fL = 0;
fVyy = 0;
fY = 0;
fX0 = 0;
fTauSquared = 0.0;
fBiasScale = 0.0;
fNdf = 0;
fConstraint = kEConstraintNone;
fRegMode = kRegModeNone;
fVyyInv = 0;
fVxx = 0;
fX = 0;
fAx = 0;
fChi2A = 0.0;
fLXsquared = 0.0;
fRhoMax = 999.0;
fRhoAvg = -1.0;
fDXDAM[0] = 0;
fDXDAZ[0] = 0;
fDXDAM[1] = 0;
fDXDAZ[1] = 0;
fDXDtauSquared = 0;
fDXDY = 0;
fEinv = 0;
fE = 0;
fVxxInv = 0;
fEpsMatrix=1.E-13;
fIgnoredBins=0;
}
void TUnfold::DeleteMatrix(TMatrixD **m)
{
if(*m) delete *m;
*m=0;
}
void TUnfold::DeleteMatrix(TMatrixDSparse **m)
{
if(*m) delete *m;
*m=0;
}
void TUnfold::ClearResults(void)
{
DeleteMatrix(&fVxx);
DeleteMatrix(&fX);
DeleteMatrix(&fAx);
for(Int_t i=0;i<2;i++) {
DeleteMatrix(fDXDAM+i);
DeleteMatrix(fDXDAZ+i);
}
DeleteMatrix(&fDXDtauSquared);
DeleteMatrix(&fDXDY);
DeleteMatrix(&fEinv);
DeleteMatrix(&fE);
DeleteMatrix(&fVxxInv);
fChi2A = 0.0;
fLXsquared = 0.0;
fRhoMax = 999.0;
fRhoAvg = -1.0;
}
TUnfold::TUnfold(void)
{
InitTUnfold();
}
Double_t TUnfold::DoUnfold(void)
{
ClearResults();
if(!fVyyInv) {
GetInputInverseEmatrix(0);
if(fConstraint != kEConstraintNone) {
fNdf--;
}
}
TMatrixDSparse *AtVyyinv=MultiplyMSparseTranspMSparse(fA,fVyyInv);
TMatrixDSparse *rhs=MultiplyMSparseM(AtVyyinv,fY);
TMatrixDSparse *lSquared=MultiplyMSparseTranspMSparse(fL,fL);
if (fBiasScale != 0.0) {
TMatrixDSparse *rhs2=MultiplyMSparseM(lSquared,fX0);
AddMSparse(rhs, fTauSquared * fBiasScale ,rhs2);
DeleteMatrix(&rhs2);
}
fEinv=MultiplyMSparseMSparse(AtVyyinv,fA);
AddMSparse(fEinv,fTauSquared,lSquared);
Int_t rank=0;
fE = InvertMSparseSymmPos(fEinv,&rank);
if(rank != GetNx()) {
Warning("DoUnfold","rank of matrix E %d expect %d",rank,GetNx());
}
TMatrixDSparse *xSparse=MultiplyMSparseMSparse(fE,rhs);
fX = new TMatrixD(*xSparse);
DeleteMatrix(&rhs);
DeleteMatrix(&xSparse);
Double_t lambda_half=0.0;
Double_t one_over_epsEeps=0.0;
TMatrixDSparse *epsilon=0;
TMatrixDSparse *Eepsilon=0;
if(fConstraint != kEConstraintNone) {
const Int_t *A_rows=fA->GetRowIndexArray();
const Int_t *A_cols=fA->GetColIndexArray();
const Double_t *A_data=fA->GetMatrixArray();
TMatrixD epsilonNosparse(fA->GetNcols(),1);
for(Int_t i=0;i<A_rows[fA->GetNrows()];i++) {
epsilonNosparse(A_cols[i],0) += A_data[i];
}
epsilon=new TMatrixDSparse(epsilonNosparse);
Eepsilon=MultiplyMSparseMSparse(fE,epsilon);
TMatrixDSparse *epsilonEepsilon=MultiplyMSparseTranspMSparse(epsilon,
Eepsilon);
if(epsilonEepsilon->GetRowIndexArray()[1]==1) {
one_over_epsEeps=1./epsilonEepsilon->GetMatrixArray()[0];
} else {
Fatal("Unfold","epsilon#Eepsilon has dimension %d != 1",
epsilonEepsilon->GetRowIndexArray()[1]);
}
DeleteMatrix(&epsilonEepsilon);
Double_t y_minus_epsx=0.0;
for(Int_t iy=0;iy<fY->GetNrows();iy++) {
y_minus_epsx += (*fY)(iy,0);
}
for(Int_t ix=0;ix<epsilonNosparse.GetNrows();ix++) {
y_minus_epsx -= epsilonNosparse(ix,0) * (*fX)(ix,0);
}
lambda_half=y_minus_epsx*one_over_epsEeps;
const Int_t *EEpsilon_rows=Eepsilon->GetRowIndexArray();
const Double_t *EEpsilon_data=Eepsilon->GetMatrixArray();
for(Int_t ix=0;ix<Eepsilon->GetNrows();ix++) {
if(EEpsilon_rows[ix]<EEpsilon_rows[ix+1]) {
(*fX)(ix,0) += lambda_half * EEpsilon_data[EEpsilon_rows[ix]];
}
}
}
fDXDY = MultiplyMSparseMSparse(fE,AtVyyinv);
if(fConstraint != kEConstraintNone) {
Int_t *rows=new Int_t[GetNy()];
Int_t *cols=new Int_t[GetNy()];
Double_t *data=new Double_t[GetNy()];
for(Int_t i=0;i<GetNy();i++) {
rows[i]=0;
cols[i]=i;
data[i]=one_over_epsEeps;
}
TMatrixDSparse *temp=CreateSparseMatrix
(1,GetNy(),GetNy(),rows,cols,data);
delete[] data;
delete[] rows;
delete[] cols;
TMatrixDSparse *epsilonB=MultiplyMSparseTranspMSparse(epsilon,fDXDY);
AddMSparse(temp, -one_over_epsEeps, epsilonB);
DeleteMatrix(&epsilonB);
TMatrixDSparse *corr=MultiplyMSparseMSparse(Eepsilon,temp);
DeleteMatrix(&temp);
AddMSparse(fDXDY,1.0,corr);
DeleteMatrix(&corr);
}
DeleteMatrix(&AtVyyinv);
TMatrixDSparse *fDXDYVyy = MultiplyMSparseMSparse(fDXDY,fVyy);
fVxx = MultiplyMSparseMSparseTranspVector(fDXDYVyy,fDXDY,0);
DeleteMatrix(&fDXDYVyy);
fAx = MultiplyMSparseM(fA,fX);
TMatrixD dy(*fY, TMatrixD::kMinus, *fAx);
TMatrixDSparse *VyyinvDy=MultiplyMSparseM(fVyyInv,&dy);
const Int_t *VyyinvDy_rows=VyyinvDy->GetRowIndexArray();
const Double_t *VyyinvDy_data=VyyinvDy->GetMatrixArray();
fChi2A=0.0;
for(Int_t iy=0;iy<VyyinvDy->GetNrows();iy++) {
if(VyyinvDy_rows[iy]<VyyinvDy_rows[iy+1]) {
fChi2A += VyyinvDy_data[VyyinvDy_rows[iy]]*dy(iy,0);
}
}
TMatrixD dx( fBiasScale * (*fX0), TMatrixD::kMinus,(*fX));
TMatrixDSparse *LsquaredDx=MultiplyMSparseM(lSquared,&dx);
const Int_t *LsquaredDx_rows=LsquaredDx->GetRowIndexArray();
const Double_t *LsquaredDx_data=LsquaredDx->GetMatrixArray();
fLXsquared = 0.0;
for(Int_t ix=0;ix<LsquaredDx->GetNrows();ix++) {
if(LsquaredDx_rows[ix]<LsquaredDx_rows[ix+1]) {
fLXsquared += LsquaredDx_data[LsquaredDx_rows[ix]]*dx(ix,0);
}
}
fDXDtauSquared=MultiplyMSparseMSparse(fE,LsquaredDx);
if(fConstraint != kEConstraintNone) {
TMatrixDSparse *temp=MultiplyMSparseTranspMSparse(epsilon,fDXDtauSquared);
Double_t f=0.0;
if(temp->GetRowIndexArray()[1]==1) {
f=temp->GetMatrixArray()[0]*one_over_epsEeps;
} else if(temp->GetRowIndexArray()[1]>1) {
Fatal("Unfold",
"epsilon#fDXDtauSquared has dimension %d != 1",
temp->GetRowIndexArray()[1]);
}
if(f!=0.0) {
AddMSparse(fDXDtauSquared, -f,Eepsilon);
}
DeleteMatrix(&temp);
}
DeleteMatrix(&epsilon);
DeleteMatrix(&LsquaredDx);
DeleteMatrix(&lSquared);
fDXDAM[0]=new TMatrixDSparse(*fE);
fDXDAM[1]=new TMatrixDSparse(*fDXDY);
fDXDAZ[0]=VyyinvDy;
VyyinvDy=0;
fDXDAZ[1]=new TMatrixDSparse(*fX);
if(fConstraint != kEConstraintNone) {
TMatrixDSparse *temp1=MultiplyMSparseMSparseTranspVector
(Eepsilon,Eepsilon,0);
AddMSparse(fDXDAM[0], -one_over_epsEeps,temp1);
DeleteMatrix(&temp1);
Int_t *rows=new Int_t[GetNy()];
Int_t *cols=new Int_t[GetNy()];
Double_t *data=new Double_t[GetNy()];
for(Int_t i=0;i<GetNy();i++) {
rows[i]=i;
cols[i]=0;
data[i]=lambda_half;
}
TMatrixDSparse *temp2=CreateSparseMatrix
(GetNy(),1,GetNy(),rows,cols,data);
delete[] data;
delete[] rows;
delete[] cols;
AddMSparse(fDXDAZ[0],1.0,temp2);
DeleteMatrix(&temp2);
}
DeleteMatrix(&Eepsilon);
rank=0;
fVxxInv = InvertMSparseSymmPos(fVxx,&rank);
if(rank != GetNx()) {
Warning("DoUnfold","rank of output covariance is %d expect %d",
rank,GetNx());
}
TVectorD VxxInvDiag(fVxxInv->GetNrows());
const Int_t *VxxInv_rows=fVxxInv->GetRowIndexArray();
const Int_t *VxxInv_cols=fVxxInv->GetColIndexArray();
const Double_t *VxxInv_data=fVxxInv->GetMatrixArray();
for (int ix = 0; ix < fVxxInv->GetNrows(); ix++) {
for(int ik=VxxInv_rows[ix];ik<VxxInv_rows[ix+1];ik++) {
if(ix==VxxInv_cols[ik]) {
VxxInvDiag(ix)=VxxInv_data[ik];
}
}
}
const Int_t *Vxx_rows=fVxx->GetRowIndexArray();
const Int_t *Vxx_cols=fVxx->GetColIndexArray();
const Double_t *Vxx_data=fVxx->GetMatrixArray();
Double_t rho_squared_max = 0.0;
Double_t rho_sum = 0.0;
Int_t n_rho=0;
for (int ix = 0; ix < fVxx->GetNrows(); ix++) {
for(int ik=Vxx_rows[ix];ik<Vxx_rows[ix+1];ik++) {
if(ix==Vxx_cols[ik]) {
Double_t rho_squared =
1. - 1. / (VxxInvDiag(ix) * Vxx_data[ik]);
if (rho_squared > rho_squared_max)
rho_squared_max = rho_squared;
if(rho_squared>0.0) {
rho_sum += TMath::Sqrt(rho_squared);
n_rho++;
}
break;
}
}
}
fRhoMax = TMath::Sqrt(rho_squared_max);
fRhoAvg = (n_rho>0) ? (rho_sum/n_rho) : -1.0;
return fRhoMax;
}
TMatrixDSparse *TUnfold::CreateSparseMatrix
(Int_t nrow,Int_t ncol,Int_t nel,Int_t *row,Int_t *col,Double_t *data) const
{
TMatrixDSparse *A=new TMatrixDSparse(nrow,ncol);
if(nel>0) {
A->SetMatrixArray(nel,row,col,data);
}
return A;
}
TMatrixDSparse *TUnfold::MultiplyMSparseMSparse(const TMatrixDSparse *a,
const TMatrixDSparse *b) const
{
if(a->GetNcols()!=b->GetNrows()) {
Fatal("MultiplyMSparseMSparse",
"inconsistent matrix col/ matrix row %d !=%d",
a->GetNcols(),b->GetNrows());
}
TMatrixDSparse *r=new TMatrixDSparse(a->GetNrows(),b->GetNcols());
const Int_t *a_rows=a->GetRowIndexArray();
const Int_t *a_cols=a->GetColIndexArray();
const Double_t *a_data=a->GetMatrixArray();
const Int_t *b_rows=b->GetRowIndexArray();
const Int_t *b_cols=b->GetColIndexArray();
const Double_t *b_data=b->GetMatrixArray();
int nMax=0;
for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
if(a_rows[irow+1]>a_rows[irow]) nMax += b->GetNcols();
}
if((nMax>0)&&(a_cols)&&(b_cols)) {
Int_t *r_rows=new Int_t[nMax];
Int_t *r_cols=new Int_t[nMax];
Double_t *r_data=new Double_t[nMax];
Double_t *row_data=new Double_t[b->GetNcols()];
Int_t n=0;
for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
if(a_rows[irow+1]<=a_rows[irow]) continue;
for(Int_t icol=0;icol<b->GetNcols();icol++) {
row_data[icol]=0.0;
}
for(Int_t ia=a_rows[irow];ia<a_rows[irow+1];ia++) {
Int_t k=a_cols[ia];
for(Int_t ib=b_rows[k];ib<b_rows[k+1];ib++) {
row_data[b_cols[ib]] += a_data[ia]*b_data[ib];
}
}
for(Int_t icol=0;icol<b->GetNcols();icol++) {
if(row_data[icol] != 0.0) {
r_rows[n]=irow;
r_cols[n]=icol;
r_data[n]=row_data[icol];
n++;
}
}
}
if(n>0) {
r->SetMatrixArray(n,r_rows,r_cols,r_data);
}
delete[] r_rows;
delete[] r_cols;
delete[] r_data;
delete[] row_data;
}
return r;
}
TMatrixDSparse *TUnfold::MultiplyMSparseTranspMSparse
(const TMatrixDSparse *a,const TMatrixDSparse *b) const
{
if(a->GetNrows() != b->GetNrows()) {
Fatal("MultiplyMSparseTranspMSparse",
"inconsistent matrix row numbers %d!=%d",
a->GetNrows(),b->GetNrows());
}
TMatrixDSparse *r=new TMatrixDSparse(a->GetNcols(),b->GetNcols());
const Int_t *a_rows=a->GetRowIndexArray();
const Int_t *a_cols=a->GetColIndexArray();
const Double_t *a_data=a->GetMatrixArray();
const Int_t *b_rows=b->GetRowIndexArray();
const Int_t *b_cols=b->GetColIndexArray();
const Double_t *b_data=b->GetMatrixArray();
typedef std::map<Int_t,Double_t> MMatrixRow_t;
typedef std::map<Int_t, MMatrixRow_t > MMatrix_t;
MMatrix_t matrix;
for(Int_t iRowAB=0;iRowAB<a->GetNrows();iRowAB++) {
for(Int_t ia=a_rows[iRowAB];ia<a_rows[iRowAB+1];ia++) {
for(Int_t ib=b_rows[iRowAB];ib<b_rows[iRowAB+1];ib++) {
MMatrixRow_t &row=matrix[a_cols[ia]];
MMatrixRow_t::iterator icol=row.find(b_cols[ib]);
if(icol!=row.end()) {
(*icol).second += a_data[ia]*b_data[ib];
} else {
row[b_cols[ib]] = a_data[ia]*b_data[ib];
}
}
}
}
Int_t n=0;
for(MMatrix_t::const_iterator irow=matrix.begin();
irow!=matrix.end();irow++) {
n += (*irow).second.size();
}
if(n>0) {
Int_t *r_rows=new Int_t[n];
Int_t *r_cols=new Int_t[n];
Double_t *r_data=new Double_t[n];
n=0;
for(MMatrix_t::const_iterator irow=matrix.begin();
irow!=matrix.end();irow++) {
for(MMatrixRow_t::const_iterator icol=(*irow).second.begin();
icol!=(*irow).second.end();icol++) {
r_rows[n]=(*irow).first;
r_cols[n]=(*icol).first;
r_data[n]=(*icol).second;
n++;
}
}
if(n>0) {
r->SetMatrixArray(n,r_rows,r_cols,r_data);
}
delete[] r_rows;
delete[] r_cols;
delete[] r_data;
}
return r;
}
TMatrixDSparse *TUnfold::MultiplyMSparseM(const TMatrixDSparse *a,
const TMatrixD *b) const
{
if(a->GetNcols()!=b->GetNrows()) {
Fatal("MultiplyMSparseM","inconsistent matrix col /matrix row %d!=%d",
a->GetNcols(),b->GetNrows());
}
TMatrixDSparse *r=new TMatrixDSparse(a->GetNrows(),b->GetNcols());
const Int_t *a_rows=a->GetRowIndexArray();
const Int_t *a_cols=a->GetColIndexArray();
const Double_t *a_data=a->GetMatrixArray();
int nMax=0;
for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
if(a_rows[irow+1]-a_rows[irow]>0) nMax += b->GetNcols();
}
if(nMax>0) {
Int_t *r_rows=new Int_t[nMax];
Int_t *r_cols=new Int_t[nMax];
Double_t *r_data=new Double_t[nMax];
Int_t n=0;
for (Int_t irow = 0; irow < a->GetNrows(); irow++) {
if(a_rows[irow+1]-a_rows[irow]<=0) continue;
for(Int_t icol=0;icol<b->GetNcols();icol++) {
r_rows[n]=irow;
r_cols[n]=icol;
r_data[n]=0.0;
for(Int_t i=a_rows[irow];i<a_rows[irow+1];i++) {
Int_t j=a_cols[i];
r_data[n] += a_data[i]*(*b)(j,icol);
}
if(r_data[n]!=0.0) n++;
}
}
if(n>0) {
r->SetMatrixArray(n,r_rows,r_cols,r_data);
}
delete[] r_rows;
delete[] r_cols;
delete[] r_data;
}
return r;
}
TMatrixDSparse *TUnfold::MultiplyMSparseMSparseTranspVector
(const TMatrixDSparse *m1,const TMatrixDSparse *m2,
const TMatrixTBase<Double_t> *v) const
{
if((m1->GetNcols() != m2->GetNcols())||
(v && ((m1->GetNcols()!=v->GetNrows())||(v->GetNcols()!=1)))) {
if(v) {
Fatal("MultiplyMSparseMSparseTranspVector",
"matrix cols/vector rows %d!=%d!=%d or vector rows %d!=1\n",
m1->GetNcols(),m2->GetNcols(),v->GetNrows(),v->GetNcols());
} else {
Fatal("MultiplyMSparseMSparseTranspVector",
"matrix cols %d!=%d\n",m1->GetNcols(),m2->GetNcols());
}
}
const Int_t *rows_m1=m1->GetRowIndexArray();
const Int_t *cols_m1=m1->GetColIndexArray();
const Double_t *data_m1=m1->GetMatrixArray();
Int_t num_m1=0;
for(Int_t i=0;i<m1->GetNrows();i++) {
if(rows_m1[i]<rows_m1[i+1]) num_m1++;
}
const Int_t *rows_m2=m2->GetRowIndexArray();
const Int_t *cols_m2=m2->GetColIndexArray();
const Double_t *data_m2=m2->GetMatrixArray();
Int_t num_m2=0;
for(Int_t j=0;j<m2->GetNrows();j++) {
if(rows_m2[j]<rows_m2[j+1]) num_m2++;
}
const TMatrixDSparse *v_sparse=dynamic_cast<const TMatrixDSparse *>(v);
const Int_t *v_rows=0;
const Double_t *v_data=0;
if(v_sparse) {
v_rows=v_sparse->GetRowIndexArray();
v_data=v_sparse->GetMatrixArray();
}
Int_t num_r=num_m1*num_m2+1;
Int_t *row_r=new Int_t[num_r];
Int_t *col_r=new Int_t[num_r];
Double_t *data_r=new Double_t[num_r];
num_r=0;
for(Int_t i=0;i<m1->GetNrows();i++) {
for(Int_t j=0;j<m2->GetNrows();j++) {
data_r[num_r]=0.0;
Int_t index_m1=rows_m1[i];
Int_t index_m2=rows_m2[j];
while((index_m1<rows_m1[i+1])&&(index_m2<rows_m2[j+1])) {
Int_t k1=cols_m1[index_m1];
Int_t k2=cols_m2[index_m2];
if(k1<k2) {
index_m1++;
} else if(k1>k2) {
index_m2++;
} else {
if(v_sparse) {
Int_t v_index=v_rows[k1];
if(v_index<v_rows[k1+1]) {
data_r[num_r] += data_m1[index_m1] * data_m2[index_m2]
* v_data[v_index];
} else {
data_r[num_r] =0.0;
}
} else if(v) {
data_r[num_r] += data_m1[index_m1] * data_m2[index_m2]
* (*v)(k1,0);
} else {
data_r[num_r] += data_m1[index_m1] * data_m2[index_m2];
}
index_m1++;
index_m2++;
}
}
if(data_r[num_r] !=0.0) {
row_r[num_r]=i;
col_r[num_r]=j;
num_r++;
}
}
}
TMatrixDSparse *r=CreateSparseMatrix(m1->GetNrows(),m2->GetNrows(),
num_r,row_r,col_r,data_r);
delete[] row_r;
delete[] col_r;
delete[] data_r;
return r;
}
void TUnfold::AddMSparse(TMatrixDSparse *dest,Double_t f,
const TMatrixDSparse *src) const
{
const Int_t *dest_rows=dest->GetRowIndexArray();
const Int_t *dest_cols=dest->GetColIndexArray();
const Double_t *dest_data=dest->GetMatrixArray();
const Int_t *src_rows=src->GetRowIndexArray();
const Int_t *src_cols=src->GetColIndexArray();
const Double_t *src_data=src->GetMatrixArray();
if((dest->GetNrows()!=src->GetNrows())||
(dest->GetNcols()!=src->GetNcols())) {
Fatal("AddMSparse","inconsistent matrix rows %d!=%d OR cols %d!=%d",
src->GetNrows(),dest->GetNrows(),src->GetNcols(),dest->GetNcols());
}
Int_t nmax=dest->GetNrows()*dest->GetNcols();
Double_t *result_data=new Double_t[nmax];
Int_t *result_rows=new Int_t[nmax];
Int_t *result_cols=new Int_t[nmax];
Int_t n=0;
for(Int_t row=0;row<dest->GetNrows();row++) {
Int_t i_dest=dest_rows[row];
Int_t i_src=src_rows[row];
while((i_dest<dest_rows[row+1])||(i_src<src_rows[row+1])) {
Int_t col_dest=(i_dest<dest_rows[row+1]) ?
dest_cols[i_dest] : dest->GetNcols();
Int_t col_src =(i_src <src_rows[row+1] ) ?
src_cols [i_src] : src->GetNcols();
result_rows[n]=row;
if(col_dest<col_src) {
result_cols[n]=col_dest;
result_data[n]=dest_data[i_dest++];
} else if(col_dest>col_src) {
result_cols[n]=col_src;
result_data[n]=f*src_data[i_src++];
} else {
result_cols[n]=col_dest;
result_data[n]=dest_data[i_dest++]+f*src_data[i_src++];
}
if(result_data[n] !=0.0) {
if(!TMath::Finite(result_data[n])) {
Fatal("AddMSparse","Nan detected %d %d %d",
row,i_dest,i_src);
}
n++;
}
}
}
if(n<=0) {
n=1;
result_rows[0]=0;
result_cols[0]=0;
result_data[0]=0.0;
}
dest->SetMatrixArray(n,result_rows,result_cols,result_data);
delete[] result_data;
delete[] result_rows;
delete[] result_cols;
}
TMatrixDSparse *TUnfold::InvertMSparseSymmPos
(const TMatrixDSparse *A,Int_t *rankPtr) const
{
if(A->GetNcols()!=A->GetNrows()) {
Fatal("InvertMSparseSymmPos","inconsistent matrix row/col %d!=%d",
A->GetNcols(),A->GetNrows());
}
Bool_t *isZero=new Bool_t[A->GetNrows()];
const Int_t *a_rows=A->GetRowIndexArray();
const Int_t *a_cols=A->GetColIndexArray();
const Double_t *a_data=A->GetMatrixArray();
Int_t iDiagonal=0;
Int_t iBlock=A->GetNrows();
Bool_t isDiagonal=kTRUE;
TVectorD aII(A->GetNrows());
Int_t nError=0;
for(Int_t iA=0;iA<A->GetNrows();iA++) {
for(Int_t indexA=a_rows[iA];indexA<a_rows[iA+1];indexA++) {
Int_t jA=a_cols[indexA];
if(iA==jA) {
if(!(a_data[indexA]>=0.0)) nError++;
aII(iA)=a_data[indexA];
}
}
}
if(nError>0) {
delete isZero;
Fatal("InvertMSparseSymmPos",
"Matrix has %d negative elements on the diagonal", nError);
return 0;
}
Int_t *swap=new Int_t[A->GetNrows()];
for(Int_t j=0;j<A->GetNrows();j++) swap[j]=j;
for(Int_t iStart=0;iStart<iBlock;iStart++) {
Int_t nZero=0;
for(Int_t i=iStart;i<iBlock;i++) {
Int_t iA=swap[i];
Int_t n=A->GetNrows()-(a_rows[iA+1]-a_rows[iA]);
if(n>nZero) {
Int_t tmp=swap[iStart];
swap[iStart]=swap[i];
swap[i]=tmp;
nZero=n;
}
}
for(Int_t i=0;i<A->GetNrows();i++) isZero[i]=kTRUE;
Int_t iA=swap[iStart];
for(Int_t indexA=a_rows[iA];indexA<a_rows[iA+1];indexA++) {
Int_t jA=a_cols[indexA];
isZero[jA]=kFALSE;
if(iA!=jA) {
isDiagonal=kFALSE;
}
}
if(isDiagonal) {
iDiagonal=iStart+1;
} else {
for(Int_t i=iStart+1;i<iBlock;) {
if(isZero[swap[i]]) {
i++;
} else {
iBlock--;
Int_t tmp=swap[iBlock];
swap[iBlock]=swap[i];
swap[i]=tmp;
}
}
}
}
#ifdef CONDITION_BLOCK_PART
Int_t nn=A->GetNrows()-iBlock;
for(int inc=(nn+1)/2;inc;inc /= 2) {
for(int i=inc;i<nn;i++) {
int itmp=swap[i+iBlock];
int j;
for(j=i;(j>=inc)&&(aII(swap[j-inc+iBlock])<aII(itmp));j -=inc) {
swap[j+iBlock]=swap[j-inc+iBlock];
}
swap[j+iBlock]=itmp;
}
}
#endif
Int_t *swapBack=new Int_t[A->GetNrows()];
for(Int_t i=0;i<A->GetNrows();i++) {
swapBack[swap[i]]=i;
}
#ifdef DEBUG_DETAIL
for(Int_t i=0;i<A->GetNrows();i++) {
std::cout<<" "<<i<<" "<<swap[i]<<" "<<swapBack[i]<<"\n";
}
std::cout<<"after sorting\n";
for(Int_t i=0;i<A->GetNrows();i++) {
if(i==iDiagonal) std::cout<<"iDiagonal="<<i<<"\n";
if(i==iBlock) std::cout<<"iBlock="<<i<<"\n";
std::cout<<" "<<swap[i]<<" "<<aII(swap[i])<<"\n";
}
{
Int_t nDiag=0;
Int_t nError1=0;
Int_t nError2=0;
Int_t nBlock=0;
Int_t nNonzero=0;
for(Int_t i=0;i<A->GetNrows();i++) {
Int_t row=swap[i];
for(Int_t indexA=a_rows[row];indexA<a_rows[row+1];indexA++) {
Int_t j=swapBack[a_cols[indexA]];
if(i==j) nDiag++;
else if((i<iDiagonal)||(j<iDiagonal)) nError1++;
else if((i<iBlock)&&(j<iBlock)) nError2++;
else if((i<iBlock)||(j<iBlock)) nBlock++;
else nNonzero++;
}
}
if(nError1+nError2>0) {
Fatal("InvertMSparseSymmPos","sparse matrix analysis failed %d %d %d %d %d",
iDiagonal,iBlock,A->GetNrows(),nError1,nError2);
}
}
#endif
#ifdef DEBUG
Info("InvertMSparseSymmPos","iDiagonal=%d iBlock=%d nRow=%d",
iDiagonal,iBlock,A->GetNrows());
#endif
Double_t *rEl_data=new Double_t[A->GetNrows()*A->GetNrows()];
Int_t *rEl_col=new Int_t[A->GetNrows()*A->GetNrows()];
Int_t *rEl_row=new Int_t[A->GetNrows()*A->GetNrows()];
Int_t rNumEl=0;
Int_t rankD1=0;
for(Int_t i=0;i<iDiagonal;++i) {
Int_t iA=swap[i];
if(aII(iA)>0.0) {
rEl_col[rNumEl]=iA;
rEl_row[rNumEl]=iA;
rEl_data[rNumEl]=1./aII(iA);
++rankD1;
++rNumEl;
}
}
if((!rankPtr)&&(rankD1!=iDiagonal)) {
Fatal("InvertMSparseSymmPos",
"diagonal part 1 has rank %d != %d, matrix can not be inverted",
rankD1,iDiagonal);
rNumEl=-1;
}
Int_t nD2=iBlock-iDiagonal;
TMatrixDSparse *D2inv=0;
if((rNumEl>=0)&&(nD2>0)) {
Double_t *D2inv_data=new Double_t[nD2];
Int_t *D2inv_col=new Int_t[nD2];
Int_t *D2inv_row=new Int_t[nD2];
Int_t D2invNumEl=0;
for(Int_t i=0;i<nD2;++i) {
Int_t iA=swap[i+iDiagonal];
if(aII(iA)>0.0) {
D2inv_col[D2invNumEl]=i;
D2inv_row[D2invNumEl]=i;
D2inv_data[D2invNumEl]=1./aII(iA);
++D2invNumEl;
}
}
if(D2invNumEl==nD2) {
D2inv=CreateSparseMatrix(nD2,nD2,D2invNumEl,D2inv_row,D2inv_col,
D2inv_data);
} else if(!rankPtr) {
Fatal("InvertMSparseSymmPos",
"diagonal part 2 has rank %d != %d, matrix can not be inverted",
D2invNumEl,nD2);
rNumEl=-2;
}
delete [] D2inv_data;
delete [] D2inv_col;
delete [] D2inv_row;
}
Int_t nF=A->GetNrows()-iBlock;
TMatrixDSparse *Finv=0;
TMatrixDSparse *B=0;
TMatrixDSparse *minusBD2inv=0;
if((rNumEl>=0)&&(nF>0)&&((nD2==0)||D2inv)) {
Int_t nFmax=nF*nF;
Double_t epsilonF2=fEpsMatrix;
Double_t *F_data=new Double_t[nFmax];
Int_t *F_col=new Int_t[nFmax];
Int_t *F_row=new Int_t[nFmax];
Int_t FnumEl=0;
Int_t nBmax=nF*(nD2+1);
Double_t *B_data=new Double_t[nBmax];
Int_t *B_col=new Int_t[nBmax];
Int_t *B_row=new Int_t[nBmax];
Int_t BnumEl=0;
for(Int_t i=0;i<nF;i++) {
Int_t iA=swap[i+iBlock];
for(Int_t indexA=a_rows[iA];indexA<a_rows[iA+1];indexA++) {
Int_t jA=a_cols[indexA];
Int_t j0=swapBack[jA];
if(j0>=iBlock) {
Int_t j=j0-iBlock;
F_row[FnumEl]=i;
F_col[FnumEl]=j;
F_data[FnumEl]=a_data[indexA];
FnumEl++;
} else if(j0>=iDiagonal) {
Int_t j=j0-iDiagonal;
B_row[BnumEl]=i;
B_col[BnumEl]=j;
B_data[BnumEl]=a_data[indexA];
BnumEl++;
}
}
}
TMatrixDSparse *F=0;
if(FnumEl) {
#ifndef FORCE_EIGENVALUE_DECOMPOSITION
F=CreateSparseMatrix(nF,nF,FnumEl,F_row,F_col,F_data);
#endif
}
delete [] F_data;
delete [] F_col;
delete [] F_row;
if(BnumEl) {
B=CreateSparseMatrix(nF,nD2,BnumEl,B_row,B_col,B_data);
}
delete [] B_data;
delete [] B_col;
delete [] B_row;
if(B && D2inv) {
minusBD2inv=MultiplyMSparseMSparse(B,D2inv);
if(minusBD2inv) {
Int_t mbd2_nMax=minusBD2inv->GetRowIndexArray()
[minusBD2inv->GetNrows()];
Double_t *mbd2_data=minusBD2inv->GetMatrixArray();
for(Int_t i=0;i<mbd2_nMax;i++) {
mbd2_data[i] = - mbd2_data[i];
}
}
}
if(minusBD2inv && F) {
TMatrixDSparse *minusBD2invBt=
MultiplyMSparseMSparseTranspVector(minusBD2inv,B,0);
AddMSparse(F,1.,minusBD2invBt);
DeleteMatrix(&minusBD2invBt);
}
if(F) {
const Int_t *f_rows=F->GetRowIndexArray();
const Int_t *f_cols=F->GetColIndexArray();
const Double_t *f_data=F->GetMatrixArray();
TMatrixD c(nF,nF);
Int_t nErrorF=0;
for(Int_t i=0;i<nF;i++) {
for(Int_t indexF=f_rows[i];indexF<f_rows[i+1];indexF++) {
if(f_cols[indexF]>=i) c(f_cols[indexF],i)=f_data[indexF];
}
Double_t c_ii=c(i,i);
for(Int_t j=0;j<i;j++) {
Double_t c_ij=c(i,j);
c_ii -= c_ij*c_ij;
}
if(c_ii<=0.0) {
nErrorF++;
break;
}
c_ii=TMath::Sqrt(c_ii);
c(i,i)=c_ii;
for(Int_t j=i+1;j<nF;j++) {
Double_t c_ji=c(j,i);
for(Int_t k=0;k<i;k++) {
c_ji -= c(i,k)*c(j,k);
}
c(j,i) = c_ji/c_ii;
}
}
if(!nErrorF) {
Double_t dmin=c(0,0);
Double_t dmax=dmin;
for(Int_t i=1;i<nF;i++) {
dmin=TMath::Min(dmin,c(i,i));
dmax=TMath::Max(dmax,c(i,i));
}
#ifdef DEBUG
std::cout<<"dmin,dmax: "<<dmin<<" "<<dmax<<"\n";
#endif
if(dmin/dmax<epsilonF2*nF) nErrorF=2;
}
if(!nErrorF) {
TMatrixD cinv(nF,nF);
for(Int_t i=0;i<nF;i++) {
cinv(i,i)=1./c(i,i);
}
for(Int_t i=0;i<nF;i++) {
for(Int_t j=i+1;j<nF;j++) {
Double_t tmp=-c(j,i)*cinv(i,i);
for(Int_t k=i+1;k<j;k++) {
tmp -= cinv(k,i)*c(j,k);
}
cinv(j,i)=tmp*cinv(j,j);
}
}
TMatrixDSparse cInvSparse(cinv);
Finv=MultiplyMSparseTranspMSparse
(&cInvSparse,&cInvSparse);
}
DeleteMatrix(&F);
}
}
Int_t rankD2Block=0;
if(rNumEl>=0) {
if( ((nD2==0)||D2inv) && ((nF==0)||Finv) ) {
TMatrixDSparse *G=0;
if(Finv && minusBD2inv) {
G=MultiplyMSparseMSparse(Finv,minusBD2inv);
}
TMatrixDSparse *E=0;
if(D2inv) E=new TMatrixDSparse(*D2inv);
if(G && minusBD2inv) {
TMatrixDSparse *minusBD2invTransG=
MultiplyMSparseTranspMSparse(minusBD2inv,G);
if(E) {
AddMSparse(E,1.,minusBD2invTransG);
DeleteMatrix(&minusBD2invTransG);
} else {
E=minusBD2invTransG;
}
}
if(E) {
const Int_t *e_rows=E->GetRowIndexArray();
const Int_t *e_cols=E->GetColIndexArray();
const Double_t *e_data=E->GetMatrixArray();
for(Int_t iE=0;iE<E->GetNrows();iE++) {
Int_t iA=swap[iE+iDiagonal];
for(Int_t indexE=e_rows[iE];indexE<e_rows[iE+1];++indexE) {
Int_t jE=e_cols[indexE];
Int_t jA=swap[jE+iDiagonal];
rEl_col[rNumEl]=iA;
rEl_row[rNumEl]=jA;
rEl_data[rNumEl]=e_data[indexE];
++rNumEl;
}
}
DeleteMatrix(&E);
}
if(G) {
const Int_t *g_rows=G->GetRowIndexArray();
const Int_t *g_cols=G->GetColIndexArray();
const Double_t *g_data=G->GetMatrixArray();
for(Int_t iG=0;iG<G->GetNrows();iG++) {
Int_t iA=swap[iG+iBlock];
for(Int_t indexG=g_rows[iG];indexG<g_rows[iG+1];++indexG) {
Int_t jG=g_cols[indexG];
Int_t jA=swap[jG+iDiagonal];
rEl_col[rNumEl]=iA;
rEl_row[rNumEl]=jA;
rEl_data[rNumEl]=g_data[indexG];
++rNumEl;
rEl_col[rNumEl]=jA;
rEl_row[rNumEl]=iA;
rEl_data[rNumEl]=g_data[indexG];
++rNumEl;
}
}
DeleteMatrix(&G);
}
if(Finv) {
const Int_t *finv_rows=Finv->GetRowIndexArray();
const Int_t *finv_cols=Finv->GetColIndexArray();
const Double_t *finv_data=Finv->GetMatrixArray();
for(Int_t iF=0;iF<Finv->GetNrows();iF++) {
Int_t iA=swap[iF+iBlock];
for(Int_t indexF=finv_rows[iF];indexF<finv_rows[iF+1];++indexF) {
Int_t jF=finv_cols[indexF];
Int_t jA=swap[jF+iBlock];
rEl_col[rNumEl]=iA;
rEl_row[rNumEl]=jA;
rEl_data[rNumEl]=finv_data[indexF];
++rNumEl;
}
}
}
rankD2Block=nD2+nF;
} else if(!rankPtr) {
rNumEl=-3;
Fatal("InvertMSparseSymmPos",
"non-trivial part has rank < %d, matrix can not be inverted",
nF);
} else {
Int_t nEV=nD2+nF;
Double_t epsilonEV2=fEpsMatrix ;
Info("InvertMSparseSymmPos",
"cholesky-decomposition failed, try eigenvalue analysis");
#ifdef DEBUG
std::cout<<"nEV="<<nEV<<" iDiagonal="<<iDiagonal<<"\n";
#endif
TMatrixDSym EV(nEV);
for(Int_t i=0;i<nEV;i++) {
Int_t iA=swap[i+iDiagonal];
for(Int_t indexA=a_rows[iA];indexA<a_rows[iA+1];indexA++) {
Int_t jA=a_cols[indexA];
Int_t j0=swapBack[jA];
if(j0>=iDiagonal) {
Int_t j=j0-iDiagonal;
#ifdef DEBUG
if((i<0)||(j<0)||(i>=nEV)||(j>=nEV)) {
std::cout<<" error "<<nEV<<" "<<i<<" "<<j<<"\n";
}
#endif
if(!TMath::Finite(a_data[indexA])) {
Fatal("InvertMSparseSymmPos",
"non-finite number detected element %d %d\n",
iA,jA);
}
EV(i,j)=a_data[indexA];
}
}
}
TMatrixDSymEigen Eigen(EV);
#ifdef DEBUG
std::cout<<"Eigenvalues\n";
#endif
Int_t errorEV=0;
Double_t condition=1.0;
if(Eigen.GetEigenValues()(0)<0.0) {
errorEV=1;
} else if(Eigen.GetEigenValues()(0)>0.0) {
condition=Eigen.GetEigenValues()(nEV-1)/Eigen.GetEigenValues()(0);
}
if(condition<-epsilonEV2) {
errorEV=2;
}
if(errorEV) {
if(errorEV==1) {
Error("InvertMSparseSymmPos",
"Largest Eigenvalue is negative %f",
Eigen.GetEigenValues()(0));
} else {
Error("InvertMSparseSymmPos",
"Some Eigenvalues are negative (EV%d/EV0=%g epsilon=%g)",
nEV-1,
Eigen.GetEigenValues()(nEV-1)/Eigen.GetEigenValues()(0),
epsilonEV2);
}
}
rankD2Block=0;
Double_t setToZero=epsilonEV2*Eigen.GetEigenValues()(0);
TMatrixD inverseEV(nEV,1);
for(Int_t i=0;i<nEV;i++) {
Double_t x=Eigen.GetEigenValues()(i);
if(x>setToZero) {
inverseEV(i,0)=1./x;
++rankD2Block;
}
}
TMatrixDSparse V(Eigen.GetEigenVectors());
TMatrixDSparse *VDVt=MultiplyMSparseMSparseTranspVector
(&V,&V,&inverseEV);
const Int_t *vdvt_rows=VDVt->GetRowIndexArray();
const Int_t *vdvt_cols=VDVt->GetColIndexArray();
const Double_t *vdvt_data=VDVt->GetMatrixArray();
for(Int_t iVDVt=0;iVDVt<VDVt->GetNrows();iVDVt++) {
Int_t iA=swap[iVDVt+iDiagonal];
for(Int_t indexVDVt=vdvt_rows[iVDVt];
indexVDVt<vdvt_rows[iVDVt+1];++indexVDVt) {
Int_t jVDVt=vdvt_cols[indexVDVt];
Int_t jA=swap[jVDVt+iDiagonal];
rEl_col[rNumEl]=iA;
rEl_row[rNumEl]=jA;
rEl_data[rNumEl]=vdvt_data[indexVDVt];
++rNumEl;
}
}
DeleteMatrix(&VDVt);
}
}
if(rankPtr) {
*rankPtr=rankD1+rankD2Block;
}
DeleteMatrix(&D2inv);
DeleteMatrix(&Finv);
DeleteMatrix(&B);
DeleteMatrix(&minusBD2inv);
delete [] swap;
delete [] swapBack;
delete [] isZero;
TMatrixDSparse *r=(rNumEl>=0) ?
CreateSparseMatrix(A->GetNrows(),A->GetNrows(),rNumEl,
rEl_row,rEl_col,rEl_data) : 0;
delete [] rEl_data;
delete [] rEl_col;
delete [] rEl_row;
#ifdef DEBUG_DETAIL
if(r) {
TMatrixDSparse *Ar=MultiplyMSparseMSparse(A,r);
TMatrixDSparse *ArA=MultiplyMSparseMSparse(Ar,A);
TMatrixDSparse *rAr=MultiplyMSparseMSparse(r,Ar);
TMatrixD ar(*Ar);
TMatrixD a(*A);
TMatrixD ara(*ArA);
TMatrixD R(*r);
TMatrixD rar(*rAr);
DeleteMatrix(&Ar);
DeleteMatrix(&ArA);
DeleteMatrix(&rAr);
Double_t epsilonA2=fEpsMatrix ;
for(Int_t i=0;i<a.GetNrows();i++) {
for(Int_t j=0;j<a.GetNcols();j++) {
if(TMath::Abs(ar(i,j)-ar(j,i))>
epsilonA2*(TMath::Abs(ar(i,j))+TMath::Abs(ar(j,i)))) {
std::cout<<"Ar is not symmetric Ar("<<i<<","<<j<<")="<<ar(i,j)
<<" Ar("<<j<<","<<i<<")="<<ar(j,i)<<"\n";
}
if(TMath::Abs(ara(i,j)-a(i,j))>
epsilonA2*(TMath::Abs(ara(i,j))+TMath::Abs(a(i,j)))) {
std::cout<<"ArA is not equal A ArA("<<i<<","<<j<<")="<<ara(i,j)
<<" A("<<i<<","<<j<<")="<<a(i,j)<<"\n";
}
if(TMath::Abs(rar(i,j)-R(i,j))>
epsilonA2*(TMath::Abs(rar(i,j))+TMath::Abs(R(i,j)))) {
std::cout<<"rAr is not equal r rAr("<<i<<","<<j<<")="<<rar(i,j)
<<" r("<<i<<","<<j<<")="<<R(i,j)<<"\n";
}
}
}
if(rankPtr) std::cout<<"rank="<<*rankPtr<<"\n";
} else {
std::cout<<"Matrix is not positive\n";
}
#endif
return r;
}
TString TUnfold::GetOutputBinName(Int_t iBinX) const
{
return TString::Format("#%d",iBinX);
}
TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
EConstraint constraint)
{
InitTUnfold();
SetConstraint(constraint);
Int_t nx0, nx, ny;
if (histmap == kHistMapOutputHoriz) {
nx0 = hist_A->GetNbinsX()+2;
ny = hist_A->GetNbinsY();
} else {
nx0 = hist_A->GetNbinsY()+2;
ny = hist_A->GetNbinsX();
}
nx = 0;
fSumOverY.Set(nx0);
fXToHist.Set(nx0);
fHistToX.Set(nx0);
Int_t nonzeroA=0;
Int_t nskipped=0;
for (Int_t ix = 0; ix < nx0; ix++) {
Double_t sum = 0.0;
Int_t nonZeroY = 0;
for (Int_t iy = 0; iy < ny; iy++) {
Double_t z;
if (histmap == kHistMapOutputHoriz) {
z = hist_A->GetBinContent(ix, iy + 1);
} else {
z = hist_A->GetBinContent(iy + 1, ix);
}
if (z != 0.0) {
nonzeroA++;
nonZeroY++;
sum += z;
}
}
if (nonZeroY) {
fXToHist[nx] = ix;
fHistToX[ix] = nx;
fSumOverY[nx] = sum;
if (histmap == kHistMapOutputHoriz) {
fSumOverY[nx] +=
hist_A->GetBinContent(ix, 0) +
hist_A->GetBinContent(ix, ny + 1);
} else {
fSumOverY[nx] +=
hist_A->GetBinContent(0, ix) +
hist_A->GetBinContent(ny + 1, ix);
}
nx++;
} else {
nskipped++;
fHistToX[ix] = -1;
}
}
Int_t underflowBin=0,overflowBin=0;
for (Int_t ix = 0; ix < nx; ix++) {
Int_t ibinx = fXToHist[ix];
if(ibinx<1) underflowBin=1;
if (histmap == kHistMapOutputHoriz) {
if(ibinx>hist_A->GetNbinsX()) overflowBin=1;
} else {
if(ibinx>hist_A->GetNbinsY()) overflowBin=1;
}
}
if(nskipped) {
Int_t nprint=0;
Int_t ixfirst=-1,ixlast=-1;
TString binlist;
int nDisconnected=0;
for (Int_t ix = 0; ix < nx0; ix++) {
if(fHistToX[ix]<0) {
nprint++;
if(ixlast<0) {
binlist +=" ";
binlist +=ix;
ixfirst=ix;
}
ixlast=ix;
nDisconnected++;
}
if(((fHistToX[ix]>=0)&&(ixlast>=0))||
(nprint==nskipped)) {
if(ixlast>ixfirst) {
binlist += "-";
binlist += ixlast;
}
ixfirst=-1;
ixlast=-1;
}
if(nprint==nskipped) {
break;
}
}
if(nskipped==(2-underflowBin-overflowBin)) {
Info("TUnfold","underflow and overflow bin "
"do not depend on the input data");
} else {
Warning("TUnfold","%d output bins "
"do not depend on the input data %s",nDisconnected,
static_cast<const char *>(binlist));
}
}
fX0 = new TMatrixD(nx, 1, fSumOverY.GetArray());
Int_t *rowA = new Int_t[nonzeroA];
Int_t *colA = new Int_t[nonzeroA];
Double_t *dataA = new Double_t[nonzeroA];
Int_t index=0;
for (Int_t iy = 0; iy < ny; iy++) {
for (Int_t ix = 0; ix < nx; ix++) {
Int_t ibinx = fXToHist[ix];
Double_t z;
if (histmap == kHistMapOutputHoriz) {
z = hist_A->GetBinContent(ibinx, iy + 1);
} else {
z = hist_A->GetBinContent(iy + 1, ibinx);
}
if (z != 0.0) {
rowA[index]=iy;
colA[index] = ix;
dataA[index] = z / fSumOverY[ix];
index++;
}
}
}
if(underflowBin && overflowBin) {
Info("TUnfold","%d input bins and %d output bins (includes 2 underflow/overflow bins)",ny,nx);
} else if(underflowBin) {
Info("TUnfold","%d input bins and %d output bins (includes 1 underflow bin)",ny,nx);
} else if(overflowBin) {
Info("TUnfold","%d input bins and %d output bins (includes 1 overflow bin)",ny,nx);
} else {
Info("TUnfold","%d input bins and %d output bins",ny,nx);
}
fA = CreateSparseMatrix(ny,nx,index,rowA,colA,dataA);
if(ny<nx) {
Error("TUnfold","too few (ny=%d) input bins for nx=%d output bins",ny,nx);
} else if(ny==nx) {
Warning("TUnfold","too few (ny=%d) input bins for nx=%d output bins",ny,nx);
}
delete[] rowA;
delete[] colA;
delete[] dataA;
fL = new TMatrixDSparse(1, GetNx());
if (regmode != kRegModeNone) {
Int_t nError=RegularizeBins(0, 1, nx0, regmode);
if(nError>0) {
if(nError>1) {
Info("TUnfold",
"%d regularisation conditions have been skipped",nError);
} else {
Info("TUnfold",
"One regularisation condition has been skipped");
}
}
}
}
TUnfold::~TUnfold(void)
{
DeleteMatrix(&fA);
DeleteMatrix(&fL);
DeleteMatrix(&fVyy);
DeleteMatrix(&fY);
DeleteMatrix(&fX0);
ClearResults();
}
void TUnfold::SetBias(const TH1 *bias)
{
DeleteMatrix(&fX0);
fX0 = new TMatrixD(GetNx(), 1);
for (Int_t i = 0; i < GetNx(); i++) {
(*fX0) (i, 0) = bias->GetBinContent(fXToHist[i]);
}
}
Bool_t TUnfold::AddRegularisationCondition
(Int_t i0,Double_t f0,Int_t i1,Double_t f1,Int_t i2,Double_t f2)
{
Int_t indices[3];
Double_t data[3];
Int_t nEle=0;
if(i2>=0) {
data[nEle]=f2;
indices[nEle]=i2;
nEle++;
}
if(i1>=0) {
data[nEle]=f1;
indices[nEle]=i1;
nEle++;
}
if(i0>=0) {
data[nEle]=f0;
indices[nEle]=i0;
nEle++;
}
return AddRegularisationCondition(nEle,indices,data);
}
Bool_t TUnfold::AddRegularisationCondition
(Int_t nEle,const Int_t *indices,const Double_t *rowData)
{
Bool_t r=kTRUE;
const Int_t *l0_rows=fL->GetRowIndexArray();
const Int_t *l0_cols=fL->GetColIndexArray();
const Double_t *l0_data=fL->GetMatrixArray();
Int_t nF=l0_rows[fL->GetNrows()]+nEle;
Int_t *l_row=new Int_t[nF];
Int_t *l_col=new Int_t[nF];
Double_t *l_data=new Double_t[nF];
nF=0;
for(Int_t row=0;row<fL->GetNrows();row++) {
for(Int_t k=l0_rows[row];k<l0_rows[row+1];k++) {
l_row[nF]=row;
l_col[nF]=l0_cols[k];
l_data[nF]=l0_data[k];
nF++;
}
}
Int_t rowMax=0;
if(nF>0) {
rowMax=fL->GetNrows();
}
for(Int_t i=0;i<nEle;i++) {
Int_t col=fHistToX[indices[i]];
if(col<0) {
r=kFALSE;
break;
}
l_row[nF]=rowMax;
l_col[nF]=col;
l_data[nF]=rowData[i];
nF++;
}
if(r) {
DeleteMatrix(&fL);
fL=CreateSparseMatrix(rowMax+1,GetNx(),nF,l_row,l_col,l_data);
}
delete [] l_row;
delete [] l_col;
delete [] l_data;
return r;
}
Int_t TUnfold::RegularizeSize(int bin, Double_t scale)
{
if(fRegMode==kRegModeNone) fRegMode=kRegModeSize;
if(fRegMode!=kRegModeSize) fRegMode=kRegModeMixed;
return AddRegularisationCondition(bin,scale) ? 0 : 1;
}
Int_t TUnfold::RegularizeDerivative(int left_bin, int right_bin,
Double_t scale)
{
if(fRegMode==kRegModeNone) fRegMode=kRegModeDerivative;
if(fRegMode!=kRegModeDerivative) fRegMode=kRegModeMixed;
return AddRegularisationCondition(left_bin,-scale,right_bin,scale) ? 0 : 1;
}
Int_t TUnfold::RegularizeCurvature(int left_bin, int center_bin,
int right_bin,
Double_t scale_left,
Double_t scale_right)
{
if(fRegMode==kRegModeNone) fRegMode=kRegModeCurvature;
if(fRegMode!=kRegModeCurvature) fRegMode=kRegModeMixed;
return AddRegularisationCondition
(left_bin,-scale_left,
center_bin,scale_left+scale_right,
right_bin,-scale_right)
? 0 : 1;
}
Int_t TUnfold::RegularizeBins(int start, int step, int nbin,
ERegMode regmode)
{
Int_t i0, i1, i2;
i0 = start;
i1 = i0 + step;
i2 = i1 + step;
Int_t nSkip = 0;
Int_t nError= 0;
if (regmode == kRegModeDerivative) {
nSkip = 1;
} else if (regmode == kRegModeCurvature) {
nSkip = 2;
} else if(regmode != kRegModeSize) {
Error("RegularizeBins","regmode = %d is not valid",regmode);
}
for (Int_t i = nSkip; i < nbin; i++) {
if (regmode == kRegModeSize) {
nError += RegularizeSize(i0);
} else if (regmode == kRegModeDerivative) {
nError += RegularizeDerivative(i0, i1);
} else if (regmode == kRegModeCurvature) {
nError += RegularizeCurvature(i0, i1, i2);
}
i0 = i1;
i1 = i2;
i2 += step;
}
return nError;
}
Int_t TUnfold::RegularizeBins2D(int start_bin, int step1, int nbin1,
int step2, int nbin2, ERegMode regmode)
{
Int_t nError = 0;
for (Int_t i1 = 0; i1 < nbin1; i1++) {
nError += RegularizeBins(start_bin + step1 * i1, step2, nbin2, regmode);
}
for (Int_t i2 = 0; i2 < nbin2; i2++) {
nError += RegularizeBins(start_bin + step2 * i2, step1, nbin1, regmode);
}
return nError;
}
Double_t TUnfold::DoUnfold(Double_t tau_reg,const TH1 *input,
Double_t scaleBias)
{
SetInput(input,scaleBias);
return DoUnfold(tau_reg);
}
Int_t TUnfold::SetInput(const TH1 *input, Double_t scaleBias,
Double_t oneOverZeroError,const TH2 *hist_vyy,
const TH2 *hist_vyy_inv)
{
DeleteMatrix(&fVyyInv);
fNdf=0;
fBiasScale = scaleBias;
ClearResults();
Int_t *rowVyyN=new Int_t[GetNy()*GetNy()+1];
Int_t *colVyyN=new Int_t[GetNy()*GetNy()+1];
Double_t *dataVyyN=new Double_t[GetNy()*GetNy()+1];
Int_t *rowVyy1=new Int_t[GetNy()];
Int_t *colVyy1=new Int_t[GetNy()];
Double_t *dataVyy1=new Double_t[GetNy()];
Double_t *dataVyyDiag=new Double_t[GetNy()];
Int_t nError=0;
Int_t nVyyN=0;
Int_t nVyy1=0;
for (Int_t iy = 0; iy < GetNy(); iy++) {
Double_t dy2;
if(!hist_vyy) {
Double_t dy = input->GetBinError(iy + 1);
dy2=dy*dy;
if (dy2 <= 0.0) {
nError++;
if(oneOverZeroError>0.0) {
dy2 = 1./ ( oneOverZeroError*oneOverZeroError);
}
}
} else {
dy2 = hist_vyy->GetBinContent(iy+1,iy+1);
}
rowVyyN[nVyyN] = iy;
colVyyN[nVyyN] = iy;
rowVyy1[nVyy1] = iy;
colVyy1[nVyy1] = 0;
dataVyyDiag[iy] = dy2;
if(dy2>0.0) {
dataVyyN[nVyyN++] = dy2;
dataVyy1[nVyy1++] = dy2;
}
}
if(hist_vyy) {
for (Int_t iy = 0; iy < GetNy(); iy++) {
if(dataVyyDiag[iy]<=0.0) continue;
for (Int_t jy = 0; jy < GetNy(); jy++) {
if(iy==jy) continue;
if(dataVyyDiag[jy]<=0.0) continue;
rowVyyN[nVyyN] = iy;
colVyyN[nVyyN] = jy;
dataVyyN[nVyyN]= hist_vyy->GetBinContent(iy+1,jy+1);
if(dataVyyN[nVyyN] == 0.0) continue;
nVyyN ++;
}
}
if(hist_vyy_inv) {
Warning("SetInput",
"inverse of input covariance is taken from user input");
Int_t *rowVyyInv=new Int_t[GetNy()*GetNy()+1];
Int_t *colVyyInv=new Int_t[GetNy()*GetNy()+1];
Double_t *dataVyyInv=new Double_t[GetNy()*GetNy()+1];
Int_t nVyyInv=0;
for (Int_t iy = 0; iy < GetNy(); iy++) {
for (Int_t jy = 0; jy < GetNy(); jy++) {
rowVyyInv[nVyyInv] = iy;
colVyyInv[nVyyInv] = jy;
dataVyyInv[nVyyInv]= hist_vyy_inv->GetBinContent(iy+1,jy+1);
if(dataVyyInv[nVyyInv] == 0.0) continue;
nVyyInv ++;
}
}
fVyyInv=CreateSparseMatrix
(GetNy(),GetNy(),nVyyInv,rowVyyInv,colVyyInv,dataVyyInv);
delete [] rowVyyInv;
delete [] colVyyInv;
delete [] dataVyyInv;
}
}
DeleteMatrix(&fVyy);
fVyy = CreateSparseMatrix
(GetNy(),GetNy(),nVyyN,rowVyyN,colVyyN,dataVyyN);
delete[] rowVyyN;
delete[] colVyyN;
delete[] dataVyyN;
TMatrixDSparse *vecV=CreateSparseMatrix
(GetNy(),1,nVyy1,rowVyy1,colVyy1, dataVyy1);
delete[] rowVyy1;
delete[] colVyy1;
delete[] dataVyy1;
DeleteMatrix(&fY);
fY = new TMatrixD(GetNy(), 1);
for (Int_t i = 0; i < GetNy(); i++) {
(*fY) (i, 0) = input->GetBinContent(i + 1);
}
TMatrixDSparse *mAtV=MultiplyMSparseTranspMSparse(fA,vecV);
DeleteMatrix(&vecV);
Int_t nError2=0;
for (Int_t i = 0; i <mAtV->GetNrows();i++) {
if(mAtV->GetRowIndexArray()[i]==
mAtV->GetRowIndexArray()[i+1]) {
nError2 ++;
}
}
if(nError>0) {
if(oneOverZeroError !=0.0) {
if(nError>1) {
Warning("SetInput","%d/%d input bins have zero error,"
" 1/error set to %lf.",nError,GetNy(),oneOverZeroError);
} else {
Warning("SetInput","One input bin has zero error,"
" 1/error set to %lf.",oneOverZeroError);
}
} else {
if(nError>1) {
Warning("SetInput","%d/%d input bins have zero error,"
" and are ignored.",nError,GetNy());
} else {
Warning("SetInput","One input bin has zero error,"
" and is ignored.");
}
}
fIgnoredBins=nError;
}
if(nError2>0) {
if(oneOverZeroError<=0.0) {
for (Int_t col = 0; col <mAtV->GetNrows();col++) {
if(mAtV->GetRowIndexArray()[col]==
mAtV->GetRowIndexArray()[col+1]) {
TString binlist("no data to constrain output bin ");
binlist += GetOutputBinName(fXToHist[col]);
Warning("SetInput","%s",binlist.Data());
}
}
}
if(nError2>1) {
Error("SetInput","%d/%d output bins are not constrained by any data.",
nError2,mAtV->GetNrows());
} else {
Error("SetInput","One output bins is not constrained by any data.");
}
}
DeleteMatrix(&mAtV);
delete[] dataVyyDiag;
return nError+10000*nError2;
}
Double_t TUnfold::DoUnfold(Double_t tau)
{
fTauSquared=tau*tau;
return DoUnfold();
}
Int_t TUnfold::ScanLcurve(Int_t nPoint,
Double_t tauMin,Double_t tauMax,
TGraph **lCurve,TSpline **logTauX,
TSpline **logTauY)
{
typedef std::map<Double_t,std::pair<Double_t,Double_t> > XYtau_t;
XYtau_t curve;
if((tauMin<=0)||(tauMax<=0.0)||(tauMin>=tauMax)) {
DoUnfold(0.0);
if(GetNdf()<=0) {
Error("ScanLcurve","too few input bins, NDF<=0 %d",GetNdf());
}
Double_t x0=GetLcurveX();
Double_t y0=GetLcurveY();
Info("ScanLcurve","logtau=-Infinity X=%lf Y=%lf",x0,y0);
if(!TMath::Finite(x0)) {
Fatal("ScanLcurve","problem (too few input bins?) X=%f",x0);
}
if(!TMath::Finite(y0)) {
Fatal("ScanLcurve","problem (missing regularisation?) Y=%f",y0);
}
{
Double_t logTau=
0.5*(TMath::Log10(fChi2A+3.*TMath::Sqrt(GetNdf()+1.0))
-GetLcurveY());
DoUnfold(TMath::Power(10.,logTau));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
logTau,GetLcurveX(),GetLcurveY());
}
if((*curve.begin()).second.first<x0) {
do {
x0=GetLcurveX();
Double_t logTau=(*curve.begin()).first-0.5;
DoUnfold(TMath::Power(10.,logTau));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
logTau,GetLcurveX(),GetLcurveY());
}
while(((int)curve.size()<(nPoint-1)/2)&&
((*curve.begin()).second.first<x0));
} else {
while(((int)curve.size()<nPoint-1)&&
(((*curve.begin()).second.first-x0>0.00432)||
((*curve.begin()).second.second-y0>0.00432)||
(curve.size()<2))) {
Double_t logTau=(*curve.begin()).first-0.5;
DoUnfold(TMath::Power(10.,logTau));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
logTau,GetLcurveX(),GetLcurveY());
}
}
} else {
Double_t logTauMin=TMath::Log10(tauMin);
Double_t logTauMax=TMath::Log10(tauMax);
if(nPoint>1) {
DoUnfold(TMath::Power(10.,logTauMax));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
logTauMax,GetLcurveX(),GetLcurveY());
curve[logTauMax]=std::make_pair(GetLcurveX(),GetLcurveY());
}
DoUnfold(TMath::Power(10.,logTauMin));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
logTauMin,GetLcurveX(),GetLcurveY());
curve[logTauMin]=std::make_pair(GetLcurveX(),GetLcurveY());
}
while(int(curve.size())<nPoint-1) {
XYtau_t::const_iterator i0,i1;
i0=curve.begin();
i1=i0;
Double_t logTau=(*i0).first;
Double_t distMax=0.0;
for(i1++;i1!=curve.end();i1++) {
const std::pair<Double_t,Double_t> &xy0=(*i0).second;
const std::pair<Double_t,Double_t> &xy1=(*i1).second;
Double_t dx=xy1.first-xy0.first;
Double_t dy=xy1.second-xy0.second;
Double_t d=TMath::Sqrt(dx*dx+dy*dy);
if(d>=distMax) {
distMax=d;
logTau=0.5*((*i0).first+(*i1).first);
}
i0=i1;
}
DoUnfold(TMath::Power(10.,logTau));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",logTau,GetLcurveX(),GetLcurveY());
curve[logTau]=std::make_pair(GetLcurveX(),GetLcurveY());
}
XYtau_t::const_iterator i0,i1;
i0=curve.begin();
i1=i0;
i1++;
Double_t logTauFin=(*i0).first;
if( ((int)curve.size())<nPoint) {
Double_t *cTi=new Double_t[curve.size()-1];
Double_t *cCi=new Double_t[curve.size()-1];
Int_t n=0;
{
Double_t *lXi=new Double_t[curve.size()];
Double_t *lYi=new Double_t[curve.size()];
Double_t *lTi=new Double_t[curve.size()];
for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
lXi[n]=(*i).second.first;
lYi[n]=(*i).second.second;
lTi[n]=(*i).first;
n++;
}
TSpline3 *splineX=new TSpline3("x vs tau",lTi,lXi,n);
TSpline3 *splineY=new TSpline3("y vs tau",lTi,lYi,n);
for(Int_t i=0;i<n-1;i++) {
Double_t ltau,xy,bi,ci,di;
splineX->GetCoeff(i,ltau,xy,bi,ci,di);
Double_t tauBar=0.5*(lTi[i]+lTi[i+1]);
Double_t dTau=0.5*(lTi[i+1]-lTi[i]);
Double_t dx1=bi+dTau*(2.*ci+3.*di*dTau);
Double_t dx2=2.*ci+6.*di*dTau;
splineY->GetCoeff(i,ltau,xy,bi,ci,di);
Double_t dy1=bi+dTau*(2.*ci+3.*di*dTau);
Double_t dy2=2.*ci+6.*di*dTau;
cTi[i]=tauBar;
cCi[i]=(dy2*dx1-dy1*dx2)/TMath::Power(dx1*dx1+dy1*dy1,1.5);
}
delete splineX;
delete splineY;
delete[] lXi;
delete[] lYi;
delete[] lTi;
}
TSpline3 *splineC=new TSpline3("L curve curvature",cTi,cCi,n-1);
Int_t iskip=0;
if(n>4) iskip=1;
if(n>7) iskip=2;
Double_t cCmax=cCi[iskip];
Double_t cTmax=cTi[iskip];
for(Int_t i=iskip;i<n-2-iskip;i++) {
Double_t xMax=cTi[i+1];
Double_t yMax=cCi[i+1];
if(cCi[i]>yMax) {
yMax=cCi[i];
xMax=cTi[i];
}
Double_t x,y,b,c,d;
splineC->GetCoeff(i,x,y,b,c,d);
Double_t m_p_half=-c/(3.*d);
Double_t q=b/(3.*d);
Double_t discr=m_p_half*m_p_half-q;
if(discr>=0.0) {
discr=TMath::Sqrt(discr);
Double_t xx;
if(m_p_half>0.0) {
xx = m_p_half + discr;
} else {
xx = m_p_half - discr;
}
Double_t dx=cTi[i+1]-x;
if((xx>0.0)&&(xx<dx)) {
y=splineC->Eval(x+xx);
if(y>yMax) {
yMax=y;
xMax=x+xx;
}
}
if(xx !=0.0) {
xx= q/xx;
} else {
xx=0.0;
}
if((xx>0.0)&&(xx<dx)) {
y=splineC->Eval(x+xx);
if(y>yMax) {
yMax=y;
xMax=x+xx;
}
}
}
if(yMax>cCmax) {
cCmax=yMax;
cTmax=xMax;
}
}
#ifdef DEBUG_LCURVE
{
TCanvas lcc;
lcc.Divide(1,1);
lcc.cd(1);
splineC->Draw();
lcc.SaveAs("splinec.ps");
}
#endif
delete splineC;
delete[] cTi;
delete[] cCi;
logTauFin=cTmax;
DoUnfold(TMath::Power(10.,logTauFin));
if((!TMath::Finite(GetLcurveX())) ||(!TMath::Finite(GetLcurveY()))) {
Fatal("ScanLcurve","problem (missing regularisation?) X=%f Y=%f",
GetLcurveX(),GetLcurveY());
}
Info("ScanLcurve","Result logtau=%lf X=%lf Y=%lf",
logTauFin,GetLcurveX(),GetLcurveY());
curve[logTauFin]=std::make_pair(GetLcurveX(),GetLcurveY());
}
Int_t bestChoice=-1;
if(curve.size()>0) {
Double_t *x=new Double_t[curve.size()];
Double_t *y=new Double_t[curve.size()];
Double_t *logT=new Double_t[curve.size()];
int n=0;
for( XYtau_t::const_iterator i=curve.begin();i!=curve.end();i++) {
if(logTauFin==(*i).first) {
bestChoice=n;
}
x[n]=(*i).second.first;
y[n]=(*i).second.second;
logT[n]=(*i).first;
n++;
}
if(lCurve) {
(*lCurve)=new TGraph(n,x,y);
(*lCurve)->SetTitle("L curve");
}
if(logTauX) (*logTauX)=new TSpline3("log(chi**2)%log(tau)",logT,x,n);
if(logTauY) (*logTauY)=new TSpline3("log(reg.cond)%log(tau)",logT,y,n);
delete[] x;
delete[] y;
delete[] logT;
}
return bestChoice;
}
void TUnfold::GetNormalisationVector(TH1 *out,const Int_t *binMap) const
{
ClearHistogram(out);
for (Int_t i = 0; i < GetNx(); i++) {
int dest=binMap ? binMap[fXToHist[i]] : fXToHist[i];
if(dest>=0) {
out->SetBinContent(dest, fSumOverY[i] + out->GetBinContent(dest));
}
}
}
void TUnfold::GetBias(TH1 *out,const Int_t *binMap) const
{
ClearHistogram(out);
for (Int_t i = 0; i < GetNx(); i++) {
int dest=binMap ? binMap[fXToHist[i]] : fXToHist[i];
if(dest>=0) {
out->SetBinContent(dest, fBiasScale*(*fX0) (i, 0) +
out->GetBinContent(dest));
}
}
}
void TUnfold::GetFoldedOutput(TH1 *out,const Int_t *binMap) const
{
ClearHistogram(out);
TMatrixDSparse *AVxx=MultiplyMSparseMSparse(fA,fVxx);
const Int_t *rows_A=fA->GetRowIndexArray();
const Int_t *cols_A=fA->GetColIndexArray();
const Double_t *data_A=fA->GetMatrixArray();
const Int_t *rows_AVxx=AVxx->GetRowIndexArray();
const Int_t *cols_AVxx=AVxx->GetColIndexArray();
const Double_t *data_AVxx=AVxx->GetMatrixArray();
for (Int_t i = 0; i < GetNy(); i++) {
Int_t destI = binMap ? binMap[i+1] : i+1;
if(destI<0) continue;
out->SetBinContent(destI, (*fAx) (i, 0)+ out->GetBinContent(destI));
Double_t e2=0.0;
Int_t index_a=rows_A[i];
Int_t index_av=rows_AVxx[i];
while((index_a<rows_A[i+1])&&(index_av<rows_AVxx[i])) {
Int_t j_a=cols_A[index_a];
Int_t j_av=cols_AVxx[index_av];
if(j_a<j_av) {
index_a++;
} else if(j_a>j_av) {
index_av++;
} else {
e2 += data_AVxx[index_av] * data_A[index_a];
index_a++;
index_av++;
}
}
out->SetBinError(destI,TMath::Sqrt(e2));
}
DeleteMatrix(&AVxx);
}
void TUnfold::GetProbabilityMatrix(TH2 *A,EHistMap histmap) const
{
const Int_t *rows_A=fA->GetRowIndexArray();
const Int_t *cols_A=fA->GetColIndexArray();
const Double_t *data_A=fA->GetMatrixArray();
for (Int_t iy = 0; iy <fA->GetNrows(); iy++) {
for(Int_t indexA=rows_A[iy];indexA<rows_A[iy+1];indexA++) {
Int_t ix = cols_A[indexA];
Int_t ih=fXToHist[ix];
if (histmap == kHistMapOutputHoriz) {
A->SetBinContent(ih, iy,data_A[indexA]);
} else {
A->SetBinContent(iy, ih,data_A[indexA]);
}
}
}
}
void TUnfold::GetInput(TH1 *out,const Int_t *binMap) const
{
ClearHistogram(out);
const Int_t *rows_Vyy=fVyy->GetRowIndexArray();
const Int_t *cols_Vyy=fVyy->GetColIndexArray();
const Double_t *data_Vyy=fVyy->GetMatrixArray();
for (Int_t i = 0; i < GetNy(); i++) {
Int_t destI=binMap ? binMap[i] : i;
if(destI<0) continue;
out->SetBinContent(destI, (*fY) (i, 0)+out->GetBinContent(destI));
Double_t e=0.0;
for(int index=rows_Vyy[i];index<rows_Vyy[i+1];index++) {
if(cols_Vyy[index]==i) {
e=TMath::Sqrt(data_Vyy[index]);
}
}
out->SetBinError(destI, e);
}
}
void TUnfold::GetInputInverseEmatrix(TH2 *out)
{
if(!fVyyInv) {
Int_t rank=0;
fVyyInv=InvertMSparseSymmPos(fVyy,&rank);
fNdf = rank-GetNpar();
if(rank<GetNy()-fIgnoredBins) {
Warning("GetInputInverseEmatrix","input covariance matrix has rank %d expect %d",
rank,GetNy());
}
if(fNdf<0) {
Error("GetInputInverseEmatrix","number of parameters %d > %d (rank of input covariance). Problem can not be solved",GetNpar(),rank);
} else if(fNdf==0) {
Warning("GetInputInverseEmatrix","number of parameters %d = input rank %d. Problem is ill posed",GetNpar(),rank);
}
}
if(out) {
const Int_t *rows_Vyy=fVyy->GetRowIndexArray();
const Int_t *cols_Vyy=fVyy->GetColIndexArray();
const Double_t *data_Vyy=fVyy->GetMatrixArray();
for(int i=0;i<=out->GetNbinsX()+1;i++) {
for(int j=0;j<=out->GetNbinsY()+1;j++) {
out->SetBinContent(i,j,0.);
}
}
for (Int_t i = 0; i < fVyy->GetNrows(); i++) {
for(int index=rows_Vyy[i];index<rows_Vyy[i+1];index++) {
Int_t j=cols_Vyy[index];
out->SetBinContent(i+1,j+1,data_Vyy[index]);
}
}
}
}
void TUnfold::GetLsquared(TH2 *out) const
{
TMatrixDSparse *lSquared=MultiplyMSparseTranspMSparse(fL,fL);
const Int_t *rows=lSquared->GetRowIndexArray();
const Int_t *cols=lSquared->GetColIndexArray();
const Double_t *data=lSquared->GetMatrixArray();
for (Int_t i = 0; i < GetNx(); i++) {
for (Int_t cindex = rows[i]; cindex < rows[i+1]; cindex++) {
Int_t j=cols[cindex];
out->SetBinContent(fXToHist[i], fXToHist[j],data[cindex]);
}
}
DeleteMatrix(&lSquared);
}
void TUnfold::GetL(TH2 *out) const
{
const Int_t *rows=fL->GetRowIndexArray();
const Int_t *cols=fL->GetColIndexArray();
const Double_t *data=fL->GetMatrixArray();
for (Int_t row = 0; row < GetNr(); row++) {
for (Int_t cindex = rows[row]; cindex < rows[row+1]; cindex++) {
Int_t col=cols[cindex];
Int_t indexH=fXToHist[col];
out->SetBinContent(indexH,row+1,data[cindex]);
}
}
}
void TUnfold::SetConstraint(EConstraint constraint)
{
if(fConstraint !=constraint) ClearResults();
fConstraint=constraint;
Info("SetConstraint","fConstraint=%d",fConstraint);
}
Double_t TUnfold::GetTau(void) const
{
return TMath::Sqrt(fTauSquared);
}
Double_t TUnfold::GetChi2L(void) const
{
return fLXsquared*fTauSquared;
}
Int_t TUnfold::GetNpar(void) const
{
return GetNx();
}
Double_t TUnfold::GetLcurveX(void) const
{
return TMath::Log10(fChi2A);
}
Double_t TUnfold::GetLcurveY(void) const
{
return TMath::Log10(fLXsquared);
}
void TUnfold::GetOutput(TH1 *output,const Int_t *binMap) const
{
ClearHistogram(output);
std::map<Int_t,Double_t> e2;
const Int_t *rows_Vxx=fVxx->GetRowIndexArray();
const Int_t *cols_Vxx=fVxx->GetColIndexArray();
const Double_t *data_Vxx=fVxx->GetMatrixArray();
Int_t binMapSize = fHistToX.GetSize();
for(Int_t i=0;i<binMapSize;i++) {
Int_t destBinI=binMap ? binMap[i] : i;
Int_t srcBinI=fHistToX[i];
if((destBinI>=0)&&(srcBinI>=0)) {
output->SetBinContent
(destBinI, (*fX)(srcBinI,0)+ output->GetBinContent(destBinI));
Int_t j=0;
Int_t index_vxx=rows_Vxx[srcBinI];
while((j<binMapSize)&&(index_vxx<rows_Vxx[srcBinI+1])) {
Int_t destBinJ=binMap ? binMap[j] : j;
if(destBinI!=destBinJ) {
j++;
} else {
Int_t srcBinJ=fHistToX[j];
if(srcBinJ<0) {
j++;
} else {
if(cols_Vxx[index_vxx]<srcBinJ) {
index_vxx++;
} else if(cols_Vxx[index_vxx]>srcBinJ) {
j++;
} else {
e2[destBinI] += data_Vxx[index_vxx];
j++;
index_vxx++;
}
}
}
}
}
}
for(std::map<Int_t,Double_t>::const_iterator i=e2.begin();
i!=e2.end();i++) {
output->SetBinError((*i).first,TMath::Sqrt((*i).second));
}
}
void TUnfold::ErrorMatrixToHist(TH2 *ematrix,const TMatrixDSparse *emat,
const Int_t *binMap,Bool_t doClear) const
{
Int_t nbin=ematrix->GetNbinsX();
if(doClear) {
for(Int_t i=0;i<nbin+2;i++) {
for(Int_t j=0;j<nbin+2;j++) {
ematrix->SetBinContent(i,j,0.0);
ematrix->SetBinError(i,j,0.0);
}
}
}
if(emat) {
const Int_t *rows_emat=emat->GetRowIndexArray();
const Int_t *cols_emat=emat->GetColIndexArray();
const Double_t *data_emat=emat->GetMatrixArray();
Int_t binMapSize = fHistToX.GetSize();
for(Int_t i=0;i<binMapSize;i++) {
Int_t destBinI=binMap ? binMap[i] : i;
Int_t srcBinI=fHistToX[i];
if((destBinI>=0)&&(destBinI<nbin+2)&&(srcBinI>=0)) {
Int_t j=0;
Int_t index_vxx=rows_emat[srcBinI];
while((j<binMapSize)&&(index_vxx<rows_emat[srcBinI+1])) {
Int_t destBinJ=binMap ? binMap[j] : j;
Int_t srcBinJ=fHistToX[j];
if((destBinJ<0)||(destBinJ>=nbin+2)||(srcBinJ<0)) {
j++;
} else {
if(cols_emat[index_vxx]<srcBinJ) {
index_vxx++;
} else if(cols_emat[index_vxx]>srcBinJ) {
j++;
} else {
Double_t e2= ematrix->GetBinContent(destBinI,destBinJ)
+ data_emat[index_vxx];
ematrix->SetBinContent(destBinI,destBinJ,e2);
j++;
index_vxx++;
}
}
}
}
}
}
}
void TUnfold::GetEmatrix(TH2 *ematrix,const Int_t *binMap) const
{
ErrorMatrixToHist(ematrix,fVxx,binMap,kTRUE);
}
void TUnfold::GetRhoIJ(TH2 *rhoij,const Int_t *binMap) const
{
GetEmatrix(rhoij,binMap);
Int_t nbin=rhoij->GetNbinsX();
Double_t *e=new Double_t[nbin+2];
for(Int_t i=0;i<nbin+2;i++) {
e[i]=TMath::Sqrt(rhoij->GetBinContent(i,i));
}
for(Int_t i=0;i<nbin+2;i++) {
for(Int_t j=0;j<nbin+2;j++) {
if((e[i]>0.0)&&(e[j]>0.0)) {
rhoij->SetBinContent(i,j,rhoij->GetBinContent(i,j)/e[i]/e[j]);
} else {
rhoij->SetBinContent(i,j,0.0);
}
}
}
delete[] e;
}
Double_t TUnfold::GetRhoI(TH1 *rhoi,const Int_t *binMap,TH2 *invEmat) const
{
ClearHistogram(rhoi,-1.);
if(binMap) {
return GetRhoIFromMatrix(rhoi,fVxx,binMap,invEmat);
} else {
Double_t rhoMax=0.0;
const Int_t *rows_Vxx=fVxx->GetRowIndexArray();
const Int_t *cols_Vxx=fVxx->GetColIndexArray();
const Double_t *data_Vxx=fVxx->GetMatrixArray();
const Int_t *rows_VxxInv=fVxxInv->GetRowIndexArray();
const Int_t *cols_VxxInv=fVxxInv->GetColIndexArray();
const Double_t *data_VxxInv=fVxxInv->GetMatrixArray();
for(Int_t i=0;i<GetNx();i++) {
Int_t destI=fXToHist[i];
Double_t e_ii=0.0,einv_ii=0.0;
for(int index_vxx=rows_Vxx[i];index_vxx<rows_Vxx[i+1];index_vxx++) {
if(cols_Vxx[index_vxx]==i) {
e_ii=data_Vxx[index_vxx];
break;
}
}
for(int index_vxxinv=rows_VxxInv[i];index_vxxinv<rows_VxxInv[i+1];
index_vxxinv++) {
if(cols_VxxInv[index_vxxinv]==i) {
einv_ii=data_VxxInv[index_vxxinv];
break;
}
}
Double_t rho=1.0;
if((einv_ii>0.0)&&(e_ii>0.0)) rho=1.-1./(einv_ii*e_ii);
if(rho>=0.0) rho=TMath::Sqrt(rho);
else rho=-TMath::Sqrt(-rho);
if(rho>rhoMax) {
rhoMax = rho;
}
rhoi->SetBinContent(destI,rho);
}
return rhoMax;
}
}
Double_t TUnfold::GetRhoIFromMatrix(TH1 *rhoi,const TMatrixDSparse *eOrig,
const Int_t *binMap,TH2 *invEmat) const
{
Double_t rhoMax=0.;
Int_t binMapSize = fHistToX.GetSize();
std::map<int,int> histToLocalBin;
Int_t nBin=0;
for(Int_t i=0;i<binMapSize;i++) {
Int_t mapped_i=binMap ? binMap[i] : i;
if(mapped_i>=0) {
if(histToLocalBin.find(mapped_i)==histToLocalBin.end()) {
histToLocalBin[mapped_i]=nBin;
nBin++;
}
}
}
if(nBin>0) {
Int_t *localBinToHist=new Int_t[nBin];
for(std::map<int,int>::const_iterator i=histToLocalBin.begin();
i!=histToLocalBin.end();i++) {
localBinToHist[(*i).second]=(*i).first;
}
const Int_t *rows_eOrig=eOrig->GetRowIndexArray();
const Int_t *cols_eOrig=eOrig->GetColIndexArray();
const Double_t *data_eOrig=eOrig->GetMatrixArray();
TMatrixD eRemap(nBin,nBin);
for(Int_t i=0;i<GetNx();i++) {
Int_t origI=fXToHist[i];
Int_t destI=binMap ? binMap[origI] : origI;
if(destI<0) continue;
Int_t ematBinI=histToLocalBin[destI];
for(int index_eOrig=rows_eOrig[i];index_eOrig<rows_eOrig[i+1];
index_eOrig++) {
Int_t j=cols_eOrig[index_eOrig];
Int_t origJ=fXToHist[j];
Int_t destJ=binMap ? binMap[origJ] : origJ;
if(destJ<0) continue;
Int_t ematBinJ=histToLocalBin[destJ];
eRemap(ematBinI,ematBinJ) += data_eOrig[index_eOrig];
}
}
TMatrixDSparse eSparse(eRemap);
Int_t rank=0;
TMatrixDSparse *einvSparse=InvertMSparseSymmPos(&eSparse,&rank);
if(rank!=einvSparse->GetNrows()) {
Warning("GetRhoIFormMatrix","Covariance matrix has rank %d expect %d",
rank,einvSparse->GetNrows());
}
const Int_t *rows_eInv=einvSparse->GetRowIndexArray();
const Int_t *cols_eInv=einvSparse->GetColIndexArray();
const Double_t *data_eInv=einvSparse->GetMatrixArray();
for(Int_t i=0;i<einvSparse->GetNrows();i++) {
Double_t e_ii=eRemap(i,i);
Double_t einv_ii=0.0;
for(Int_t index_einv=rows_eInv[i];index_einv<rows_eInv[i+1];
index_einv++) {
Int_t j=cols_eInv[index_einv];
if(j==i) {
einv_ii=data_eInv[index_einv];
}
if(invEmat) {
invEmat->SetBinContent(localBinToHist[i],localBinToHist[j],
data_eInv[index_einv]);
}
}
Double_t rho=1.0;
if((einv_ii>0.0)&&(e_ii>0.0)) rho=1.-1./(einv_ii*e_ii);
if(rho>=0.0) rho=TMath::Sqrt(rho);
else rho=-TMath::Sqrt(-rho);
if(rho>rhoMax) {
rhoMax = rho;
}
rhoi->SetBinContent(localBinToHist[i],rho);
}
DeleteMatrix(&einvSparse);
delete [] localBinToHist;
}
return rhoMax;
}
void TUnfold::ClearHistogram(TH1 *h,Double_t x) const
{
Int_t nxyz[3];
nxyz[0]=h->GetNbinsX()+1;
nxyz[1]=h->GetNbinsY()+1;
nxyz[2]=h->GetNbinsZ()+1;
for(int i=h->GetDimension();i<3;i++) nxyz[i]=0;
Int_t ixyz[3];
for(int i=0;i<3;i++) ixyz[i]=0;
while((ixyz[0]<=nxyz[0])&&
(ixyz[1]<=nxyz[1])&&
(ixyz[2]<=nxyz[2])){
Int_t ibin=h->GetBin(ixyz[0],ixyz[1],ixyz[2]);
h->SetBinContent(ibin,x);
h->SetBinError(ibin,0.0);
for(Int_t i=0;i<3;i++) {
ixyz[i] += 1;
if(ixyz[i]<=nxyz[i]) break;
if(i<2) ixyz[i]=0;
}
}
}
void TUnfold::SetEpsMatrix(Double_t eps) {
if((eps>0.0)&&(eps<1.0)) fEpsMatrix=eps;
}