52 TDecompSVD::TDecompSVD(Int_t nrows,Int_t ncols)
55 Error(
"TDecompSVD(Int_t,Int_t",
"matrix rows should be >= columns");
58 fU.ResizeTo(nrows,nrows);
60 fV.ResizeTo(nrows,ncols);
66 TDecompSVD::TDecompSVD(Int_t row_lwb,Int_t row_upb,Int_t col_lwb,Int_t col_upb)
68 const Int_t nrows = row_upb-row_lwb+1;
69 const Int_t ncols = col_upb-col_lwb+1;
72 Error(
"TDecompSVD(Int_t,Int_t,Int_t,Int_t",
"matrix rows should be >= columns");
77 fU.ResizeTo(nrows,nrows);
79 fV.ResizeTo(nrows,ncols);
85 TDecompSVD::TDecompSVD(
const TMatrixD &a,Double_t tol)
87 R__ASSERT(a.IsValid());
88 if (a.GetNrows() < a.GetNcols()) {
89 Error(
"TDecompSVD(const TMatrixD &",
"matrix rows should be >= columns");
98 fRowLwb = a.GetRowLwb();
99 fColLwb = a.GetColLwb();
100 const Int_t nRow = a.GetNrows();
101 const Int_t nCol = a.GetNcols();
103 fU.ResizeTo(nRow,nRow);
105 fV.ResizeTo(nRow,nCol);
108 memcpy(fV.GetMatrixArray(),a.GetMatrixArray(),nRow*nCol*
sizeof(Double_t));
114 TDecompSVD::TDecompSVD(
const TDecompSVD &another): TDecompBase(another)
123 Bool_t TDecompSVD::Decompose()
125 if (TestBit(kDecomposed))
return kTRUE;
127 if ( !TestBit(kMatrixSet) ) {
128 Error(
"Decompose()",
"Matrix has not been set");
132 const Int_t nCol = this->GetNcols();
133 const Int_t rowLwb = this->GetRowLwb();
134 const Int_t colLwb = this->GetColLwb();
137 Double_t work[kWorkMax];
138 if (nCol > kWorkMax) offDiag.ResizeTo(nCol);
139 else offDiag.Use(nCol,work);
142 if (!Bidiagonalize(fV,fU,fSig,offDiag))
146 if (!Diagonalize(fV,fU,fSig,offDiag))
150 SortSingular(fV,fU,fSig);
151 fV.ResizeTo(nCol,nCol); fV.Shift(colLwb,colLwb);
153 fU.Transpose(fU); fU.Shift(rowLwb,colLwb);
192 Bool_t TDecompSVD::Bidiagonalize(TMatrixD &v,TMatrixD &u,TVectorD &sDiag,TVectorD &oDiag)
194 const Int_t nRow_v = v.GetNrows();
195 const Int_t nCol_v = v.GetNcols();
196 const Int_t nCol_u = u.GetNcols();
199 TArrayD betas(nCol_v);
201 for (Int_t i = 0; i < nCol_v; i++) {
205 if (i < nCol_v-1 || nRow_v > nCol_v) {
206 const TVectorD vc_i = TMatrixDColumn_const(v,i);
209 DefHouseHolder(vc_i,i,i+1,up,beta);
212 for (Int_t j = i; j < nCol_v; j++) {
213 TMatrixDColumn vc_j = TMatrixDColumn(v,j);
214 ApplyHouseHolder(vc_i,up,beta,i,i+1,vc_j);
218 for (Int_t j = 0; j < nCol_u; j++)
220 TMatrixDColumn uc_j = TMatrixDColumn(u,j);
221 ApplyHouseHolder(vc_i,up,beta,i,i+1,uc_j);
226 const TVectorD vr_i = TMatrixDRow_const(v,i);
230 DefHouseHolder(vr_i,i+1,i+2,up,beta);
237 for (Int_t j = i; j < nRow_v; j++) {
238 TMatrixDRow vr_j = TMatrixDRow(v,j);
239 ApplyHouseHolder(vr_i,up,beta,i+1,i+2,vr_j);
243 for (Int_t k = i+2; k < nCol_v; k++)
252 for (Int_t i = 1; i < nCol_v; i++)
256 sDiag = TMatrixDDiag(v);
260 TVectorD vr_i(nCol_v);
261 for (Int_t i = nCol_v-1; i >= 0; i--) {
263 vr_i = TMatrixDRow_const(v,i);
264 TMatrixDRow(v,i).Assign( 0.0 );
268 for (Int_t k = i; k < nCol_v; k++) {
270 TMatrixDColumn vc_k = TMatrixDColumn(v,k);
271 ApplyHouseHolder(vr_i,ups[i],betas[i],i+1,i+2,vc_k);
307 Bool_t TDecompSVD::Diagonalize(TMatrixD &v,TMatrixD &u,TVectorD &sDiag,TVectorD &oDiag)
311 Double_t bmx = sDiag(0);
313 const Int_t nCol_v = v.GetNcols();
316 for (Int_t i = 1; i < nCol_v; i++)
317 bmx = TMath::Max(TMath::Abs(sDiag(i))+TMath::Abs(oDiag(i)),bmx);
320 const Double_t eps = std::numeric_limits<double>::epsilon();
322 const Int_t niterm = 10*nCol_v;
323 for (Int_t k = nCol_v-1; k >= 0; k--) {
327 if (TMath::Abs(sDiag(k)) < eps*bmx)
328 Diag_1(v,sDiag,oDiag,k);
337 for (Int_t ll = k; ll >= 0 ; ll--) {
342 }
else if (TMath::Abs(oDiag(l)) < eps*bmx) {
345 }
else if (TMath::Abs(sDiag(l-1)) < eps*bmx)
348 if (l > 0 && !elzero)
349 Diag_2(sDiag,oDiag,k,l);
352 Diag_3(v,u,sDiag,oDiag,k,l);
354 if (niter <= niterm)
goto loop;
355 ::Error(
"TDecompSVD::Diagonalize",
"no convergence after %d steps",niter);
362 sDiag(k) = -sDiag(k);
363 TMatrixDColumn(v,k) *= -1.0;
374 void TDecompSVD::Diag_1(TMatrixD &v,TVectorD &sDiag,TVectorD &oDiag,Int_t k)
376 const Int_t nCol_v = v.GetNcols();
378 TMatrixDColumn vc_k = TMatrixDColumn(v,k);
379 for (Int_t i = k-1; i >= 0; i--) {
380 TMatrixDColumn vc_i = TMatrixDColumn(v,i);
383 DefAplGivens(sDiag[i],oDiag[i+1],cs,sn);
385 DefAplGivens(sDiag[i],h,cs,sn);
388 ApplyGivens(oDiag[i],h,cs,sn);
390 for (Int_t j = 0; j < nCol_v; j++)
391 ApplyGivens(vc_i(j),vc_k(j),cs,sn);
398 void TDecompSVD::Diag_2(TVectorD &sDiag,TVectorD &oDiag,Int_t k,Int_t l)
400 for (Int_t i = l; i <= k; i++) {
403 DefAplGivens(sDiag(i),oDiag(i),cs,sn);
405 DefAplGivens(sDiag(i),h,cs,sn);
408 ApplyGivens(oDiag(i+1),h,cs,sn);
416 void TDecompSVD::Diag_3(TMatrixD &v,TMatrixD &u,TVectorD &sDiag,TVectorD &oDiag,Int_t k,Int_t l)
418 Double_t *pS = sDiag.GetMatrixArray();
419 Double_t *pO = oDiag.GetMatrixArray();
423 const Double_t psk1 = pS[k-1];
424 const Double_t psk = pS[k];
425 const Double_t pok1 = pO[k-1];
426 const Double_t pok = pO[k];
427 const Double_t psl = pS[l];
430 if (psl == 0.0 || pok == 0.0 || psk1 == 0.0) {
431 const Double_t b = ((psk1-psk)*(psk1+psk)+pok1*pok1)/2.0;
432 const Double_t c = (psk*pok1)*(psk*pok1);
434 Double_t shift = 0.0;
435 if ((b != 0.0) | (c != 0.0)) {
436 shift = TMath::Sqrt(b*b+c);
442 f = (psl+psk)*(psl-psk)+shift;
444 f = ((psk1-psk)*(psk1+psk)+(pok1-pok)*(pok1+pok))/(2.*pok*psk1);
445 const Double_t g = TMath::Hypot(1.,f);
446 const Double_t t = (f >= 0.) ? f+g : f-g;
448 f = ((psl-psk)*(psl+psk)+pok*(psk1/t-pok))/psl;
451 const Int_t nCol_v = v.GetNcols();
452 const Int_t nCol_u = u.GetNcols();
456 for (Int_t i = l; i <= k-1; i++) {
459 DefGivens(f,pO[i+1],cs,sn);
462 DefAplGivens(pO[i],h,cs,sn);
464 ApplyGivens(pS[i],pO[i+1],cs,sn);
466 ApplyGivens(h,pS[i+1],cs,sn);
468 TMatrixDColumn vc_i = TMatrixDColumn(v,i);
469 TMatrixDColumn vc_i1 = TMatrixDColumn(v,i+1);
470 for (j = 0; j < nCol_v; j++)
471 ApplyGivens(vc_i(j),vc_i1(j),cs,sn);
473 DefAplGivens(pS[i],h,cs,sn);
474 ApplyGivens(pO[i+1],pS[i+1],cs,sn);
477 ApplyGivens(h,pO[i+2],cs,sn);
480 TMatrixDRow ur_i = TMatrixDRow(u,i);
481 TMatrixDRow ur_i1 = TMatrixDRow(u,i+1);
482 for (j = 0; j < nCol_u; j++)
483 ApplyGivens(ur_i(j),ur_i1(j),cs,sn);
497 void TDecompSVD::SortSingular(TMatrixD &v,TMatrixD &u,TVectorD &sDiag)
499 const Int_t nCol_v = v.GetNcols();
500 const Int_t nCol_u = u.GetNcols();
502 Double_t *pS = sDiag.GetMatrixArray();
503 Double_t *pV = v.GetMatrixArray();
504 Double_t *pU = u.GetMatrixArray();
511 Bool_t found = kFALSE;
513 while (!found && i < nCol_v) {
520 for (i = 1; i < nCol_v; i++) {
521 Double_t t = pS[i-1];
523 for (j = i; j < nCol_v; j++) {
534 for (j = 0; j < nCol_v; j++) {
535 const Int_t off_j = j*nCol_v;
537 pV[off_j+k] = pV[off_j+i-1];
541 for (j = 0; j < nCol_u; j++) {
542 const Int_t off_k = k*nCol_u;
543 const Int_t off_i1 = (i-1)*nCol_u;
545 pU[off_k+j] = pU[off_i1+j];
557 const TMatrixD TDecompSVD::GetMatrix()
559 if (TestBit(kSingular)) {
560 Error(
"GetMatrix()",
"Matrix is singular");
563 if ( !TestBit(kDecomposed) ) {
565 Error(
"GetMatrix()",
"Decomposition failed");
570 const Int_t nRows = fU.GetNrows();
571 const Int_t nCols = fV.GetNcols();
572 const Int_t colLwb = this->GetColLwb();
573 TMatrixD s(nRows,nCols); s.Shift(colLwb,colLwb);
574 TMatrixDDiag diag(s); diag = fSig;
575 const TMatrixD vt(TMatrixD::kTransposed,fV);
582 void TDecompSVD::SetMatrix(
const TMatrixD &a)
584 R__ASSERT(a.IsValid());
587 if (a.GetNrows() < a.GetNcols()) {
588 Error(
"TDecompSVD(const TMatrixD &",
"matrix rows should be >= columns");
595 fRowLwb = a.GetRowLwb();
596 fColLwb = a.GetColLwb();
597 const Int_t nRow = a.GetNrows();
598 const Int_t nCol = a.GetNcols();
600 fU.ResizeTo(nRow,nRow);
602 fV.ResizeTo(nRow,nCol);
605 memcpy(fV.GetMatrixArray(),a.GetMatrixArray(),nRow*nCol*
sizeof(Double_t));
615 Bool_t TDecompSVD::Solve(TVectorD &b)
617 R__ASSERT(b.IsValid());
618 if (TestBit(kSingular)) {
621 if ( !TestBit(kDecomposed) ) {
627 if (fU.GetNrows() != b.GetNrows() || fU.GetRowLwb() != b.GetLwb())
629 Error(
"Solve(TVectorD &",
"vector and matrix incompatible");
637 const Int_t lwb = fU.GetColLwb();
638 const Int_t upb = lwb+fV.GetNcols()-1;
639 const Double_t threshold = fSig(lwb)*fTol;
641 TVectorD tmp(lwb,upb);
642 for (Int_t irow = lwb; irow <= upb; irow++) {
644 if (fSig(irow) > threshold) {
645 const TVectorD uc_i = TMatrixDColumn(fU,irow);
652 if (b.GetNrows() > fV.GetNrows()) {
654 tmp2.Use(lwb,upb,b.GetMatrixArray());
670 Bool_t TDecompSVD::Solve(TMatrixDColumn &cb)
672 TMatrixDBase *b =
const_cast<TMatrixDBase *
>(cb.GetMatrix());
673 R__ASSERT(b->IsValid());
674 if (TestBit(kSingular)) {
677 if ( !TestBit(kDecomposed) ) {
683 if (fU.GetNrows() != b->GetNrows() || fU.GetRowLwb() != b->GetRowLwb())
685 Error(
"Solve(TMatrixDColumn &",
"vector and matrix incompatible");
693 const Int_t lwb = fU.GetColLwb();
694 const Int_t upb = lwb+fV.GetNcols()-1;
695 const Double_t threshold = fSig(lwb)*fTol;
697 TVectorD tmp(lwb,upb);
698 const TVectorD vb = cb;
699 for (Int_t irow = lwb; irow <= upb; irow++) {
701 if (fSig(irow) > threshold) {
702 const TVectorD uc_i = TMatrixDColumn(fU,irow);
709 if (b->GetNrows() > fV.GetNrows()) {
710 const TVectorD tmp2 = fV*tmp;
712 tmp3.SetSub(tmp2.GetLwb(),tmp2);
723 Bool_t TDecompSVD::TransSolve(TVectorD &b)
725 R__ASSERT(b.IsValid());
726 if (TestBit(kSingular)) {
729 if ( !TestBit(kDecomposed) ) {
735 if (fU.GetNrows() != fV.GetNrows() || fU.GetRowLwb() != fV.GetRowLwb()) {
736 Error(
"TransSolve(TVectorD &",
"matrix should be square");
740 if (fV.GetNrows() != b.GetNrows() || fV.GetRowLwb() != b.GetLwb())
742 Error(
"TransSolve(TVectorD &",
"vector and matrix incompatible");
750 const Int_t lwb = fU.GetColLwb();
751 const Int_t upb = lwb+fV.GetNcols()-1;
752 const Double_t threshold = fSig(lwb)*fTol;
754 TVectorD tmp(lwb,upb);
755 for (Int_t i = lwb; i <= upb; i++) {
757 if (fSig(i) > threshold) {
758 const TVectorD vc = TMatrixDColumn(fV,i);
772 Bool_t TDecompSVD::TransSolve(TMatrixDColumn &cb)
774 TMatrixDBase *b =
const_cast<TMatrixDBase *
>(cb.GetMatrix());
775 R__ASSERT(b->IsValid());
776 if (TestBit(kSingular)) {
779 if ( !TestBit(kDecomposed) ) {
785 if (fU.GetNrows() != fV.GetNrows() || fU.GetRowLwb() != fV.GetRowLwb()) {
786 Error(
"TransSolve(TMatrixDColumn &",
"matrix should be square");
790 if (fV.GetNrows() != b->GetNrows() || fV.GetRowLwb() != b->GetRowLwb())
792 Error(
"TransSolve(TMatrixDColumn &",
"vector and matrix incompatible");
800 const Int_t lwb = fU.GetColLwb();
801 const Int_t upb = lwb+fV.GetNcols()-1;
802 const Double_t threshold = fSig(lwb)*fTol;
804 const TVectorD vb = cb;
805 TVectorD tmp(lwb,upb);
806 for (Int_t i = lwb; i <= upb; i++) {
808 if (fSig(i) > threshold) {
809 const TVectorD vc = TMatrixDColumn(fV,i);
823 Double_t TDecompSVD::Condition()
825 if ( !TestBit(kCondition) ) {
827 if (TestBit(kSingular))
829 if ( !TestBit(kDecomposed) ) {
833 const Int_t colLwb = GetColLwb();
834 const Int_t nCols = GetNcols();
835 const Double_t max = fSig(colLwb);
836 const Double_t min = fSig(colLwb+nCols-1);
837 fCondition = (min > 0.0) ? max/min : -1.0;
846 void TDecompSVD::Det(Double_t &d1,Double_t &d2)
848 if ( !TestBit(kDetermined) ) {
849 if ( !TestBit(kDecomposed) )
851 if (TestBit(kSingular)) {
855 DiagProd(fSig,fTol,fDet1,fDet2);
865 Int_t TDecompSVD::GetNrows ()
const
867 return fU.GetNrows();
870 Int_t TDecompSVD::GetNcols ()
const
872 return fV.GetNcols();
881 Bool_t TDecompSVD::Invert(TMatrixD &inv)
883 const Int_t rowLwb = GetRowLwb();
884 const Int_t colLwb = GetColLwb();
885 const Int_t nRows = fU.GetNrows();
887 if (inv.GetNrows() != nRows || inv.GetNcols() != nRows ||
888 inv.GetRowLwb() != rowLwb || inv.GetColLwb() != colLwb) {
889 Error(
"Invert(TMatrixD &",
"Input matrix has wrong shape");
894 Bool_t status = MultiSolve(inv);
903 TMatrixD TDecompSVD::Invert(Bool_t &status)
905 const Int_t rowLwb = GetRowLwb();
906 const Int_t colLwb = GetColLwb();
907 const Int_t rowUpb = rowLwb+fU.GetNrows()-1;
908 TMatrixD inv(rowLwb,rowUpb,colLwb,colLwb+fU.GetNrows()-1);
910 status = MultiSolve(inv);
911 inv.ResizeTo(rowLwb,rowLwb+fV.GetNcols()-1,colLwb,colLwb+fU.GetNrows()-1);
919 void TDecompSVD::Print(Option_t *opt)
const
921 TDecompBase::Print(opt);
930 TDecompSVD &TDecompSVD::operator=(
const TDecompSVD &source)
932 if (
this != &source) {
933 TDecompBase::operator=(source);
934 fU.ResizeTo(source.fU);
936 fV.ResizeTo(source.fV);
938 fSig.ResizeTo(source.fSig);