TDecompQRH.cxx

Go to the documentation of this file.
00001 // @(#)root/matrix:$Id: TDecompQRH.cxx 22039 2008-02-07 05:48:31Z brun $
00002 // Authors: Fons Rademakers, Eddy Offermann  Dec 2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 ///////////////////////////////////////////////////////////////////////////
00013 //                                                                       //
00014 // QR Decomposition class                                                //
00015 //                                                                       //
00016 // Decompose  a general (m x n) matrix A into A = fQ fR H   where        //
00017 //                                                                       //
00018 //  fQ : (m x n) - orthogonal matrix                                     //
00019 //  fR : (n x n) - upper triangular matrix                               //
00020 //  H  : HouseHolder matrix which is stored through                      //
00021 //  fUp: (n) - vector with Householder up's                              //
00022 //  fW : (n) - vector with Householder beta's                            //
00023 //                                                                       //
00024 //  If row/column index of A starts at (rowLwb,colLwb) then              //
00025 //  the decomposed matrices start from :                                 //
00026 //  fQ  : (rowLwb,0)                                                     //
00027 //  fR  : (0,colLwb)                                                     //
00028 //  and the decomposed vectors start from :                              //
00029 //  fUp : (0)                                                            //
00030 //  fW  : (0)                                                            //
00031 //                                                                       //
00032 // Errors arise from formation of reflectors i.e. singularity .          //
00033 // Note it attempts to handle the cases where the nRow <= nCol .         //
00034 //                                                                       //
00035 ///////////////////////////////////////////////////////////////////////////
00036 
00037 #include "TDecompQRH.h"
00038 
00039 ClassImp(TDecompQRH)
00040 
00041 //______________________________________________________________________________
00042 TDecompQRH::TDecompQRH(Int_t nrows,Int_t ncols)
00043 {
00044 // Constructor for (nrows x ncols) matrix
00045 
00046    if (nrows < ncols) {
00047       Error("TDecompQRH(Int_t,Int_t","matrix rows should be >= columns");
00048       return;
00049    }
00050 
00051    fQ.ResizeTo(nrows,ncols);
00052    fR.ResizeTo(ncols,ncols);
00053    if (nrows <= ncols) {
00054       fW.ResizeTo(nrows);
00055       fUp.ResizeTo(nrows);
00056    } else {
00057       fW.ResizeTo(ncols);
00058       fUp.ResizeTo(ncols);
00059    }
00060 }
00061 
00062 //______________________________________________________________________________
00063 TDecompQRH::TDecompQRH(Int_t row_lwb,Int_t row_upb,Int_t col_lwb,Int_t col_upb)
00064 {
00065 // Constructor for ([row_lwb..row_upb] x [col_lwb..col_upb]) matrix
00066 
00067    const Int_t nrows = row_upb-row_lwb+1;
00068    const Int_t ncols = col_upb-col_lwb+1;
00069 
00070    if (nrows < ncols) {
00071       Error("TDecompQRH(Int_t,Int_t,Int_t,Int_t","matrix rows should be >= columns");
00072       return;
00073    }
00074 
00075    fRowLwb = row_lwb;
00076    fColLwb = col_lwb;
00077 
00078    fQ.ResizeTo(nrows,ncols);
00079    fR.ResizeTo(ncols,ncols);
00080    if (nrows <= ncols) {
00081       fW.ResizeTo(nrows);
00082       fUp.ResizeTo(nrows);
00083    } else {
00084       fW.ResizeTo(ncols);
00085       fUp.ResizeTo(ncols);
00086    }
00087 }
00088 
00089 //______________________________________________________________________________
00090 TDecompQRH::TDecompQRH(const TMatrixD &a,Double_t tol)
00091 {
00092 // Constructor for general matrix A .
00093 
00094    R__ASSERT(a.IsValid());
00095    if (a.GetNrows() < a.GetNcols()) {
00096       Error("TDecompQRH(const TMatrixD &","matrix rows should be >= columns");
00097       return;
00098    }
00099 
00100    SetBit(kMatrixSet);
00101    fCondition = a.Norm1();
00102    fTol = a.GetTol();
00103    if (tol > 0.0)
00104       fTol = tol;
00105 
00106    fRowLwb = a.GetRowLwb();
00107    fColLwb = a.GetColLwb();
00108    const Int_t nRow = a.GetNrows();
00109    const Int_t nCol = a.GetNcols();
00110 
00111    fQ.ResizeTo(nRow,nCol);
00112    memcpy(fQ.GetMatrixArray(),a.GetMatrixArray(),nRow*nCol*sizeof(Double_t));
00113    fR.ResizeTo(nCol,nCol);
00114    if (nRow <= nCol) {
00115       fW.ResizeTo(nRow);
00116       fUp.ResizeTo(nRow);
00117    } else {
00118       fW.ResizeTo(nCol);
00119       fUp.ResizeTo(nCol);
00120    }
00121 }
00122 
00123 //______________________________________________________________________________
00124 TDecompQRH::TDecompQRH(const TDecompQRH &another) : TDecompBase(another)
00125 {
00126 // Copy constructor
00127 
00128    *this = another;
00129 }
00130 
00131 //______________________________________________________________________________
00132 Bool_t TDecompQRH::Decompose()
00133 {
00134 // QR decomposition of matrix a by Householder transformations,
00135 //  see Golub & Loan first edition p41 & Sec 6.2.
00136 // First fR is returned in upper triang of fQ and diagR. fQ returned in
00137 // 'u-form' in lower triang of fQ and fW, the latter containing the
00138 //  "Householder betas".
00139 // If the decomposition succeeds, bit kDecomposed is set , otherwise kSingular
00140 
00141    if (TestBit(kDecomposed)) return kTRUE;
00142 
00143    if ( !TestBit(kMatrixSet) ) {
00144       Error("Decompose()","Matrix has not been set");
00145       return kFALSE;
00146    }
00147 
00148    const Int_t nRow   = this->GetNrows();
00149    const Int_t nCol   = this->GetNcols();
00150    const Int_t rowLwb = this->GetRowLwb();
00151    const Int_t colLwb = this->GetColLwb();
00152 
00153    TVectorD diagR;
00154    Double_t work[kWorkMax];
00155    if (nCol > kWorkMax) diagR.ResizeTo(nCol);
00156    else                 diagR.Use(nCol,work);
00157 
00158    if (QRH(fQ,diagR,fUp,fW,fTol)) {
00159       for (Int_t i = 0; i < nRow; i++) {
00160          const Int_t ic = (i < nCol) ? i : nCol;
00161          for (Int_t j = ic ; j < nCol; j++)
00162             fR(i,j) = fQ(i,j);
00163       }
00164       TMatrixDDiag diag(fR); diag = diagR;
00165 
00166       fQ.Shift(rowLwb,0);
00167       fR.Shift(0,colLwb);
00168 
00169       SetBit(kDecomposed);
00170    }
00171 
00172    return kTRUE;
00173 }
00174 
00175 //______________________________________________________________________________
00176 Bool_t TDecompQRH::QRH(TMatrixD &q,TVectorD &diagR,TVectorD &up,TVectorD &w,Double_t tol)
00177 {
00178 // Decomposition function .
00179 
00180    const Int_t nRow = q.GetNrows();
00181    const Int_t nCol = q.GetNcols();
00182 
00183    const Int_t n = (nRow <= nCol) ? nRow-1 : nCol;
00184 
00185    for (Int_t k = 0 ; k < n ; k++) {
00186       const TVectorD qc_k = TMatrixDColumn_const(q,k);
00187       if (!DefHouseHolder(qc_k,k,k+1,up(k),w(k),tol))
00188          return kFALSE;
00189       diagR(k) = qc_k(k)-up(k);
00190       if (k < nCol-1) {
00191          // Apply HouseHolder to sub-matrix
00192          for (Int_t j = k+1; j < nCol; j++) {
00193             TMatrixDColumn qc_j = TMatrixDColumn(q,j);
00194             ApplyHouseHolder(qc_k,up(k),w(k),k,k+1,qc_j);
00195          }
00196       }
00197    }
00198 
00199    if (nRow <= nCol) {
00200       diagR(nRow-1) = q(nRow-1,nRow-1);
00201       up(nRow-1) = 0;
00202       w(nRow-1)  = 0;
00203    }
00204 
00205    return kTRUE;
00206 }
00207 
00208 //______________________________________________________________________________
00209 void TDecompQRH::SetMatrix(const TMatrixD &a)
00210 {
00211 // Set matrix to be decomposed
00212 
00213    R__ASSERT(a.IsValid());
00214 
00215    ResetStatus();
00216    if (a.GetNrows() < a.GetNcols()) {
00217       Error("TDecompQRH(const TMatrixD &","matrix rows should be >= columns");
00218       return;
00219    }
00220 
00221    SetBit(kMatrixSet);
00222    fCondition = a.Norm1();
00223 
00224    fRowLwb = a.GetRowLwb();
00225    fColLwb = a.GetColLwb();
00226    const Int_t nRow = a.GetNrows();
00227    const Int_t nCol = a.GetNcols();
00228 
00229    fQ.ResizeTo(nRow,nCol);
00230    memcpy(fQ.GetMatrixArray(),a.GetMatrixArray(),nRow*nCol*sizeof(Double_t));
00231    fR.ResizeTo(nCol,nCol);
00232    if (nRow <= nCol) {
00233       fW.ResizeTo(nRow);
00234       fUp.ResizeTo(nRow);
00235    } else {
00236       fW.ResizeTo(nCol);
00237       fUp.ResizeTo(nCol);
00238    }
00239 }
00240 
00241 //______________________________________________________________________________
00242 Bool_t TDecompQRH::Solve(TVectorD &b)
00243 {
00244 // Solve Ax=b assuming the QR form of A is stored in fR,fQ and fW, but assume b
00245 // has *not* been transformed.  Solution returned in b.
00246 
00247    R__ASSERT(b.IsValid());
00248    if (TestBit(kSingular)) {
00249       Error("Solve()","Matrix is singular");
00250       return kFALSE;
00251    }
00252    if ( !TestBit(kDecomposed) ) {
00253       if (!Decompose()) {
00254          Error("Solve()","Decomposition failed");
00255          return kFALSE;
00256       }
00257    }
00258 
00259    if (fQ.GetNrows() != b.GetNrows() || fQ.GetRowLwb() != b.GetLwb()) {
00260       Error("Solve(TVectorD &","vector and matrix incompatible");
00261       return kFALSE;
00262    }
00263 
00264    const Int_t nQRow = fQ.GetNrows();
00265    const Int_t nQCol = fQ.GetNcols();
00266 
00267    // Calculate  Q^T.b
00268    const Int_t nQ = (nQRow <= nQCol) ? nQRow-1 : nQCol;
00269    for (Int_t k = 0; k < nQ; k++) {
00270       const TVectorD qc_k = TMatrixDColumn_const(fQ,k);
00271       ApplyHouseHolder(qc_k,fUp(k),fW(k),k,k+1,b);
00272    }
00273 
00274    const Int_t nRCol = fR.GetNcols();
00275 
00276    const Double_t *pR = fR.GetMatrixArray();
00277          Double_t *pb = b.GetMatrixArray();
00278 
00279    // Backward substitution
00280    for (Int_t i = nRCol-1; i >= 0; i--) {
00281       const Int_t off_i = i*nRCol;
00282       Double_t r = pb[i];
00283       for (Int_t j = i+1; j < nRCol; j++)
00284          r -= pR[off_i+j]*pb[j];
00285       if (TMath::Abs(pR[off_i+i]) < fTol)
00286       {
00287          Error("Solve(TVectorD &)","R[%d,%d]=%.4e < %.4e",i,i,pR[off_i+i],fTol);
00288          return kFALSE;
00289       }
00290       pb[i] = r/pR[off_i+i];
00291    }
00292 
00293    return kTRUE;
00294 }
00295 
00296 //______________________________________________________________________________
00297 Bool_t TDecompQRH::Solve(TMatrixDColumn &cb)
00298 {
00299 // Solve Ax=b assuming the QR form of A is stored in fR,fQ and fW, but assume b
00300 // has *not* been transformed.  Solution returned in b.
00301 
00302    TMatrixDBase *b = const_cast<TMatrixDBase *>(cb.GetMatrix());
00303    R__ASSERT(b->IsValid());
00304    if (TestBit(kSingular)) {
00305       Error("Solve()","Matrix is singular");
00306       return kFALSE;
00307    }
00308    if ( !TestBit(kDecomposed) ) {
00309       if (!Decompose()) {
00310          Error("Solve()","Decomposition failed");
00311          return kFALSE;
00312       }
00313    }
00314 
00315    if (fQ.GetNrows() != b->GetNrows() || fQ.GetRowLwb() != b->GetRowLwb())
00316    {
00317       Error("Solve(TMatrixDColumn &","vector and matrix incompatible");
00318       return kFALSE;
00319    }
00320 
00321    const Int_t nQRow = fQ.GetNrows();
00322    const Int_t nQCol = fQ.GetNcols();
00323 
00324    // Calculate  Q^T.b
00325    const Int_t nQ = (nQRow <= nQCol) ? nQRow-1 : nQCol;
00326    for (Int_t k = 0; k < nQ; k++) {
00327       const TVectorD qc_k = TMatrixDColumn_const(fQ,k);
00328       ApplyHouseHolder(qc_k,fUp(k),fW(k),k,k+1,cb);
00329    }
00330 
00331    const Int_t nRCol = fR.GetNcols();
00332 
00333    const Double_t *pR  = fR.GetMatrixArray();
00334          Double_t *pcb = cb.GetPtr();
00335    const Int_t     inc = cb.GetInc();
00336 
00337    // Backward substitution
00338    for (Int_t i = nRCol-1; i >= 0; i--) {
00339       const Int_t off_i  = i*nRCol;
00340       const Int_t off_i2 = i*inc;
00341       Double_t r = pcb[off_i2];
00342       for (Int_t j = i+1; j < nRCol; j++)
00343          r -= pR[off_i+j]*pcb[j*inc];
00344       if (TMath::Abs(pR[off_i+i]) < fTol)
00345       {
00346          Error("Solve(TMatrixDColumn &)","R[%d,%d]=%.4e < %.4e",i,i,pR[off_i+i],fTol);
00347          return kFALSE;
00348       }
00349       pcb[off_i2] = r/pR[off_i+i];
00350    }
00351 
00352    return kTRUE;
00353 }
00354 
00355 //______________________________________________________________________________
00356 Bool_t TDecompQRH::TransSolve(TVectorD &b)
00357 {
00358 // Solve A^T x=b assuming the QR form of A is stored in fR,fQ and fW, but assume b
00359 // has *not* been transformed.  Solution returned in b.
00360 
00361    R__ASSERT(b.IsValid());
00362    if (TestBit(kSingular)) {
00363       Error("TransSolve()","Matrix is singular");
00364       return kFALSE;
00365    }
00366    if ( !TestBit(kDecomposed) ) {
00367       if (!Decompose()) {
00368          Error("TransSolve()","Decomposition failed");
00369          return kFALSE;
00370       }
00371    }
00372 
00373    if (fQ.GetNrows() != fQ.GetNcols() || fQ.GetRowLwb() != fQ.GetColLwb()) {
00374       Error("TransSolve(TVectorD &","matrix should be square");
00375       return kFALSE;
00376    }
00377 
00378    if (fR.GetNrows() != b.GetNrows() || fR.GetRowLwb() != b.GetLwb()) {
00379       Error("TransSolve(TVectorD &","vector and matrix incompatible");
00380       return kFALSE;
00381    }
00382 
00383    const Double_t *pR = fR.GetMatrixArray();
00384          Double_t *pb = b.GetMatrixArray();
00385 
00386    const Int_t nRCol = fR.GetNcols();
00387 
00388    // Backward substitution
00389    for (Int_t i = 0; i < nRCol; i++) {
00390       const Int_t off_i = i*nRCol;
00391       Double_t r = pb[i];
00392       for (Int_t j = 0; j < i; j++) {
00393          const Int_t off_j = j*nRCol;
00394          r -= pR[off_j+i]*pb[j];
00395       }
00396       if (TMath::Abs(pR[off_i+i]) < fTol)
00397       {
00398          Error("TransSolve(TVectorD &)","R[%d,%d]=%.4e < %.4e",i,i,pR[off_i+i],fTol);
00399          return kFALSE;
00400       }
00401       pb[i] = r/pR[off_i+i];
00402    }
00403 
00404    const Int_t nQRow = fQ.GetNrows();
00405 
00406    // Calculate  Q.b; it was checked nQRow == nQCol
00407    for (Int_t k = nQRow-1; k >= 0; k--) {
00408       const TVectorD qc_k = TMatrixDColumn_const(fQ,k);
00409       ApplyHouseHolder(qc_k,fUp(k),fW(k),k,k+1,b);
00410    }
00411 
00412    return kTRUE;
00413 }
00414 
00415 //______________________________________________________________________________
00416 Bool_t TDecompQRH::TransSolve(TMatrixDColumn &cb)
00417 {
00418 // Solve A^T x=b assuming the QR form of A is stored in fR,fQ and fW, but assume b
00419 // has *not* been transformed.  Solution returned in b.
00420 
00421    TMatrixDBase *b = const_cast<TMatrixDBase *>(cb.GetMatrix());
00422    R__ASSERT(b->IsValid());
00423    if (TestBit(kSingular)) {
00424       Error("TransSolve()","Matrix is singular");
00425       return kFALSE;
00426    }
00427    if ( !TestBit(kDecomposed) ) {
00428       if (!Decompose()) {
00429          Error("TransSolve()","Decomposition failed");
00430          return kFALSE;
00431       }
00432    }
00433 
00434    if (fQ.GetNrows() != fQ.GetNcols() || fQ.GetRowLwb() != fQ.GetColLwb()) {
00435       Error("TransSolve(TMatrixDColumn &","matrix should be square");
00436       return kFALSE;
00437    }
00438 
00439    if (fR.GetNrows() != b->GetNrows() || fR.GetRowLwb() != b->GetRowLwb()) {
00440       Error("TransSolve(TMatrixDColumn &","vector and matrix incompatible");
00441       return kFALSE;
00442    }
00443 
00444    const Double_t *pR  = fR.GetMatrixArray();
00445          Double_t *pcb = cb.GetPtr();
00446    const Int_t     inc = cb.GetInc();
00447 
00448    const Int_t nRCol = fR.GetNcols();
00449 
00450    // Backward substitution
00451    for (Int_t i = 0; i < nRCol; i++) {
00452       const Int_t off_i  = i*nRCol;
00453       const Int_t off_i2 = i*inc;
00454       Double_t r = pcb[off_i2];
00455       for (Int_t j = 0; j < i; j++) {
00456          const Int_t off_j = j*nRCol;
00457          r -= pR[off_j+i]*pcb[j*inc];
00458       }
00459       if (TMath::Abs(pR[off_i+i]) < fTol)
00460       {
00461          Error("TransSolve(TMatrixDColumn &)","R[%d,%d]=%.4e < %.4e",i,i,pR[off_i+i],fTol);
00462          return kFALSE;
00463       }
00464       pcb[off_i2] = r/pR[off_i+i];
00465    }
00466 
00467    const Int_t nQRow = fQ.GetNrows();
00468 
00469    // Calculate  Q.b; it was checked nQRow == nQCol
00470    for (Int_t k = nQRow-1; k >= 0; k--) {
00471       const TVectorD qc_k = TMatrixDColumn_const(fQ,k);
00472       ApplyHouseHolder(qc_k,fUp(k),fW(k),k,k+1,cb);
00473    }
00474 
00475    return kTRUE;
00476 }
00477 
00478 //______________________________________________________________________________
00479 void TDecompQRH::Det(Double_t &d1,Double_t &d2)
00480 {
00481 // This routine calculates the absolute (!) value of the determinant
00482 // |det| = d1*TMath::Power(2.,d2)
00483 
00484    if ( !TestBit(kDetermined) ) {
00485       if ( !TestBit(kDecomposed) )
00486         Decompose();
00487       if (TestBit(kSingular)) {
00488          fDet1 = 0.0;
00489          fDet2 = 0.0;
00490       } else
00491          TDecompBase::Det(d1,d2);
00492       SetBit(kDetermined);
00493    }
00494    d1 = fDet1;
00495    d2 = fDet2;
00496 }
00497 
00498 //______________________________________________________________________________
00499 Bool_t TDecompQRH::Invert(TMatrixD &inv)
00500 {
00501 // For a matrix A(m,n), its inverse A_inv is defined as A * A_inv = A_inv * A = unit
00502 // The user should always supply a matrix of size (m x m) !
00503 // If m > n , only the (n x m) part of the returned (pseudo inverse) matrix
00504 // should be used .
00505 
00506    if (inv.GetNrows()  != GetNrows()  || inv.GetNcols()  != GetNrows() ||
00507        inv.GetRowLwb() != GetRowLwb() || inv.GetColLwb() != GetColLwb()) {
00508       Error("Invert(TMatrixD &","Input matrix has wrong shape");
00509       return kFALSE;
00510    }
00511 
00512    inv.UnitMatrix();
00513    const Bool_t status = MultiSolve(inv);
00514 
00515    return status;
00516 }
00517 
00518 //______________________________________________________________________________
00519 TMatrixD TDecompQRH::Invert(Bool_t &status)
00520 {
00521 // For a matrix A(m,n), its inverse A_inv is defined as A * A_inv = A_inv * A = unit
00522 // (n x m) Ainv is returned .
00523 
00524    const Int_t rowLwb = GetRowLwb();
00525    const Int_t colLwb = GetColLwb();
00526    const Int_t rowUpb = rowLwb+GetNrows()-1;
00527    TMatrixD inv(rowLwb,rowUpb,colLwb,colLwb+GetNrows()-1);
00528    inv.UnitMatrix();
00529    status = MultiSolve(inv);
00530    inv.ResizeTo(rowLwb,rowLwb+GetNcols()-1,colLwb,colLwb+GetNrows()-1);
00531 
00532    return inv;
00533 }
00534 
00535 //______________________________________________________________________________
00536 void TDecompQRH::Print(Option_t *opt) const
00537 {
00538 // Print the class members
00539 
00540    TDecompBase::Print(opt);
00541    fQ.Print("fQ");
00542    fR.Print("fR");
00543    fUp.Print("fUp");
00544    fW.Print("fW");
00545 }
00546 
00547 //______________________________________________________________________________
00548 TDecompQRH &TDecompQRH::operator=(const TDecompQRH &source)
00549 {
00550 // Assignment operator
00551 
00552    if (this != &source) {
00553       TDecompBase::operator=(source);
00554       fQ.ResizeTo(source.fQ);
00555       fR.ResizeTo(source.fR);
00556       fUp.ResizeTo(source.fUp);
00557       fW.ResizeTo(source.fW);
00558       fQ  = source.fQ;
00559       fR  = source.fR;
00560       fUp = source.fUp;
00561       fW  = source.fW;
00562    }
00563    return *this;
00564 }

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