#include "TDecompBK.h"
#include "TMath.h"
#include "TError.h"
ClassImp(TDecompBK)
TDecompBK::TDecompBK()
{
   fNIpiv = 0;
   fIpiv  = 0;
}
TDecompBK::TDecompBK(Int_t nrows)
{
   fNIpiv = nrows;
   fIpiv = new Int_t[fNIpiv];
   memset(fIpiv,0,fNIpiv*sizeof(Int_t));
   fU.ResizeTo(nrows,nrows);
}
TDecompBK::TDecompBK(Int_t row_lwb,Int_t row_upb)
{
   const Int_t nrows = row_upb-row_lwb+1;
   fNIpiv = nrows;
   fIpiv = new Int_t[fNIpiv];
   memset(fIpiv,0,fNIpiv*sizeof(Int_t));
   fColLwb = fRowLwb = row_lwb;
   fU.ResizeTo(nrows,nrows);
}
TDecompBK::TDecompBK(const TMatrixDSym &a,Double_t tol)
{
   R__ASSERT(a.IsValid());
   SetBit(kMatrixSet);
   fCondition = a.Norm1();
   fTol = a.GetTol();
   if (tol > 0)
      fTol = tol;
   fNIpiv = a.GetNcols();
   fIpiv = new Int_t[fNIpiv];
   memset(fIpiv,0,fNIpiv*sizeof(Int_t));
   const Int_t nRows = a.GetNrows();
   fColLwb = fRowLwb = a.GetRowLwb();
   fU.ResizeTo(nRows,nRows);
   memcpy(fU.GetMatrixArray(),a.GetMatrixArray(),nRows*nRows*sizeof(Double_t));
}
TDecompBK::TDecompBK(const TDecompBK &another) : TDecompBase(another)
{
   fNIpiv = 0;
   fIpiv  = 0;
   *this = another;
}
Bool_t TDecompBK::Decompose()
{
   if ( !TestBit(kMatrixSet) ) {
      Error("Decompose()","Matrix has not been set");
      return kFALSE;
   }
   Bool_t ok = kTRUE;
   const Double_t alpha = (1.+TMath::Sqrt(17.))/8.;
   const Int_t     n  = fU.GetNcols();
         Double_t *pU = fU.GetMatrixArray();
   TMatrixDDiag diag(fU);
   Int_t imax = 0;
   Int_t k = n-1;
   while (k >= 0) {
      Int_t kstep = 1;
      
      
      const Double_t absakk = TMath::Abs(diag(k));
      
      
      Double_t colmax;
      if ( k > 0 ) {
         TVectorD vcol = TMatrixDColumn_const(fU,k);
         vcol.Abs();
         const Int_t imax = TMath::LocMax(k,vcol.GetMatrixArray());
         colmax = vcol[imax];
      } else {
         colmax = 0.;
      }
      Int_t kp;
      if (TMath::Max(absakk,colmax) <= fTol) {
         
         kp = k;
         ok = kFALSE;
      } else {
         if (absakk >= alpha*colmax) {
           
            kp = k;
         } else {
            
            
            TVectorD vrow = TMatrixDRow_const(fU,imax);
            vrow.Abs();
            Int_t jmax = imax+1+TMath::LocMax(k-imax,vrow.GetMatrixArray()+imax+1);
            Double_t rowmax = vrow[jmax];
            if (imax > 0) {
               TVectorD vcol = TMatrixDColumn_const(fU,imax);
               vcol.Abs();
               jmax = TMath::LocMax(imax,vcol.GetMatrixArray());
               rowmax = TMath::Max(rowmax,vcol[jmax]);
            }
            if (absakk >= alpha*colmax*(colmax/rowmax)) {
               
               kp = k;
            } else if( TMath::Abs(diag(imax)) >= alpha*rowmax) {
               
               kp = imax;
            } else {
               
               kp = imax;
               kstep = 2;
            }
         }
         const Int_t kk = k-kstep+1;
         if (kp != kk) {
            
            Double_t *c_kk = pU+kk;
            Double_t *c_kp = pU+kp;
            for (Int_t irow = 0; irow < kp; irow++) {
               const Double_t t = *c_kk;
               *c_kk = *c_kp;
               *c_kp = t;
               c_kk += n;
               c_kp += n;
            }
            c_kk = pU+(kp+1)*n+kk;
            Double_t *r_kp = pU+kp*n+kp+1;
            for (Int_t icol = 0; icol < kk-kp-1; icol++) {
               const Double_t t = *c_kk;
               *c_kk = *r_kp;
               *r_kp = t;
               c_kk += n;
               r_kp += 1;
            }
            Double_t t = diag(kk);
            diag(kk) = diag(kp);
            diag(kp) = t;
            if (kstep == 2) {
               t = pU[(k-1)*n+k];
               pU[(k-1)*n+k] = pU[kp*n+k];
               pU[kp*n+k]    = t;
            }
         }
         
         if (kstep == 1 && k > 0) {
            
            
            
            
            const Double_t r1 = 1./diag(k);
            TMatrixDSub sub1(fU,0,k-1,0,k-1);
            sub1.Rank1Update(TMatrixDColumn_const(fU,k),-r1);
            
            TMatrixDSub sub2(fU,0,k-1,k,k);
            sub2 *= r1;
         } else {
            
            
            
            
            
            
            if ( k > 1 ) {
                     Double_t *pU_k1 = pU+(k-1)*n;
                     Double_t d12    = pU_k1[k];
               const Double_t d22    = pU_k1[k-1]/d12;
               const Double_t d11    = diag(k)/d12;
               const Double_t t      = 1./(d11*d22-1.);
               d12 = t/d12;
               for (Int_t j = k-2; j >= 0; j--) {
                  Double_t *pU_j = pU+j*n;
                  const Double_t wkm1 = d12*(d11*pU_j[k-1]-pU_j[k]);
                  const Double_t wk   = d12*(d22*pU_j[k]-pU_j[k-1]);
                  for (Int_t i = j; i >= 0; i--) {
                     Double_t *pU_i = pU+i*n;
                     pU_i[j] -= (pU_i[k]*wk+pU_i[k-1]*wkm1);
                  }
                  pU_j[k]   = wk;
                  pU_j[k-1] = wkm1;
               }
            }
         }
         
         if (kstep == 1) {
            fIpiv[k] = (kp+1);
         } else {
            fIpiv[k]   = -(kp+1);
            fIpiv[k-1] = -(kp+1);
         }
      }
      k -= kstep;
   }
   if (!ok) SetBit(kSingular);
   else     SetBit(kDecomposed);
   fU.Shift(fRowLwb,fRowLwb);
   return ok;
}
void TDecompBK::SetMatrix(const TMatrixDSym &a)
{
   R__ASSERT(a.IsValid());
   ResetStatus();
   SetBit(kMatrixSet);
   fCondition = a.Norm1();
   if (fNIpiv != a.GetNcols()) {
      fNIpiv = a.GetNcols();
      delete [] fIpiv;
      fIpiv = new Int_t[fNIpiv];
      memset(fIpiv,0,fNIpiv*sizeof(Int_t));
   }
   const Int_t nRows = a.GetNrows();
   fColLwb = fRowLwb = a.GetRowLwb();
   fU.ResizeTo(nRows,nRows);
   memcpy(fU.GetMatrixArray(),a.GetMatrixArray(),nRows*nRows*sizeof(Double_t));
}
Bool_t TDecompBK::Solve(TVectorD &b)
{
   R__ASSERT(b.IsValid());
   if (TestBit(kSingular)) {
      Error("Solve()","Matrix is singular");
      return kFALSE;
   }
   if ( !TestBit(kDecomposed) ) {
      if (!Decompose()) {
         Error("Solve()","Decomposition failed");
         return kFALSE;
      }
   }
   if (fU.GetNrows() != b.GetNrows() || fU.GetRowLwb() != b.GetLwb()) {
      Error("Solve(TVectorD &","vector and matrix incompatible");
      return kFALSE;
   }
   const Int_t n = fU.GetNrows();
   TMatrixDDiag_const diag(fU);
   const Double_t *pU = fU.GetMatrixArray();
         Double_t *pb = b.GetMatrixArray();
   
   
   
   Int_t k = n-1;
   while (k >= 0) {
      if (fIpiv[k] > 0) {
         
         
         const Int_t kp = fIpiv[k]-1;
         if (kp != k) {
            const Double_t tmp = pb[k];
            pb[k]  = pb[kp];
            pb[kp] = tmp;
         }
         
         
         for (Int_t i = 0; i < k; i++)
            pb[i] -= pU[i*n+k]*pb[k];
         
         pb[k] /= diag(k);
         k--;
      } else {
         
         
         const Int_t kp = -fIpiv[k]-1;
         if (kp != k-1) {
            const Double_t tmp = pb[k-1];
            pb[k-1]  = pb[kp];
            pb[kp]   = tmp;
         }
         
         
         Int_t i;
         for (i = 0; i < k-1; i++)
            pb[i] -= pU[i*n+k]*pb[k];
         for (i = 0; i < k-1; i++)
            pb[i] -= pU[i*n+k-1]*pb[k-1];
         
         const Double_t *pU_k1 = pU+(k-1)*n;
         const Double_t ukm1k  = pU_k1[k];
         const Double_t ukm1   = pU_k1[k-1]/ukm1k;
         const Double_t uk     = diag(k)/ukm1k;
         const Double_t denom  = ukm1*uk-1.;
         const Double_t bkm1   = pb[k-1]/ukm1k;
         const Double_t bk     = pb[k]/ukm1k;
         pb[k-1] = (uk*bkm1-bk)/denom;
         pb[k]   = (ukm1*bk-bkm1)/denom;
         k -= 2;
      }
   }
   
   
   
   
   k = 0;
   while (k < n) {
      if (fIpiv[k] > 0) {
         
         
         
         for (Int_t i = 0; i < k; i++)
            pb[k] -= pU[i*n+k]*pb[i];
         
         const Int_t kp = fIpiv[k]-1;
         if (kp != k) {
            const Double_t tmp = pb[k];
            pb[k]  = pb[kp];
            pb[kp] = tmp;
         }
         k++;
      } else {
         
         
         
         Int_t i ;
         for (i = 0; i < k; i++)
            pb[k] -= pU[i*n+k]*pb[i];
         for (i = 0; i < k; i++)
            pb[k+1] -= pU[i*n+k+1]*pb[i];
         
         const Int_t kp = -fIpiv[k]-1;
         if (kp != k) {
            const Double_t tmp = pb[k];
            pb[k]  = pb[kp];
            pb[kp] = tmp;
         }
         k += 2;
      }
   }
   return kTRUE;
}
Bool_t TDecompBK::Solve(TMatrixDColumn &cb)
{
   TMatrixDBase *b = const_cast<TMatrixDBase *>(cb.GetMatrix());
   R__ASSERT(b->IsValid());
   if (TestBit(kSingular)) {
      Error("Solve()","Matrix is singular");
      return kFALSE;
   }
   if ( !TestBit(kDecomposed) ) {
      if (!Decompose()) {
         Error("Solve()","Decomposition failed");
         return kFALSE;
      }
   }
   if (fU.GetNrows() != b->GetNrows() || fU.GetRowLwb() != b->GetRowLwb()) {
      Error("Solve(TMatrixDColumn &","vector and matrix incompatible");
      return kFALSE;
   }
   const Int_t n = fU.GetNrows();
   TMatrixDDiag_const diag(fU);
   const Double_t *pU  = fU.GetMatrixArray();
         Double_t *pcb = cb.GetPtr();
   const Int_t     inc = cb.GetInc();
  
  
  
   Int_t k = n-1;
   while (k >= 0) {
      if (fIpiv[k] > 0) {
         
         
         const Int_t kp = fIpiv[k]-1;
         if (kp != k) {
            const Double_t tmp = pcb[k*inc];
            pcb[k*inc]  = pcb[kp*inc];
            pcb[kp*inc] = tmp;
         }
         
         
         for (Int_t i = 0; i < k; i++)
            pcb[i*inc] -= pU[i*n+k]*pcb[k*inc];
         
         pcb[k*inc] /= diag(k);
         k--;
      } else {
         
         
         const Int_t kp = -fIpiv[k]-1;
         if (kp != k-1) {
            const Double_t tmp = pcb[(k-1)*inc];
            pcb[(k-1)*inc] = pcb[kp*inc];
            pcb[kp*inc]    = tmp;
         }
         
         
         Int_t i;
         for (i = 0; i < k-1; i++)
            pcb[i*inc] -= pU[i*n+k]*pcb[k*inc];
         for (i = 0; i < k-1; i++)
            pcb[i*inc] -= pU[i*n+k-1]*pcb[(k-1)*inc];
         
         const Double_t *pU_k1 = pU+(k-1)*n;
         const Double_t ukm1k  = pU_k1[k];
         const Double_t ukm1   = pU_k1[k-1]/ukm1k;
         const Double_t uk     = diag(k)/ukm1k;
         const Double_t denom  = ukm1*uk-1.;
         const Double_t bkm1   = pcb[(k-1)*inc]/ukm1k;
         const Double_t bk     = pcb[k*inc]/ukm1k;
         pcb[(k-1)*inc] = (uk*bkm1-bk)/denom;
         pcb[k*inc]     = (ukm1*bk-bkm1)/denom;
         k -= 2;
      }
   }
   
   
   
   
   k = 0;
   while (k < n) {
      if (fIpiv[k] > 0) {
         
         
         
         for (Int_t i = 0; i < k; i++)
            pcb[k*inc] -= pU[i*n+k]*pcb[i*inc];
         
         const Int_t kp = fIpiv[k]-1;
         if (kp != k) {
            const Double_t tmp = pcb[k*inc];
            pcb[k*inc]  = pcb[kp*inc];
            pcb[kp*inc] = tmp;
         }
         k++;
      } else {
         
         
         
         Int_t i;
         for (i = 0; i < k; i++)
            pcb[k*inc] -= pU[i*n+k]*pcb[i*inc];
         for (i = 0; i < k; i++)
            pcb[(k+1)*inc] -= pU[i*n+k+1]*pcb[i*inc];
         
         const Int_t kp = -fIpiv[k]-1;
         if (kp != k) {
            const Double_t tmp = pcb[k*inc];
            pcb[k*inc]  = pcb[kp*inc];
            pcb[kp*inc] = tmp;
         }
         k += 2;
      }
   }
   return kTRUE;
}
Bool_t TDecompBK::Invert(TMatrixDSym &inv)
{
   if (inv.GetNrows() != GetNrows() || inv.GetRowLwb() != GetRowLwb()) {
      Error("Invert(TMatrixDSym &","Input matrix has wrong shape");
      return kFALSE;
   }
   inv.UnitMatrix();
   const Int_t colLwb = inv.GetColLwb();
   const Int_t colUpb = inv.GetColUpb();
   Bool_t status = kTRUE;
   for (Int_t icol = colLwb; icol <= colUpb && status; icol++) {
      TMatrixDColumn b(inv,icol);
      status &= Solve(b);
   }
   return status;
}
TMatrixDSym TDecompBK::Invert(Bool_t &status)
{
   const Int_t rowLwb = GetRowLwb();
   const Int_t rowUpb = rowLwb+GetNrows()-1;
   TMatrixDSym inv(rowLwb,rowUpb);
   inv.UnitMatrix();
   status = Invert(inv);
   return inv;
}
void TDecompBK::Print(Option_t *opt) const
{
   TDecompBase::Print(opt);
   printf("fIpiv:\n");
   for (Int_t i = 0; i < fNIpiv; i++)
      printf("[%d] = %d\n",i,fIpiv[i]);
   fU.Print("fU");
}
TDecompBK &TDecompBK::operator=(const TDecompBK &source)
{
   if (this != &source) {
      TDecompBase::operator=(source);
      fU.ResizeTo(source.fU);
      fU   = source.fU;
      if (fNIpiv != source.fNIpiv) {
         if (fIpiv)
            delete [] fIpiv;
         fNIpiv = source.fNIpiv;
         fIpiv = new Int_t[fNIpiv];
      }
      memcpy(fIpiv,source.fIpiv,fNIpiv*sizeof(Int_t));
   }
   return *this;
}
Last update: Thu Jan 17 08:47:49 2008
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.