#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <float.h>
#include <string.h>
#include <TClass.h>
#include <TMath.h>
#include "AliSymMatrix.h"
#include "AliLog.h"
ClassImp(AliSymMatrix)
AliSymMatrix* AliSymMatrix::fgBuffer = 0;
Int_t AliSymMatrix::fgCopyCnt = 0;
AliSymMatrix::AliSymMatrix()
: fElems(0),fElemsAdd(0)
{
fSymmetric = kTRUE;
fgCopyCnt++;
}
AliSymMatrix::AliSymMatrix(Int_t size)
: AliMatrixSq(),fElems(0),fElemsAdd(0)
{
fNrows = 0;
fNrowIndex = fNcols = fRowLwb = size;
fElems = new Double_t[fNcols*(fNcols+1)/2];
fSymmetric = kTRUE;
Reset();
fgCopyCnt++;
}
AliSymMatrix::AliSymMatrix(const AliSymMatrix &src)
: AliMatrixSq(src),fElems(0),fElemsAdd(0)
{
fNrowIndex = fNcols = src.GetSize();
fNrows = 0;
fRowLwb = src.GetSizeUsed();
if (fNcols) {
int nmainel = fNcols*(fNcols+1)/2;
fElems = new Double_t[nmainel];
nmainel = src.fNcols*(src.fNcols+1)/2;
memcpy(fElems,src.fElems,nmainel*sizeof(Double_t));
if (src.GetSizeAdded()) {
Double_t *pnt = fElems + nmainel;
int ncl = src.GetSizeBooked() + 1;
for (int ir=0;ir<src.GetSizeAdded();ir++) {
memcpy(pnt,src.fElemsAdd[ir],ncl*sizeof(Double_t));
pnt += ncl;
ncl++;
}
}
}
else fElems = 0;
fElemsAdd = 0;
fgCopyCnt++;
}
AliSymMatrix::~AliSymMatrix()
{
Clear();
if (--fgCopyCnt < 1 && fgBuffer) {delete fgBuffer; fgBuffer = 0;}
}
AliSymMatrix& AliSymMatrix::operator=(const AliSymMatrix& src)
{
if (this != &src) {
TObject::operator=(src);
if (GetSizeBooked()!=src.GetSizeBooked() && GetSizeAdded()!=src.GetSizeAdded()) {
if (fElems) delete[] fElems;
for (int i=0;i<GetSizeAdded();i++) delete[] fElemsAdd[i];
delete[] fElemsAdd;
fNrowIndex = src.GetSize();
fNcols = src.GetSize();
fNrows = 0;
fRowLwb = src.GetSizeUsed();
fElems = new Double_t[GetSize()*(GetSize()+1)/2];
int nmainel = src.GetSizeBooked()*(src.GetSizeBooked()+1);
memcpy(fElems,src.fElems,nmainel*sizeof(Double_t));
if (src.GetSizeAdded()) {
Double_t *pnt = fElems + nmainel;
int ncl = src.GetSizeBooked() + 1;
for (int ir=0;ir<src.GetSizeAdded();ir++) {
ncl += ir;
memcpy(pnt,src.fElemsAdd[ir],ncl*sizeof(Double_t));
pnt += ncl;
}
}
}
else {
memcpy(fElems,src.fElems,GetSizeBooked()*(GetSizeBooked()+1)/2*sizeof(Double_t));
int ncl = GetSizeBooked() + 1;
for (int ir=0;ir<GetSizeAdded();ir++) {
ncl += ir;
memcpy(fElemsAdd[ir],src.fElemsAdd[ir],ncl*sizeof(Double_t));
}
}
}
return *this;
}
AliSymMatrix& AliSymMatrix::operator+=(const AliSymMatrix& src)
{
if (GetSizeUsed() != src.GetSizeUsed()) {
AliError("Matrix sizes are different");
return *this;
}
for (int i=0;i<GetSizeUsed();i++) for (int j=i;j<GetSizeUsed();j++) (*this)(j,i) += src(j,i);
return *this;
}
void AliSymMatrix::Clear(Option_t*)
{
if (fElems) {delete[] fElems; fElems = 0;}
if (fElemsAdd) {
for (int i=0;i<GetSizeAdded();i++) delete[] fElemsAdd[i];
delete[] fElemsAdd;
fElemsAdd = 0;
}
fNrowIndex = fNcols = fNrows = fRowLwb = 0;
}
Float_t AliSymMatrix::GetDensity() const
{
Int_t nel = 0;
for (int i=GetSizeUsed();i--;) for (int j=i+1;j--;) if (!IsZero(GetEl(i,j))) nel++;
return 2.*nel/( (GetSizeUsed()+1)*GetSizeUsed() );
}
void AliSymMatrix::Print(Option_t* option) const
{
printf("Symmetric Matrix: Size = %d (%d rows added dynamically), %d used\n",GetSize(),GetSizeAdded(),GetSizeUsed());
TString opt = option; opt.ToLower();
if (opt.IsNull()) return;
opt = "%"; opt += 1+int(TMath::Log10(double(GetSize()))); opt+="d|";
for (Int_t i=0;i<GetSizeUsed();i++) {
printf(opt,i);
for (Int_t j=0;j<=i;j++) printf("%+.3e|",GetEl(i,j));
printf("\n");
}
}
void AliSymMatrix::MultiplyByVec(const Double_t *vecIn,Double_t *vecOut) const
{
for (int i=GetSizeUsed();i--;) {
vecOut[i] = 0.0;
for (int j=GetSizeUsed();j--;) vecOut[i] += vecIn[j]*GetEl(i,j);
}
}
AliSymMatrix* AliSymMatrix::DecomposeChol()
{
if (!fgBuffer || fgBuffer->GetSizeUsed()!=GetSizeUsed()) {
delete fgBuffer;
fgBuffer = new AliSymMatrix(*this);
}
else (*fgBuffer) = *this;
AliSymMatrix& mchol = *fgBuffer;
for (int i=0;i<GetSizeUsed();i++) {
Double_t *rowi = mchol.GetRow(i);
for (int j=i;j<GetSizeUsed();j++) {
Double_t *rowj = mchol.GetRow(j);
double sum = rowj[i];
for (int k=i-1;k>=0;k--) if (rowi[k]&&rowj[k]) sum -= rowi[k]*rowj[k];
if (i == j) {
if (sum <= 0.0) {
AliInfo(Form("The matrix is not positive definite [%e]\n"
"Choleski decomposition is not possible",sum));
Print("l");
return 0;
}
rowi[i] = TMath::Sqrt(sum);
} else rowj[i] = sum/rowi[i];
}
}
return fgBuffer;
}
Bool_t AliSymMatrix::InvertChol()
{
AliSymMatrix* mchol = DecomposeChol();
if (!mchol) {
AliInfo("Failed to invert the matrix");
return kFALSE;
}
InvertChol(mchol);
return kTRUE;
}
void AliSymMatrix::InvertChol(AliSymMatrix* pmchol)
{
Double_t sum;
AliSymMatrix& mchol = *pmchol;
for (int i=0;i<GetSizeUsed();i++) {
mchol(i,i) = 1.0/mchol(i,i);
for (int j=i+1;j<GetSizeUsed();j++) {
Double_t *rowj = mchol.GetRow(j);
sum = 0.0;
for (int k=i;k<j;k++) if (rowj[k]) {
double &mki = mchol(k,i); if (mki) sum -= rowj[k]*mki;
}
rowj[i] = sum/rowj[j];
}
}
for (int i=GetSizeUsed();i--;) {
for (int j=i+1;j--;) {
sum = 0;
for (int k=i;k<GetSizeUsed();k++) {
double &mik = mchol(i,k);
if (mik) {
double &mjk = mchol(j,k);
if (mjk) sum += mik*mjk;
}
}
(*this)(j,i) = sum;
}
}
}
Bool_t AliSymMatrix::SolveChol(Double_t *b, Bool_t invert)
{
Int_t i,k;
Double_t sum;
AliSymMatrix *pmchol = DecomposeChol();
if (!pmchol) {
AliInfo("SolveChol failed");
return kFALSE;
}
AliSymMatrix& mchol = *pmchol;
for (i=0;i<GetSizeUsed();i++) {
Double_t *rowi = mchol.GetRow(i);
for (sum=b[i],k=i-1;k>=0;k--) if (rowi[k]&&b[k]) sum -= rowi[k]*b[k];
b[i]=sum/rowi[i];
}
for (i=GetSizeUsed()-1;i>=0;i--) {
for (sum=b[i],k=i+1;k<GetSizeUsed();k++) if (b[k]) {
double &mki=mchol(k,i); if (mki) sum -= mki*b[k];
}
b[i]=sum/mchol(i,i);
}
if (invert) InvertChol(pmchol);
return kTRUE;
}
Bool_t AliSymMatrix::SolveChol(TVectorD &b, Bool_t invert)
{
return SolveChol((Double_t*)b.GetMatrixArray(),invert);
}
Bool_t AliSymMatrix::SolveChol(Double_t *brhs, Double_t *bsol,Bool_t invert)
{
memcpy(bsol,brhs,GetSizeUsed()*sizeof(Double_t));
return SolveChol(bsol,invert);
}
Bool_t AliSymMatrix::SolveChol(const TVectorD &brhs, TVectorD &bsol,Bool_t invert)
{
bsol = brhs;
return SolveChol(bsol,invert);
}
void AliSymMatrix::AddRows(int nrows)
{
if (nrows<1) return;
Double_t **pnew = new Double_t*[nrows+fNrows];
for (int ir=0;ir<fNrows;ir++) pnew[ir] = fElemsAdd[ir];
for (int ir=0;ir<nrows;ir++) {
int ncl = GetSize()+1;
pnew[fNrows] = new Double_t[ncl];
memset(pnew[fNrows],0,ncl*sizeof(Double_t));
fNrows++;
fNrowIndex++;
fRowLwb++;
}
delete[] fElemsAdd;
fElemsAdd = pnew;
}
void AliSymMatrix::Reset()
{
if (fElemsAdd) {
delete[] fElems;
for (int i=0;i<fNrows;i++) delete[] fElemsAdd[i];
delete[] fElemsAdd; fElemsAdd = 0;
fNcols = fRowLwb = fNrowIndex;
fElems = new Double_t[GetSize()*(GetSize()+1)/2];
fNrows = 0;
}
if (fElems) memset(fElems,0,GetSize()*(GetSize()+1)/2*sizeof(Double_t));
}
Double_t* AliSymMatrix::GetRow(Int_t r)
{
if (r>=GetSize()) {
int nn = GetSize();
AddRows(r-GetSize()+1);
AliDebug(2,Form("create %d of %d\n",r, nn));
return &((fElemsAdd[r-GetSizeBooked()])[0]);
}
else return &fElems[GetIndex(r,0)];
}
int AliSymMatrix::SolveSpmInv(double *vecB, Bool_t stabilize)
{
Int_t nRank = 0;
int iPivot;
double vPivot = 0.;
double eps = 1e-14;
int nGlo = GetSizeUsed();
bool *bUnUsed = new bool[nGlo];
double *rowMax,*colMax=0;
rowMax = new double[nGlo];
if (stabilize) {
colMax = new double[nGlo];
for (Int_t i=nGlo; i--;) rowMax[i] = colMax[i] = 0.0;
for (Int_t i=nGlo; i--;) for (Int_t j=i+1;j--;) {
double vl = TMath::Abs(Query(i,j));
if (IsZero(vl)) continue;
if (vl > rowMax[i]) rowMax[i] = vl;
if (vl > colMax[j]) colMax[j] = vl;
if (i==j) continue;
if (vl > rowMax[j]) rowMax[j] = vl;
if (vl > colMax[i]) colMax[i] = vl;
}
for (Int_t i=nGlo; i--;) {
if (!IsZero(rowMax[i])) rowMax[i] = 1./rowMax[i];
if (!IsZero(colMax[i])) colMax[i] = 1./colMax[i];
}
}
for (Int_t i=nGlo; i--;) bUnUsed[i] = true;
if (!fgBuffer || fgBuffer->GetSizeUsed()!=GetSizeUsed()) {
delete fgBuffer;
fgBuffer = new AliSymMatrix(*this);
}
else (*fgBuffer) = *this;
if (stabilize) for (int i=0;i<nGlo; i++) {
for (int j=0;j<=i; j++) {
double vl = Query(i,j);
if (!IsZero(vl)) SetEl(i,j, TMath::Sqrt(rowMax[i])*vl*TMath::Sqrt(colMax[j]) );
}
for (int j=i+1;j<nGlo;j++) {
double vl = Query(j,i);
if (!IsZero(vl)) fgBuffer->SetEl(j,i,TMath::Sqrt(rowMax[i])*vl*TMath::Sqrt(colMax[j]) );
}
}
for (Int_t j=nGlo; j--;) fgBuffer->DiagElem(j) = TMath::Abs(QueryDiag(j));
for (Int_t i=0; i<nGlo; i++) {
vPivot = 0.0;
iPivot = -1;
for (Int_t j=0; j<nGlo; j++) {
double vl;
if (bUnUsed[j] && (TMath::Abs(vl=QueryDiag(j))>TMath::Max(TMath::Abs(vPivot),eps*fgBuffer->QueryDiag(j)))) {
vPivot = vl;
iPivot = j;
}
}
if (iPivot >= 0) {
nRank++;
bUnUsed[iPivot] = false;
vPivot = 1.0/vPivot;
DiagElem(iPivot) = -vPivot;
for (Int_t j=0; j<nGlo; j++) {
for (Int_t jj=0; jj<nGlo; jj++) {
if (j != iPivot && jj != iPivot) {
double &r = j>=jj ? (*this)(j,jj) : (*fgBuffer)(jj,j);
r -= vPivot* ( j>iPivot ? Query(j,iPivot) : fgBuffer->Query(iPivot,j) )
* ( iPivot>jj ? Query(iPivot,jj) : fgBuffer->Query(jj,iPivot));
}
}
}
for (Int_t j=0; j<nGlo; j++) if (j != iPivot) {
(*this)(j,iPivot) *= vPivot;
(*fgBuffer)(iPivot,j) *= vPivot;
}
}
else {
for (Int_t j=0; j<nGlo; j++) {
if (bUnUsed[j]) {
vecB[j] = 0.0;
for (Int_t k=0; k<nGlo; k++) {
(*this)(j,k) = 0.;
if (j!=k) (*fgBuffer)(j,k) = 0;
}
}
}
break;
}
}
if (stabilize) for (Int_t i=0; i<nGlo; i++) for (Int_t j=0; j<nGlo; j++) {
double vl = TMath::Sqrt(colMax[i])*TMath::Sqrt(rowMax[j]);
if (i>=j) (*this)(i,j) *= vl;
else (*fgBuffer)(j,i) *= vl;
}
for (Int_t j=0; j<nGlo; j++) {
rowMax[j] = 0.0;
for (Int_t jj=0; jj<nGlo; jj++) {
double vl;
if (j>=jj) vl = (*this)(j,jj) = -Query(j,jj);
else vl = (*fgBuffer)(j,jj) = -fgBuffer->Query(j,jj);
rowMax[j] += vl*vecB[jj];
}
}
for (Int_t j=0; j<nGlo; j++) {
vecB[j] = rowMax[j];
}
delete [] bUnUsed;
delete [] rowMax;
if (stabilize) delete [] colMax;
return nRank;
}