00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef matrixMat_SOURCES
00027 #define matrixMat_SOURCES
00028
00029 #include "matrixMat.h"
00030
00031 #include <float.h>
00032
00035 namespace PLib {
00036
00048 template <class T>
00049 LUMatrix<T>& LUMatrix<T>::operator=(const LUMatrix<T>& a){
00050 resize(a.rows(),a.cols()) ;
00051 for(int i=0;i<rows();++i)
00052 for(int j=0;j<cols();++j)
00053 elem(i,j) = a(i,j) ;
00054 pivot_ = a.pivot_ ;
00055 return *this ;
00056 }
00057
00069 template <class T>
00070 LUMatrix<T>& LUMatrix<T>::decompose(const Matrix<T>& a)
00071 {
00072 int i, j, k, l, kp1, nm1, n;
00073 T t, q;
00074 double den, ten;
00075
00076 n = a.rows();
00077
00078 resize(n,n) ;
00079
00080 if(a.rows()!=a.cols()){
00081 #ifdef USE_EXCEPTION
00082 throw WrongSize2D(a.rows(),a.cols(),0,0) ;
00083 #else
00084 Error err("LUMatrix::decompose");
00085 err << "The a matrix is not squared!" ;
00086 err.fatal() ;
00087 #endif
00088 }
00089
00090
00091 for(i=0;i<n;++i)
00092 for(j=0;j<n;++j)
00093 elem(i,j) = a(i,j) ;
00094
00095 errval = 0;
00096 nm1 = n - 1;
00097 for (k = 0; k < n; k++)
00098 pivot_[k] = k ;
00099
00100 sign = 1 ;
00101
00102 if (nm1 >= 1)
00103 {
00104 for (k = 0; k < nm1; k++)
00105 {
00106 kp1 = k + 1;
00107
00108
00109 #ifdef COMPLEX_COMMENT
00110 ten = absolute(real(a(k,k)))+
00111 absolute(imag(a(k,k)));
00112 #else
00113 ten = absolute(a(k,k));
00114 #endif
00115 l = k;
00116 for (i = kp1; i < n; i++)
00117 {
00118 #ifdef COMPLEX_COMMENT
00119 den = absolute(real(a(i,k)))+
00120 absolute(imag(a(i,k)));
00121 #else
00122 den = absolute(a(i,k));
00123 #endif
00124 if ( den > ten )
00125 {
00126 ten = den;
00127 l = i;
00128 }
00129 }
00130 pivot_[k] = l;
00131
00132 if ( elem(l,k) != 0.0 )
00133 {
00134 if (l != k ){
00135 for (i = k; i < n; i++)
00136 {
00137 t = elem(l,i) ;
00138 elem(l,i) = elem(k,i) ;
00139 elem(k,i) = t ;
00140 }
00141 sign = -sign ;
00142 }
00143 q = elem(k,k);
00144 for (i = kp1; i < n; i++)
00145 {
00146 t = - elem(i,k)/q;
00147 elem(i,k) = t;
00148 for (j = kp1; j < n; j++)
00149 elem(i,j) += t * elem(k,j);
00150 }
00151 }
00152 else
00153 errval = k;
00154 }
00155
00156 }
00157
00158 pivot_[nm1] = nm1;
00159 if (elem(nm1,nm1) == 0.0)
00160 errval = nm1;
00161 return *this;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00197 template <class T>
00198 T LUMatrix<T>::determinant(){
00199 T det = elem(0,0) ;
00200 for(int i=1;i<rows();++i)
00201 det *= elem(i,i) ;
00202 return det * (T)sign ;
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00250 template <class T>
00251 void LUMatrix<T>::inverseIn(Matrix<T>& inv)
00252 {
00253 T ten;
00254 int i, j, k, l, kb, kp1, nm1, n, coln;
00255
00256 if ( rows() != cols() )
00257 {
00258 #ifdef USE_EXCEPTION
00259 throw WrongSize2D(rows(),cols(),0,0) ;
00260 #else
00261 Error error("invm");
00262 error << "matrix inverse, not square: " << rows() << " by " << cols() << endl;
00263 error.fatal();
00264 #endif
00265 }
00266
00267 n = coln = rows();
00268
00269
00270 inv = *this ;
00271
00272 nm1 = n - 1;
00273
00274
00275 for (k = 0; k < n; k++)
00276 {
00277 inv(k,k) = ten = 1.0 / inv(k,k) ;
00278 ten = -ten;
00279 for (i = 0; i < k; i++)
00280 inv(i,k) *= ten;
00281 kp1 = k + 1;
00282 if (nm1 >= kp1)
00283 {
00284 for (j = kp1; j < n; j++)
00285 {
00286 ten = inv(k,j) ;
00287 inv(k,j) = 0.0 ;
00288 for (i = 0; i < kp1; i++)
00289 inv(i,j) += ten * inv(i,k) ;
00290 }
00291 }
00292 }
00293
00294
00295 if (nm1 >= 1)
00296 {
00297 Vector<T> work(n) ;
00298
00299
00300 for (kb = 0; kb < nm1; kb++)
00301 {
00302 k = nm1 - kb - 1;
00303 kp1 = k + 1;
00304 for (i = kp1; i < n; i++)
00305 {
00306 work[i] = inv(i,k) ;
00307 inv(i,k) = 0.0;
00308 }
00309 for (j = kp1; j < n; j++)
00310 {
00311 ten = work[j];
00312 for (i = 0; i < n; i++)
00313 inv(i,k) += ten * inv(i,j) ;
00314 }
00315 l = pivot[k];
00316 if (l != k)
00317 for (i = 0; i < n; i++)
00318 {
00319 ten = inv(i,k) ;
00320 inv(i,k) = inv(i,l);
00321 inv(i,l) = ten;
00322 }
00323 }
00324
00325 }
00326 }
00327
00338 template <class T>
00339 Matrix<T> LUMatrix<T>::inverse()
00340 {
00341 if ( rows() != cols() )
00342 {
00343 #ifdef USE_EXCEPTION
00344 throw WrongSize2D(rows(),cols(),0,0) ;
00345 #else
00346 Error error("invm");
00347 error << "matrix inverse, not square: " << rows() << " by " << cols() << endl;
00348 error.fatal();
00349 #endif
00350 }
00351
00352 Matrix<T> inverse ;
00353 inverseIn(inverse) ;
00354
00355 return inverse;
00356 }
00357
00358
00359 template <class T>
00360 inline T sqr(T a){
00361 return a*a ;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 template <class T>
00423 double SVDMatrix<T>::left_householder(Matrix<T>& A, const int i)
00424 {
00425 int j,k;
00426 T scale = 0;
00427 for(k=i; k<M; k++)
00428 scale += absolute(A(k,i));
00429 if( scale == 0 )
00430 return 0;
00431 double Norm_sqr = 0;
00432 for(k=i; k<M; k++)
00433 Norm_sqr += sqr(A(k,i) /= scale);
00434 double new_Aii = sqrt(Norm_sqr);
00435 if( A(i,i) > 0 ) new_Aii = -new_Aii;
00436 const float beta = - A(i,i)*new_Aii + Norm_sqr;
00437 A(i,i) -= new_Aii;
00438
00439 for(j=i+1; j<N; j++)
00440 {
00441 T factor = 0;
00442 for(k=i; k<M; k++)
00443 factor += A(k,i) * A(k,j);
00444 factor /= beta;
00445 for(k=i; k<M; k++)
00446 A(k,j) -= A(k,i) * factor;
00447 }
00448
00449 for(j=0; j<M; j++)
00450 {
00451 T factor = 0;
00452 for(k=i; k<M; k++)
00453 factor += A(k,i) * U_(j,k);
00454 factor /= beta;
00455 for(k=i; k<M; k++)
00456 U_(j,k) -= A(k,i) * factor;
00457 }
00458 return new_Aii * scale;
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 template <class T>
00513 double SVDMatrix<T>::right_householder(Matrix<T>& A, const int i)
00514 {
00515 int j,k;
00516 T scale = 0;
00517 for(k=i+1; k<N; k++)
00518 scale += absolute(A(i,k));
00519 if( scale == 0 )
00520 return 0;
00521
00522 double Norm_sqr = 0;
00523 for(k=i+1; k<N; k++)
00524 Norm_sqr += sqr(A(i,k) /= scale);
00525 double new_Aii1 = sqrt(Norm_sqr);
00526 if( A(i,i+1) > 0 )
00527 new_Aii1 = -new_Aii1;
00528 const float beta = - A(i,i+1)*new_Aii1 + Norm_sqr;
00529 A(i,i+1) -= new_Aii1;
00530
00531 for(j=i+1; j<M; j++)
00532 {
00533 T factor = 0;
00534 for(k=i+1; k<N; k++)
00535 factor += A(i,k) * A(j,k);
00536 factor /= beta;
00537 for(k=i+1; k<N; k++)
00538 A(j,k) -= A(i,k) * factor;
00539 }
00540
00541 for(j=0; j<N; j++)
00542 {
00543 T factor = 0;
00544 for(k=i+1; k<N; k++)
00545 factor += A(i,k) * V_(j,k);
00546 factor /= beta;
00547 for(k=i+1; k<N; k++)
00548 V_(j,k) -= A(i,k) * factor;
00549 }
00550 return new_Aii1 * scale;
00551 }
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 template <class T>
00566 double SVDMatrix<T>::bidiagonalize(Vector<T>& super_diag, const Matrix<T>& _A)
00567 {
00568 double norm_acc = 0;
00569 super_diag[0] = 0;
00570 Matrix<T> A = _A;
00571 for(int i=0; i<N; i++)
00572 {
00573 const T& diagi = sig_[i] = left_householder(A,i);
00574 if( i < N-1 )
00575 super_diag[i+1] = right_householder(A,i);
00576 double t2 = absolute(diagi)+absolute(super_diag[i]) ;
00577 norm_acc = maximum(norm_acc,t2);
00578 }
00579 return norm_acc;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 template <class T>
00640 void SVDMatrix<T>::rotate(Matrix<T>& Mu, const int i, const int j,
00641 const double cos_ph, const double sin_ph)
00642 {
00643 for(int l=0; l<Mu.rows(); l++)
00644 {
00645 T& Uil = Mu(l,i); T& Ujl = Mu(l,j);
00646 const T Ujl_was = Ujl;
00647 Ujl = cos_ph*Ujl_was + sin_ph*Uil;
00648 Uil = -sin_ph*Ujl_was + cos_ph*Uil;
00649 }
00650 }
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 template <class T>
00666 void SVDMatrix<T>::rip_through(Vector<T>& super_diag, const int k, const int l, const double eps)
00667 {
00668 double cos_ph = 0, sin_ph = 1;
00669
00670
00671
00672
00673
00674
00675
00676
00677 for(int i=l; i<=k; i++)
00678 {
00679 const double f = sin_ph * super_diag[i];
00680 super_diag[i] *= cos_ph;
00681 if( absolute(f) <= eps )
00682 break;
00683 cos_ph = sig[i]; sin_ph = -f;
00684 const double norm = (sig_[i] = hypot(cos_ph,sin_ph));
00685 cos_ph /= norm, sin_ph /= norm;
00686 rotate(U_,i,l-1,cos_ph,sin_ph);
00687 }
00688 }
00689
00690
00691
00692
00693
00694
00695
00696 template <class T>
00697 int SVDMatrix<T>::get_submatrix_to_work_on(Vector<T>& super_diag, const int k, const double eps)
00698 {
00699 for(register int l=k; l>0; l--)
00700 if( absolute(super_diag[l]) <= eps )
00701 return l;
00702 else if( absolute(sig[l-1]) <= eps )
00703 {
00704 rip_through(super_diag,k,l,eps);
00705 return l;
00706 }
00707 return 0;
00708 }
00709
00710
00711 template <class T>
00712 void SVDMatrix<T>::diagonalize(Vector<T>& super_diag, const double eps)
00713 {
00714 for(register int k=N-1; k>=0; k--)
00715 {
00716 int l;
00717
00718
00719
00720 while(absolute(super_diag[k]) > eps)
00721 {
00722 l=get_submatrix_to_work_on(super_diag,k,eps) ;
00723 double shift;
00724 {
00725 T Jk2k1 = super_diag[k-1],
00726 Jk1k = super_diag[k],
00727 Jk1k1 = sig[k-1],
00728 Jkk = sig[k],
00729 Jll = sig[l];
00730 shift = (Jk1k1-Jkk)*(Jk1k1+Jkk) + (Jk2k1-Jk1k)*(Jk2k1+Jk1k);
00731 shift /= 2*Jk1k*Jk1k1;
00732 shift += (shift < 0 ? -1 : 1) * sqrt(shift*shift+1);
00733 shift = ( (Jll-Jkk)*(Jll+Jkk) + Jk1k*(Jk1k1/shift-Jk1k) )/Jll;
00734 }
00735
00736 double cos_th = 1, sin_th = 1;
00737 T Ji1i1 = sig[l];
00738 for(register int i=l+1; i<=k; i++)
00739 {
00740 T Ji1i = super_diag[i], Jii = sig[i];
00741 sin_th *= Ji1i; Ji1i *= cos_th; cos_th = shift;
00742 double norm_f = (super_diag[i-1] = hypot(cos_th,sin_th));
00743 cos_th /= norm_f, sin_th /= norm_f;
00744
00745 shift = cos_th*Ji1i1 + sin_th*Ji1i;
00746 Ji1i = -sin_th*Ji1i1 + cos_th*Ji1i;
00747 const double Jii1 = Jii*sin_th;
00748 Jii *= cos_th;
00749 rotate(V_,i,i-1,cos_th,sin_th);
00750
00751 double cos_ph = shift, sin_ph = Jii1;
00752 sig_[i-1] = (norm_f = hypot(cos_ph,sin_ph));
00753 if( norm_f == 0 )
00754 cos_ph = cos_th, sin_ph = sin_th;
00755 else
00756 cos_ph /= norm_f, sin_ph /= norm_f;
00757
00758 shift = cos_ph * Ji1i + sin_ph*Jii;
00759 Ji1i1 = -sin_ph*Ji1i + cos_ph*Jii;
00760
00761 rotate(U_,i,i-1,cos_ph,sin_ph);
00762
00763 cos_th = cos_ph, sin_th = sin_ph;
00764
00765
00766 }
00767 super_diag[l] = 0;
00768 super_diag[k] = shift;
00769 sig_[k] = Ji1i1;
00770 }
00771 if( sig[k] < 0 )
00772 {
00773 sig_[k] = -sig_[k];
00774 for(register int j=0; j<V_.rows(); j++)
00775 V_(j,k) = -V_(j,k);
00776 }
00777 }
00778 }
00779
00795 template <class T>
00796 SVDMatrix<T>::SVDMatrix(const Matrix<T>& A)
00797 : U(U_),V(V_),sig(sig_)
00798 {
00799 decompose(A) ;
00800 }
00801
00816 template <class T>
00817 int SVDMatrix<T>::decompose(const Matrix<T>& A){
00818 M = A.rows() ;
00819 N = A.cols() ;
00820
00821 if( M < N ){
00822 #ifdef USE_EXCEPTION
00823 throw WrongSize2D(A.rows(),A.cols(),0,0) ;
00824 #else
00825 Error err("SVD") ;
00826 err << "Matrix A should have at least as many rows() as it has columns";
00827 err.warning() ;
00828 #endif
00829 return 0 ;
00830 }
00831
00832 U_.resize(M,M) ;
00833 V_.resize(N,N) ;
00834 sig_.resize(N) ;
00835
00836 U_.diag(1) ;
00837 V_.diag(1) ;
00838
00839 Vector<T> super_diag(N);
00840 const double bidiag_norm = bidiagonalize(super_diag,A);
00841 const double eps = FLT_EPSILON * bidiag_norm;
00842 diagonalize(super_diag,eps);
00843
00844 return 1 ;
00845 }
00846
00847
00861 template <class T>
00862 void SVDMatrix<T>::minMax(T& min_sig, T& max_sig) const
00863 {
00864 max_sig = min_sig = sig[0];
00865 for(register int i=0; i<sig.n(); ++i)
00866 if( sig[i] > max_sig )
00867 max_sig = sig[i];
00868 else if( sig[i] < min_sig )
00869 min_sig = sig[i];
00870 }
00871
00885 template <class T>
00886 double SVDMatrix<T>::q_cond_number(void) const
00887 {
00888 T mins,maxs ;
00889 minMax(mins,maxs) ;
00890 return (maxs/mins);
00891 }
00892
00906 template <class T>
00907 void SVDMatrix<T>::inverseIn(Matrix<T>& A, double tau) {
00908 Matrix<T> S ;
00909
00910 T min_sig, max_sig ;
00911 minMax(min_sig,max_sig) ;
00912
00913 if(tau==0)
00914 tau = V.rows()*max_sig*FLT_EPSILON ;
00915
00916 if(min_sig<tau){
00917 #ifdef USE_EXCEPTION
00918 throw MatrixErr() ;
00919 #else
00920 Error err("SVDMatrix::inverseIn") ;
00921 err << "\nSVD found some singular value null coefficients.\n" ;
00922 err.warning() ;
00923 #endif
00924 }
00925
00926 S.resize(V.cols(),U.rows());
00927 S.reset(0) ;
00928 for(int i=0;i<sig.n();++i)
00929 S(i,i) = (T)1/sig[i] ;
00930
00931
00932 A = U.transpose() ;
00933 A = (const Matrix<T>&)S*(const Matrix<T>&)A ;
00934 A = (const Matrix<T>&)V*(const Matrix<T>&)A ;
00935 }
00936
00937
00950 template <class T>
00951 Matrix<T> SVDMatrix<T>::inverse(double tau) {
00952 Matrix<T> A ;
00953
00954 inverseIn(A,tau) ;
00955 return A ;
00956 }
00957
00976 template <class T>
00977 int SVDMatrix<T>::solve(const Matrix<T>&B, Matrix<T>&X, double tau) {
00978 T min_sig, max_sig ;
00979 minMax(min_sig,max_sig) ;
00980
00981 if(B.rows() != U.rows()){
00982 #ifdef USE_EXCEPTION
00983 throw WrongSize2D(B.rows(),B.cols(),U.rows(),U.cols()) ;
00984 #else
00985 Error err("SVDMatrix::solve");
00986 err << "The matrix B doesn't have a proper size for this SVD matrix." ;
00987 err.fatal() ;
00988 return 0 ;
00989 #endif
00990 }
00991
00992 X.resize(V.rows(),B.cols()) ;
00993
00994 if(tau==0)
00995 tau = V.rows()*max_sig*FLT_EPSILON ;
00996 int stable = 1 ;
00997
00998 Vector<T> S(sig.n()) ;
00999
01000
01001 int i,j,k ;
01002 for(j=0;j<B.cols();++j){
01003 for(i=0;i<V.cols();++i){
01004 T s = 0 ;
01005 if(sig[i]>tau){
01006 for(k=0;k<U.cols();++k)
01007 s += U(k,i)*B(k,j);
01008 s /= sig[i] ;
01009 }
01010 else
01011 stable = 0 ;
01012 S[i] = s ;
01013 }
01014 for(i=0;i<V.rows();++i){
01015 X(i,j) = 0 ;
01016 for(k=0;k<V.rows();++k)
01017 X(i,j) += V(i,k)*S[k] ;
01018 }
01019 }
01020 return stable ;
01021 }
01022
01040 template <class T>
01041 int solve(const Matrix<T>& A,
01042 const Matrix<T>& B,
01043 Matrix<T>& X){
01044 if(A.rows()==A.cols()){
01045
01046 LUMatrix<T> lu(A) ;
01047 X = lu.inverse()*B ;
01048 }
01049 else{
01050 SVDMatrix<T> svd(A) ;
01051 return svd.solve(B,X) ;
01052 }
01053 return 1;
01054 }
01055
01072 template <class T>
01073 Matrix<T> inverse(const Matrix<T>&A){
01074 Matrix<T> inv ;
01075 if(A.rows()==A.cols()){
01076 LUMatrix<T> lu(A) ;
01077 lu.inverseIn(inv) ;
01078 }
01079 else{
01080 SVDMatrix<T> svd(A) ;
01081 svd.inverseIn(inv) ;
01082 }
01083 return inv ;
01084 }
01085
01086 }
01087
01088
01089 #endif