#include <iostream>
#include <TMatrixD.h>
#include <TMatrixDSparse.h>
#include <TMatrixDSym.h>
#include <TMath.h>
#include <TDecompBK.h>
#include <TUnfold.h>
#include <map>
#include <vector>
#define SCHUR_COMPLEMENT_MATRIX_INVERSION
#define INVERT_WITH_CONDITIONING
#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;
fLsquared = 0;
fVyy = 0;
fY = 0;
fX0 = 0;
fTauSquared = 0.0;
fBiasScale = 0.0;
fNdf = 0;
fConstraint = kEConstraintNone;
fRegMode = kRegModeNone;
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;
}
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();
Int_t ny=fVyy->GetNrows();
const Int_t *vyy_rows=fVyy->GetRowIndexArray();
const Int_t *vyy_cols=fVyy->GetColIndexArray();
const Double_t *vyy_data=fVyy->GetMatrixArray();
Int_t *usedBin=new Int_t[ny];
for(Int_t i=0;i<ny;i++) {
usedBin[i]=0;
}
for(Int_t i=0;i<ny;i++) {
for(Int_t k=vyy_rows[i];k<vyy_rows[i+1];k++) {
if(vyy_data[k]>0.0) {
usedBin[i]++;
usedBin[vyy_cols[k]]++;
}
}
}
Int_t n=0;
Int_t *yToI=new Int_t[ny];
Int_t *iToY=new Int_t[ny];
for(Int_t i=0;i<ny;i++) {
if(usedBin[i]) {
yToI[i]=n;
iToY[n]=i;
n++;
} else {
yToI[i]=-1;
}
}
delete[] usedBin;
Int_t nn=vyy_rows[ny];
Int_t *vyyred_rows=new Int_t[nn];
Int_t *vyyred_cols=new Int_t[nn];
Double_t *vyyred_data=new Double_t[nn];
nn=0;
for(Int_t i=0;i<ny;i++) {
for(Int_t k=vyy_rows[i];k<vyy_rows[i+1];k++) {
if(vyy_data[k]>0.0) {
vyyred_rows[nn]=yToI[i];
vyyred_cols[nn]=yToI[vyy_cols[k]];
vyyred_data[nn]=vyy_data[k];
nn++;
}
}
}
TMatrixDSparse *vyyred=CreateSparseMatrix
(n,n,nn,vyyred_rows,vyyred_cols,vyyred_data);
delete[] vyyred_rows;
delete[] vyyred_cols;
delete[] vyyred_data;
TMatrixD *vyyredinv=InvertMSparse(vyyred);
DeleteMatrix(&vyyred);
nn=ny*ny;
Int_t *vyyinv_rows=new Int_t[nn];
Int_t *vyyinv_cols=new Int_t[nn];
Double_t *vyyinv_data=new Double_t[nn];
nn=0;
for(Int_t ix=0;ix<n;ix++) {
for(Int_t iy=0;iy<n;iy++) {
Double_t d=(*vyyredinv)(ix,iy);
if(d != 0.0) {
vyyinv_rows[nn]=iToY[ix];
vyyinv_cols[nn]=iToY[iy];
vyyinv_data[nn]=d;
nn++;
}
}
}
DeleteMatrix(&vyyredinv);
TMatrixDSparse *Vyyinv=CreateSparseMatrix
(ny,ny,nn,vyyinv_rows,vyyinv_cols,vyyinv_data);
delete[] vyyinv_rows;
delete[] vyyinv_cols;
delete[] vyyinv_data;
delete[] yToI;
delete[] iToY;
TMatrixDSparse *AtVyyinv=MultiplyMSparseTranspMSparse(fA,Vyyinv);
TMatrixDSparse *rhs=MultiplyMSparseM(AtVyyinv,fY);
if (fBiasScale != 0.0) {
TMatrixDSparse *rhs2=MultiplyMSparseM(fLsquared,fX0);
AddMSparse(rhs, fTauSquared * fBiasScale ,rhs2);
DeleteMatrix(&rhs2);
}
fEinv=MultiplyMSparseMSparse(AtVyyinv,fA);
AddMSparse(fEinv,fTauSquared,fLsquared);
TMatrixD *EE = InvertMSparse(fEinv);
fE=new TMatrixDSparse(*EE);
fX = new TMatrixD(*EE, TMatrixD::kMult, *rhs);
DeleteMatrix(&rhs);
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("TUnfold::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 *AE = MultiplyMSparseMSparse(fA,fE);
fVxx = MultiplyMSparseMSparse(fDXDY,AE);
DeleteMatrix(&AE);
fAx = MultiplyMSparseM(fA,fX);
TMatrixD dy(*fY, TMatrixD::kMinus, *fAx);
TMatrixDSparse *VyyinvDy=MultiplyMSparseM(Vyyinv,&dy);
DeleteMatrix(&Vyyinv);
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(fLsquared,&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("TUnfold::Unfold",
"epsilon#fDXDtauSquared has dimension %d != 1",
temp->GetRowIndexArray()[1]);
}
if(f!=0.0) {
AddMSparse(fDXDtauSquared, -f,Eepsilon);
}
DeleteMatrix(&temp);
}
DeleteMatrix(&epsilon);
DeleteMatrix(&LsquaredDx);
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);
DeleteMatrix(&EE);
TMatrixD *VxxINV = InvertMSparse(fVxx);
fVxxInv=new TMatrixDSparse(*VxxINV);
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. / ((*VxxINV) (ix, 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;
delete VxxINV;
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 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) 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;
}
TMatrixD *TUnfold::InvertMSparse(const TMatrixDSparse *A) const {
if(A->GetNcols()!=A->GetNrows()) {
Fatal("InvertMSparse","inconsistent matrix row/col %d!=%d",
A->GetNcols(),A->GetNrows());
}
#ifdef SCHUR_COMPLEMENT_MATRIX_INVERSION
const Int_t *a_rows=A->GetRowIndexArray();
const Int_t *a_cols=A->GetColIndexArray();
const Double_t *a_data=A->GetMatrixArray();
Int_t nmin=0,nmax=0;
for(Int_t imin=0;imin<A->GetNrows();imin++) {
Int_t imax=A->GetNrows();
for(Int_t i2=imin;i2<imax;i2++) {
for(Int_t i=a_rows[i2];i<a_rows[i2+1];i++) {
if(a_data[i]==0.0) continue;
Int_t icol=a_cols[i];
if(icol<imin) continue;
if(icol==i2) continue;
if(icol<i2) {
imax=i2;
break;
} else {
imax=icol;
break;
}
}
}
if(imax-imin>nmax-nmin) {
nmin=imin;
nmax=imax;
}
}
if(nmin>=nmax-1) {
TMatrixD *r=new TMatrixD(*A);
if(!InvertMConditioned(r)) {
Fatal("InvertMSparse","InvertMConditioned(full matrix) failed");
}
return r;
} else if((nmin==0)&&(nmax==A->GetNrows())) {
TMatrixD *r=new TMatrixD(A->GetNrows(),A->GetNcols());
Int_t error=0;
for(Int_t irow=nmin;irow<nmax;irow++) {
for(Int_t i=a_rows[irow];i<a_rows[irow+1];i++) {
if(a_cols[i]==irow) {
if(a_data[i] !=0.0) (*r)(irow,irow)=1./a_data[i];
else error++;
}
}
}
if(error) {
Error("InvertMSparse",
"inversion failed (diagonal matrix) nerror=%d",error);
}
return r;
}
std::vector<Double_t> Dinv;
Dinv.resize(nmax-nmin);
Int_t error=0;
for(Int_t irow=nmin;irow<nmax;irow++) {
for(Int_t i=a_rows[irow];i<a_rows[irow+1];i++) {
if(a_cols[i]==irow) {
if(a_data[i]!=0.0) {
Dinv[irow-nmin]=1./a_data[i];
} else {
Dinv[irow-nmin]=0.0;
error++;
}
break;
}
}
}
if(error) {
Error("InvertMSparse",
"inversion failed (diagonal part) nerror=%d",error);
}
Int_t nBDinv=0,nC=0;
for(Int_t irow_a=0;irow_a<A->GetNrows();irow_a++) {
if((irow_a<nmin)||(irow_a>=nmax)) {
for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
Int_t icol=a_cols[i];
if((icol>=nmin)&&(icol<nmax)) nBDinv++;
}
} else {
for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
Int_t icol = a_cols[i];
if((icol<nmin)||(icol>=nmax)) nC++;
}
}
}
Int_t *row_BDinv=new Int_t[nBDinv+1];
Int_t *col_BDinv=new Int_t[nBDinv+1];
Double_t *data_BDinv=new Double_t[nBDinv+1];
Int_t *row_C=new Int_t[nC+1];
Int_t *col_C=new Int_t[nC+1];
Double_t *data_C=new Double_t[nC+1];
TMatrixD Aschur(A->GetNrows()-(nmax-nmin),A->GetNcols()-(nmax-nmin));
nBDinv=0;
nC=0;
for(Int_t irow_a=0;irow_a<A->GetNrows();irow_a++) {
if((irow_a<nmin)||(irow_a>=nmax)) {
Int_t row=(irow_a<nmin) ? irow_a : (irow_a-(nmax-nmin));
for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
Int_t icol_a=a_cols[i];
if(icol_a<nmin) {
Aschur(row,icol_a)=a_data[i];
} else if(icol_a>=nmax) {
Aschur(row,icol_a-(nmax-nmin))=a_data[i];
} else {
row_BDinv[nBDinv]=row;
col_BDinv[nBDinv]=icol_a-nmin;
data_BDinv[nBDinv]=a_data[i]*Dinv[icol_a-nmin];
nBDinv++;
}
}
} else {
for(Int_t i=a_rows[irow_a];i<a_rows[irow_a+1];i++) {
Int_t icol_a=a_cols[i];
if(icol_a<nmin) {
row_C[nC]=irow_a-nmin;
col_C[nC]=icol_a;
data_C[nC]=a_data[i];
nC++;
} else if(icol_a>=nmax) {
row_C[nC]=irow_a-nmin;
col_C[nC]=icol_a-(nmax-nmin);
data_C[nC]=a_data[i];
nC++;
}
}
}
}
TMatrixDSparse *BDinv=CreateSparseMatrix
(A->GetNrows()-(nmax-nmin),nmax-nmin,
nBDinv,row_BDinv,col_BDinv,data_BDinv);
delete[] row_BDinv;
delete[] col_BDinv;
delete[] data_BDinv;
TMatrixDSparse *C=CreateSparseMatrix(nmax-nmin,A->GetNcols()-(nmax-nmin),
nC,row_C,col_C,data_C);
delete[] row_C;
delete[] col_C;
delete[] data_C;
TMatrixDSparse *BDinvC=MultiplyMSparseMSparse(BDinv,C);
Aschur -= *BDinvC;
if(!InvertMConditioned(&Aschur)) {
Fatal("InvertMSparse","InvertMConditioned failed (part of matrix)");
}
DeleteMatrix(&BDinvC);
TMatrixD *r=new TMatrixD(A->GetNrows(),A->GetNcols());
for(Int_t row_a=0;row_a<Aschur.GetNrows();row_a++) {
for(Int_t col_a=0;col_a<Aschur.GetNcols();col_a++) {
(*r)((row_a<nmin) ? row_a : (row_a+nmax-nmin),
(col_a<nmin) ? col_a : (col_a+nmax-nmin))=Aschur(row_a,col_a);
}
}
TMatrixDSparse *CAschur=MultiplyMSparseM(C,&Aschur);
TMatrixDSparse *CAschurBDinv=MultiplyMSparseMSparse(CAschur,BDinv);
DeleteMatrix(&C);
const Int_t *CAschurBDinv_row=CAschurBDinv->GetRowIndexArray();
const Int_t *CAschurBDinv_col=CAschurBDinv->GetColIndexArray();
const Double_t *CAschurBDinv_data=CAschurBDinv->GetMatrixArray();
for(Int_t row=0;row<CAschurBDinv->GetNrows();row++) {
for(Int_t i=CAschurBDinv_row[row];i<CAschurBDinv_row[row+1];i++) {
Int_t col=CAschurBDinv_col[i];
(*r)(row+nmin,col+nmin)=CAschurBDinv_data[i]*Dinv[row];
}
(*r)(row+nmin,row+nmin) += Dinv[row];
}
DeleteMatrix(&CAschurBDinv);
const Int_t *CAschur_row=CAschur->GetRowIndexArray();
const Int_t *CAschur_col=CAschur->GetColIndexArray();
const Double_t *CAschur_data=CAschur->GetMatrixArray();
for(Int_t row=0;row<CAschur->GetNrows();row++) {
for(Int_t i=CAschur_row[row];i<CAschur_row[row+1];i++) {
Int_t col=CAschur_col[i];
(*r)(row+nmin,
(col<nmin) ? col : (col+nmax-nmin))= -CAschur_data[i]*Dinv[row];
}
}
DeleteMatrix(&CAschur);
const Int_t *BDinv_row=BDinv->GetRowIndexArray();
const Int_t *BDinv_col=BDinv->GetColIndexArray();
const Double_t *BDinv_data=BDinv->GetMatrixArray();
for(Int_t row_aschur=0;row_aschur<Aschur.GetNrows();row_aschur++) {
Int_t row=(row_aschur<nmin) ? row_aschur : (row_aschur+nmax-nmin);
for(Int_t row_bdinv=0;row_bdinv<BDinv->GetNrows();row_bdinv++) {
for(Int_t i=BDinv_row[row_bdinv];i<BDinv_row[row_bdinv+1];i++) {
(*r)(row,BDinv_col[i]+nmin) -= Aschur(row_aschur,row_bdinv)*
BDinv_data[i];
}
}
}
DeleteMatrix(&BDinv);
return r;
#else
TMatrixD *r=new TMatrixD(A);
if(!InvertMConditioned(*r)) {
Fatal("InvertMSparse","InvertMConditioned failed (full matrix)";
print_backtrace();
}
return r;
#endif
}
Bool_t TUnfold::InvertMConditioned(TMatrixD *A) {
#ifdef INVERT_WITH_CONDITIONING
Double_t *A_diagonals=new Double_t[A->GetNrows()];
for(Int_t i=0;i<A->GetNrows();i++) {
A_diagonals[i]=TMath::Sqrt(TMath::Abs((*A)(i,i)));
if(A_diagonals[i]>0.0) A_diagonals[i]=1./A_diagonals[i];
else A_diagonals[i]=1.0;
}
for(Int_t i=0;i<A->GetNrows();i++) {
for(Int_t j=0;j<A->GetNcols();j++) {
(*A)(i,j) *= A_diagonals[i]*A_diagonals[j];
}
}
#endif
Double_t det=0.0;
A->Invert(&det);
#ifdef INVERT_WITH_CONDITIONING
for(Int_t i=0;i<A->GetNrows();i++) {
for(Int_t j=0;j<A->GetNcols();j++) {
(*A)(i,j) *= A_diagonals[i]*A_diagonals[j];
}
}
delete[] A_diagonals;
#endif
return (det !=0.0);
}
TUnfold::TUnfold(const TH2 *hist_A, EHistMap histmap, ERegMode regmode,
TUnfold::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;
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++;
sum += z;
}
}
if (sum > 0.0) {
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;
for (Int_t ix = 0; ix < nx0; ix++) {
if(fHistToX[ix]<0) {
nprint++;
if(ixlast<0) {
binlist +=" ";
binlist +=ix;
ixfirst=ix;
}
ixlast=ix;
}
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","the following output bins "
"are not connected to the input side %s",
static_cast<const char *>(binlist));
} else {
Warning("TUnfold","the following output bins "
"are not connected to the input side %s",
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;
fLsquared = new TMatrixDSparse(GetNx(), 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(&fLsquared);
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]);
}
}
Int_t TUnfold::RegularizeSize(int bin, Double_t scale)
{
if(fRegMode==kRegModeNone) fRegMode=kRegModeSize;
if(fRegMode!=kRegModeSize) fRegMode=kRegModeMixed;
Int_t i = fHistToX[bin];
if (i < 0) {
return 1;
}
(*fLsquared) (i, i) = scale * scale;
return 0;
}
Int_t TUnfold::RegularizeDerivative(int left_bin, int right_bin,
Double_t scale)
{
if(fRegMode==kRegModeNone) fRegMode=kRegModeDerivative;
if(fRegMode!=kRegModeDerivative) fRegMode=kRegModeMixed;
Int_t il = fHistToX[left_bin];
Int_t ir = fHistToX[right_bin];
if ((il < 0) || (ir < 0)) {
return 1;
}
Double_t scale_squared = scale * scale;
(*fLsquared) (il, il) += scale_squared;
(*fLsquared) (il, ir) -= scale_squared;
(*fLsquared) (ir, il) -= scale_squared;
(*fLsquared) (ir, ir) += scale_squared;
return 0;
}
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;
Int_t il, ic, ir;
il = fHistToX[left_bin];
ic = fHistToX[center_bin];
ir = fHistToX[right_bin];
if ((il < 0) || (ic < 0) || (ir < 0)) {
return 1;
}
Double_t r[3];
r[0] = -scale_left;
r[2] = -scale_right;
r[1] = -r[0] - r[2];
(*fLsquared) (il, il) += r[0] * r[0];
(*fLsquared) (il, ic) += r[0] * r[1];
(*fLsquared) (il, ir) += r[0] * r[2];
(*fLsquared) (ic, il) += r[1] * r[0];
(*fLsquared) (ic, ic) += r[1] * r[1];
(*fLsquared) (ic, ir) += r[1] * r[2];
(*fLsquared) (ir, il) += r[2] * r[0];
(*fLsquared) (ir, ic) += r[2] * r[1];
(*fLsquared) (ir, ir) += r[2] * r[2];
return 0;
}
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("TUnfold::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) {
fBiasScale = scaleBias;
ClearResults();
fNdf = -GetNpar();
Int_t *rowColVyy=new Int_t[GetNy()];
Int_t *col1Vyy=new Int_t[GetNy()];
Double_t *dataVyy=new Double_t[GetNy()];
Int_t nError=0;
for (Int_t iy = 0; iy < GetNy(); iy++) {
Double_t dy = input->GetBinError(iy + 1);
rowColVyy[iy] = iy;
col1Vyy[iy] = 0;
if (dy <= 0.0) {
nError++;
if(oneOverZeroError>0.0) {
dataVyy[iy] = 1./ ( oneOverZeroError*oneOverZeroError);
} else {
dataVyy[iy] = 0.0;
}
} else {
dataVyy[iy] = dy * dy;
}
if( dataVyy[iy]>0.0) fNdf ++;
}
DeleteMatrix(&fVyy);
fVyy = CreateSparseMatrix
(GetNy(),GetNy(),GetNy(),rowColVyy,rowColVyy,dataVyy);
TMatrixDSparse *vecV=CreateSparseMatrix
(GetNy(),1,GetNy(),rowColVyy,col1Vyy, dataVyy);
delete[] rowColVyy;
delete[] col1Vyy;
delete[] dataVyy;
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 input bins have zero error,"
" 1/error set to %lf.",nError,oneOverZeroError);
} else {
Warning("SetInput","One input bin has zero error,"
" 1/error set to %lf.",oneOverZeroError);
}
} else {
if(nError>1) {
Warning("SetInput","%d input bins have zero error,"
" and are ignored.",nError);
} else {
Warning("SetInput","One input bin has zero error,"
" and is ignored.");
}
}
}
if(nError2>0) {
if(nError2>1) {
Warning("SetInput","%d output bins are not constrained by any data.",
nError2);
} else {
Warning("SetInput","One output bins is not constrained by any data.");
}
if(oneOverZeroError<=0.0) {
const Int_t *a_rows=fA->GetRowIndexArray();
const Int_t *a_cols=fA->GetColIndexArray();
for (Int_t col = 0; col <mAtV->GetNrows();col++) {
if(mAtV->GetRowIndexArray()[col]==
mAtV->GetRowIndexArray()[col+1]) {
TString binlist("output bin ");
binlist += fXToHist[col];
binlist +=" depends on ignored input bins ";
for(Int_t row=0;row<fA->GetNrows();row++) {
if(input->GetBinError(row + 1)>0.0) continue;
for(Int_t i=a_rows[row];i<a_rows[row+1];i++) {
if(a_cols[i]!=col) continue;
binlist +=" ";
binlist +=row;
}
}
Warning("SetInput","%s",binlist.Data());
}
}
}
}
DeleteMatrix(&mAtV);
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)) {
if(GetNdf()<=0) {
Error("ScanLcurve","too few input bins, NDF<=0");
}
DoUnfold(0.0);
Double_t x0=GetLcurveX();
Double_t y0=GetLcurveY();
Info("ScanLcurve","logtau=-Infinity X=%lf Y=%lf",x0,y0);
{
Double_t logTau=
0.5*(TMath::Log10(fChi2A+3.*TMath::Sqrt(GetNdf()+1.0))
-GetLcurveY());
DoUnfold(TMath::Power(10.,logTau));
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));
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));
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));
Info("ScanLcurve","logtau=%lf X=%lf Y=%lf",
logTauMax,GetLcurveX(),GetLcurveY());
curve[logTauMax]=std::make_pair(GetLcurveX(),GetLcurveY());
}
DoUnfold(TMath::Power(10.,logTauMin));
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));
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));
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;
}
TH1D *TUnfold::GetOutput(const char *name,const char *title,
Double_t xmin, Double_t xmax) const
{
int nbins = fHistToX.GetSize() - 2;
if (xmin >= xmax) {
xmin = 0.0;
xmax = nbins;
}
TH1D *out = new TH1D(name, title, nbins, xmin, xmax);
GetOutput(out);
return out;
}
TH1D *TUnfold::GetBias(const char *name,const char *title,
Double_t xmin, Double_t xmax) const
{
int nbins = fHistToX.GetSize() - 2;
if (xmin >= xmax) {
xmin = 0.0;
xmax = nbins;
}
TH1D *out = new TH1D(name, title, nbins, xmin, xmax);
for (Int_t i = 0; i < GetNx(); i++) {
out->SetBinContent(fXToHist[i], (*fX0) (i, 0));
}
return out;
}
TH1D *TUnfold::GetFoldedOutput(const char *name,const char *title,
Double_t y0, Double_t y1) const
{
if (y0 >= y1) {
y0 = 0.0;
y1 = GetNy();
}
TH1D *out = new TH1D(name, title, GetNy(), y0, y1);
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++) {
out->SetBinContent(i + 1, (*fAx) (i, 0));
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(i + 1,TMath::Sqrt(e2));
}
DeleteMatrix(&AVxx);
return out;
}
TH1D *TUnfold::GetInput(const char *name,const char *title,
Double_t y0, Double_t y1) const
{
if (y0 >= y1) {
y0 = 0.0;
y1 = GetNy();
}
TH1D *out = new TH1D(name, title, GetNy(), y0, y1);
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++) {
out->SetBinContent(i + 1, (*fY) (i, 0));
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(i + 1, e);
}
return out;
}
TH2D *TUnfold::GetRhoIJ(const char *name,const char *title,
Double_t xmin, Double_t xmax) const
{
int nbins = fHistToX.GetSize() - 2;
if (xmin >= xmax) {
xmin = 0.0;
xmax = nbins;
}
TH2D *out = new TH2D(name, title, nbins, xmin, xmax, nbins, xmin, xmax);
GetRhoIJ(out);
return out;
}
TH2D *TUnfold::GetEmatrix(const char *name,const char *title,
Double_t xmin, Double_t xmax) const
{
int nbins = fHistToX.GetSize() - 2;
if (xmin >= xmax) {
xmin = 0.0;
xmax = nbins;
}
TH2D *out = new TH2D(name, title, nbins, xmin, xmax, nbins, xmin, xmax);
GetEmatrix(out);
return out;
}
TH1D *TUnfold::GetRhoI(const char *name,const char *title,
Double_t xmin, Double_t xmax) const
{
int nbins = fHistToX.GetSize() - 2;
if (xmin >= xmax) {
xmin = 0.0;
xmax = nbins;
}
TH1D *out = new TH1D(name, title, nbins, xmin, xmax);
GetRhoI(out);
return out;
}
TH2D *TUnfold::GetLsquared(const char *name,const char *title,
Double_t xmin, Double_t xmax) const
{
int nbins = fHistToX.GetSize() - 2;
if (xmin >= xmax) {
xmin = 0.0;
xmax = nbins;
}
TH2D *out = new TH2D(name, title, nbins, xmin, xmax, nbins, xmin, xmax);
out->SetOption("BOX");
const Int_t *rows=fLsquared->GetRowIndexArray();
const Int_t *cols=fLsquared->GetColIndexArray();
const Double_t *data=fLsquared->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], fTauSquared * data[cindex]);
}
}
return out;
}
void TUnfold::SetConstraint(TUnfold::EConstraint constraint) {
if(fConstraint !=constraint) ClearResults();
fConstraint=constraint;
Info("TUnfold::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 {
Int_t nbin=output->GetNbinsX();
Double_t *c=new Double_t[nbin+2];
Double_t *e2=new Double_t[nbin+2];
for(Int_t i=0;i<nbin+2;i++) {
c[i]=0.0;
e2[i]=0.0;
}
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)&&(destBinI<nbin+2)&&(srcBinI>=0)) {
c[destBinI]+=(*fX)(srcBinI,0);
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(Int_t i=0;i<nbin+2;i++) {
output->SetBinContent(i,c[i]);
output->SetBinError(i,TMath::Sqrt(e2[i]));
}
delete[] c;
delete[] e2;
}
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);
}
Double_t TUnfold::GetRhoI(TH1 *rhoi,TH2 *ematrixinv,const Int_t *binMap) const {
Int_t nbin=rhoi->GetNbinsX();
Int_t n=0;
Int_t *outputToEmat=new Int_t[nbin+2];
Int_t *ematToOutput=new Int_t[nbin+2];
Int_t *vxxToEmat=new Int_t[GetNx()];
for(Int_t i=0;i<nbin+2;i++) {
outputToEmat[i]=-1;
}
for(Int_t i=0;i<GetNx();i++) {
Int_t matrix_bin=fXToHist[i];
Int_t output_bin=binMap ? binMap[matrix_bin] : matrix_bin;
if((output_bin>=0)&&(output_bin<nbin+2)) {
if(outputToEmat[output_bin]<0) {
outputToEmat[output_bin]=n;
ematToOutput[n]=output_bin;
n++;
}
vxxToEmat[i]=outputToEmat[output_bin];
} else {
vxxToEmat[i]=-1;
}
}
delete[] outputToEmat;
TMatrixD e(n,n);
const Int_t *rows_Vxx=fVxx->GetRowIndexArray();
const Int_t *cols_Vxx=fVxx->GetColIndexArray();
const Double_t *data_Vxx=fVxx->GetMatrixArray();
for(Int_t i=0;i<GetNx();i++) {
Int_t ie=vxxToEmat[i];
if(ie<0) continue;
for(int index_vxx=rows_Vxx[i];index_vxx<rows_Vxx[i+1];index_vxx++) {
Int_t je=vxxToEmat[cols_Vxx[index_vxx]];
if(je<0) continue;
e(ie,je) += data_Vxx[index_vxx];
}
}
delete[] vxxToEmat;
TMatrixD einv(e);
InvertMConditioned(&einv);
Double_t rhoMax=0.0;
for(Int_t i=0;i<n;i++) {
Int_t i_out=ematToOutput[i];
Double_t rho=1.-1./(einv(i,i)*e(i,i));
if(rho>=0.0) rho=TMath::Sqrt(rho);
else rho=-TMath::Sqrt(-rho);
if(rho>rhoMax) {
rhoMax = rho;
}
rhoi->SetBinContent(i_out,rho);
if(ematrixinv) {
for(Int_t j=0;j<n;j++) {
ematrixinv->SetBinContent(i_out,ematToOutput[j],einv(i,j));
}
}
}
delete[] ematToOutput;
return rhoMax;
}
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;
}