00001 /*=============================================================================
00002 File: matrixMat.cpp
00003 Purpose:
00004 Revision: $Id: matrixMat.cpp,v 1.2 2002/05/13 21:07:45 philosophil Exp $
00005 Created by: Philippe Lavoie (22 Oct, 1997)
00006 Modified by:
00007
00008 Copyright notice:
00009 Copyright (C) 1996-1997 Philippe Lavoie
00010
00011 This library is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU Library General Public
00013 License as published by the Free Software Foundation; either
00014 version 2 of the License, or (at your option) any later version.
00015
00016 This library is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00019 Library General Public License for more details.
00020
00021 You should have received a copy of the GNU Library General Public
00022 License along with this library; if not, write to the Free
00023 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 // lu = a; must do it by copying or LUFACT will be recursively called !
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) /* non-trivial problem */
00103 {
00104 for (k = 0; k < nm1; k++)
00105 {
00106 kp1 = k + 1;
00107 // partial pivoting ROW exchanges
00108 // -- search over column
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 { // nonsingular pivot found
00134 if (l != k ){ // interchange needed
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); /* scale row */
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 /* pivot singular */
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 // a type cast from an LUMatrix directly to a Matrix
00166 template <class T>
00167 Matrix<T> LUMatrix::operator Matrix()
00168 {
00169 int i, j, r = rows(), c = cols();
00170
00171 Matrix mat( r, c );
00172
00173 el_type *ptr,*mptr;
00174 for (i = 0; i < r; i++)
00175 {
00176 mptr = mat.vm[i];
00177 ptr = vm[i];
00178 for (j = 0; j < c; j++)
00179 *mptr++ = *ptr++;
00180 }
00181 return mat;
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 // routine copied from Numerical Recipes in C
00207 // IT DOESN"T WORK
00208 template <class T>
00209 void LUMatrix<T>::backSub(const Matrix<T>& B, Matrix<T>& X){
00210 int i,ii,ip,j,k ;
00211 T sum ;
00212 int n = rows() ;
00213 // one column at a time
00214 //X.resize(n,B.cols()) ;
00215 X = B ;
00216 for(j=0;j<B.cols();++j){
00217 ii = 0 ;
00218 for(i=0;i<n;++i){ // doing back substitution
00219 ip=pivot[i] ;
00220 sum=X(ip,j) ;
00221 X(ip,j) = X(i,j) ;
00222 if(ii)
00223 for(k=ii;k<i;++k)
00224 sum -= elem(i,k)*X(k,j);
00225 else
00226 if(sum)
00227 ii=i ;
00228 X(i,j) = sum ;
00229 }
00230 for(i=n-1;i>0;--i){ // doing forward substitution
00231 sum=X(i,j) ;
00232 for(k=i+1;k<n;++k)
00233 sum -= elem(i,k)*X(k,j) ;
00234 X(i,j) = sum/elem(i,i) ;
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 // inverse U
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 // INV(U) * INV(L)
00295 if (nm1 >= 1)
00296 {
00297 Vector<T> work(n) ;
00298 //error.memory( work.memory() );
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 * Bidiagonalization
00367 */
00368
00369 /*
00370 * Left Householder Transformations
00371 *
00372 * Zero out an entire subdiagonal of the i-th column of A and compute the
00373 * modified A[i,i] by multiplication (UP' * A) with a matrix UP'
00374 * (1) UP' = E - UPi * UPi' / beta
00375 *
00376 * where a column-vector UPi is as follows
00377 * (2) UPi = [ (i-1) zeros, A[i,i] + Norm, vector A[i+1:M,i] ]
00378 * where beta = UPi' * A[,i] and Norm is the norm of a vector A[i:M,i]
00379 * (sub-diag part of the i-th column of A). Note we assign the Norm the
00380 * same sign as that of A[i,i].
00381 * By construction, (1) does not affect the first (i-1) rows of A. Since
00382 * A[*,1:i-1] is bidiagonal (the result of the i-1 previous steps of
00383 * the bidiag algorithm), transform (1) doesn't affect these i-1 columns
00384 * either as one can easily verify.
00385 * The i-th column of A is transformed as
00386 * (3) UP' * A[*,i] = A[*,i] - UPi
00387 * (since UPi'*A[*,i]/beta = 1 by construction of UPi and beta)
00388 * This means effectively zeroing out A[i+1:M,i] (the entire subdiagonal
00389 * of the i-th column of A) and replacing A[i,i] with the -Norm. Thus
00390 * modified A[i,i] is returned by the present function.
00391 * The other (i+1:N) columns of A are transformed as
00392 * (4) UP' * A[,j] = A[,j] - UPi * ( UPi' * A[,j] / beta )
00393 * Note, due to (2), only elements of rows i+1:M actually participate
00394 * in above transforms; the upper i-1 rows of A are not affected.
00395 * As was mentioned earlier,
00396 * (5) beta = UPi' * A[,i] = (A[i,i] + Norm)*A[i,i] + A[i+1:M,i]*A[i+1:M,i]
00397 * = ||A[i:M,i]||^2 + Norm*A[i,i] = Norm^2 + Norm*A[i,i]
00398 * (note the sign of the Norm is the same as A[i,i])
00399 * For extra precision, vector UPi (and so is Norm and beta) are scaled,
00400 * which would not affect (4) as easy to see.
00401 *
00402 * To satisfy the definition
00403 * (6) .SIG = U' A V
00404 * the result of consecutive transformations (1) over matrix A is accumulated
00405 * in matrix U' (which is initialized to be a unit matrix). At each step,
00406 * U' is left-multiplied by UP' = UP (UP is symmetric by construction,
00407 * see (1)). That is, U is right-multiplied by UP, that is, rows of U are
00408 * transformed similarly to columns of A, see eq. (4). We also keep in mind
00409 * that multiplication by UP at the i-th step does not affect the first i-1
00410 * columns of U.
00411 * Note that the vector UPi doesn't have to be allocated explicitly: its
00412 * first i-1 components are zeros (which we can always imply in computations),
00413 * and the rest of the components (but the UPi[i]) are the same as those
00414 * of A[i:M,i], the subdiagonal of A[,i]. This column, A[,i] is affected only
00415 * trivially as explained above, that is, we don't need to carry this
00416 * transformation explicitly (only A[i,i] is going to be non-trivially
00417 * affected, that is, replaced by -Norm, but we will use sig[i] to store
00418 * the result).
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; // Compute the scaling factor
00427 for(k=i; k<M; k++)
00428 scale += absolute(A(k,i));
00429 if( scale == 0 ) // If A[,i] is a null vector, no
00430 return 0; // transform is required
00431 double Norm_sqr = 0; // Scale UPi (that is, A[,i])
00432 for(k=i; k<M; k++) // and compute its norm, Norm^2
00433 Norm_sqr += sqr(A(k,i) /= scale);
00434 double new_Aii = sqrt(Norm_sqr); // new_Aii = -Norm, Norm has the
00435 if( A(i,i) > 0 ) new_Aii = -new_Aii; // same sign as Aii (that is, UPi[i])
00436 const float beta = - A(i,i)*new_Aii + Norm_sqr;
00437 A(i,i) -= new_Aii; // UPi[i] = A[i,i] - (-Norm)
00438
00439 for(j=i+1; j<N; j++) // Transform i+1:N columns of A
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++) // Accumulate the transform in U
00450 {
00451 T factor = 0;
00452 for(k=i; k<M; k++)
00453 factor += A(k,i) * U_(j,k); // Compute U[j,] * UPi
00454 factor /= beta;
00455 for(k=i; k<M; k++)
00456 U_(j,k) -= A(k,i) * factor;
00457 }
00458 return new_Aii * scale; // Scale new Aii back (our new Sig[i])
00459 }
00460
00461 /*
00462 * Right Householder Transformations
00463 *
00464 * Zero out i+2:N elements of a row A[i,] of matrix A by right
00465 * multiplication (A * VP) with a matrix VP
00466 * (1) VP = E - VPi * VPi' / beta
00467 *
00468 * where a vector-column .VPi is as follows
00469 * (2) VPi = [ i zeros, A[i,i+1] + Norm, vector A[i,i+2:N] ]
00470 * where beta = A[i,] * VPi and Norm is the norm of a vector A[i,i+1:N]
00471 * (right-diag part of the i-th row of A). Note we assign the Norm the
00472 * same sign as that of A[i,i+1].
00473 * By construction, (1) does not affect the first i columns of A. Since
00474 * A[1:i-1,] is bidiagonal (the result of the previous steps of
00475 * the bidiag algorithm), transform (1) doesn't affect these i-1 rows
00476 * either as one can easily verify.
00477 * The i-th row of A is transformed as
00478 * (3) A[i,*] * VP = A[i,*] - VPi'
00479 * (since A[i,*]*VPi/beta = 1 by construction of VPi and beta)
00480 * This means effectively zeroing out A[i,i+2:N] (the entire right super-
00481 * diagonal of the i-th row of A, but ONE superdiag element) and replacing
00482 * A[i,i+1] with - Norm. Thus modified A[i,i+1] is returned as the result of
00483 * the present function.
00484 * The other (i+1:M) rows of A are transformed as
00485 * (4) A[j,] * VP = A[j,] - VPi' * ( A[j,] * VPi / beta )
00486 * Note, due to (2), only elements of columns i+1:N actually participate
00487 * in above transforms; the left i columns of A are not affected.
00488 * As was mentioned earlier,
00489 * (5) beta = A[i,] * VPi = (A[i,i+1] + Norm)*A[i,i+1]
00490 * + A[i,i+2:N]*A[i,i+2:N]
00491 * = ||A[i,i+1:N]||^2 + Norm*A[i,i+1] = Norm^2 + Norm*A[i,i+1]
00492 * (note the sign of the Norm is the same as A[i,i+1])
00493 * For extra precision, vector VPi (and so is Norm and beta) are scaled,
00494 * which would not affect (4) as easy to see.
00495 *
00496 * The result of consecutive transformations (1) over matrix A is accumulated
00497 * in matrix V (which is initialized to be a unit matrix). At each step,
00498 * V is right-multiplied by VP. That is, rows of V are transformed similarly
00499 * to rows of A, see eq. (4). We also keep in mind that multiplication by
00500 * VP at the i-th step does not affect the first i rows of V.
00501 * Note that vector VPi doesn't have to be allocated explicitly: its
00502 * first i components are zeros (which we can always imply in computations),
00503 * and the rest of the components (but the VPi[i+1]) are the same as those
00504 * of A[i,i+1:N], the superdiagonal of A[i,]. This row, A[i,] is affected
00505 * only trivially as explained above, that is, we don't need to carry this
00506 * transformation explicitly (only A[i,i+1] is going to be non-trivially
00507 * affected, that is, replaced by -Norm, but we will use super_diag[i+1] to
00508 * store the result).
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; // Compute the scaling factor
00517 for(k=i+1; k<N; k++)
00518 scale += absolute(A(i,k));
00519 if( scale == 0 ) // If A[i,] is a null vector, no
00520 return 0; // transform is required
00521
00522 double Norm_sqr = 0; // Scale VPi (that is, A[i,])
00523 for(k=i+1; k<N; k++) // and compute its norm, Norm^2
00524 Norm_sqr += sqr(A(i,k) /= scale);
00525 double new_Aii1 = sqrt(Norm_sqr); // new_Aii1 = -Norm, Norm has the
00526 if( A(i,i+1) > 0 ) // same sign as
00527 new_Aii1 = -new_Aii1; // Aii1 (that is, VPi[i+1])
00528 const float beta = - A(i,i+1)*new_Aii1 + Norm_sqr;
00529 A(i,i+1) -= new_Aii1; // VPi[i+1] = A[i,i+1] - (-Norm)
00530
00531 for(j=i+1; j<M; j++) // Transform i+1:M rows of A
00532 {
00533 T factor = 0;
00534 for(k=i+1; k<N; k++)
00535 factor += A(i,k) * A(j,k); // Compute A[j,] * VPi
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++) // Accumulate the transform in V
00542 {
00543 T factor = 0;
00544 for(k=i+1; k<N; k++)
00545 factor += A(i,k) * V_(j,k); // Compute V[j,] * VPi
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; // Scale new Aii1 back
00551 }
00552
00553 /*
00554 *------------------------------------------------------------------------
00555 * Bidiagonalization
00556 * This nethod turns matrix A into a bidiagonal one. Its N diagonal elements
00557 * are stored in a vector sig, while N-1 superdiagonal elements are stored
00558 * in a vector super_diag(2:N) (with super_diag(1) being always 0).
00559 * Matrices U and V store the record of orthogonal Householder
00560 * reflections that were used to convert A to this form. The method
00561 * returns the norm of the resulting bidiagonal matrix, that is, the
00562 * maximal column sum.
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; // No superdiag elem above A(1,1)
00570 Matrix<T> A = _A; // A being transformed
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 * QR-diagonalization of a bidiagonal matrix
00585 *
00586 * After bidiagonalization we get a bidiagonal matrix J:
00587 * (1) J = U' * A * V
00588 * The present method turns J into a matrix JJ by applying a set of
00589 * orthogonal transforms
00590 * (2) JJ = S' * J * T
00591 * Orthogonal matrices S and T are chosen so that JJ were also a
00592 * bidiagonal matrix, but with superdiag elements smaller than those of J.
00593 * We repeat (2) until non-diag elements of JJ become smaller than EPS
00594 * and can be disregarded.
00595 * Matrices S and T are constructed as
00596 * (3) S = S1 * S2 * S3 ... Sn, and similarly T
00597 * where Sk and Tk are matrices of simple rotations
00598 * (4) Sk[i,j] = i==j ? 1 : 0 for all i>k or i<k-1
00599 * Sk[k-1,k-1] = cos(Phk), Sk[k-1,k] = -sin(Phk),
00600 * SK[k,k-1] = sin(Phk), Sk[k,k] = cos(Phk), k=2..N
00601 * Matrix Tk is constructed similarly, only with angle Thk rather than Phk.
00602 *
00603 * Thus left multiplication of J by SK' can be spelled out as
00604 * (5) (Sk' * J)[i,j] = J[i,j] when i>k or i<k-1,
00605 * [k-1,j] = cos(Phk)*J[k-1,j] + sin(Phk)*J[k,j]
00606 * [k,j] = -sin(Phk)*J[k-1,j] + cos(Phk)*J[k,j]
00607 * That is, k-1 and k rows of J are replaced by their linear combinations;
00608 * the rest of J is unaffected. Right multiplication of J by Tk similarly
00609 * changes only k-1 and k columns of J.
00610 * Matrix T2 is chosen the way that T2'J'JT2 were a QR-transform with a
00611 * shift. Note that multiplying J by T2 gives rise to a J[2,1] element of
00612 * the product J (which is below the main diagonal). Angle Ph2 is then
00613 * chosen so that multiplication by S2' (which combines 1 and 2 rows of J)
00614 * gets rid of that elemnent. But this will create a [1,3] non-zero element.
00615 * T3 is made to make it disappear, but this leads to [3,2], etc.
00616 * In the end, Sn removes a [N,N-1] element of J and matrix S'JT becomes
00617 * bidiagonal again. However, because of a special choice
00618 * of T2 (QR-algorithm), its non-diag elements are smaller than those of J.
00619 *
00620 * All this process in more detail is described in
00621 * J.H. Wilkinson, C. Reinsch. Linear algebra - Springer-Verlag, 1971
00622 *
00623 * If during transforms (1), JJ[N-1,N] turns 0, then JJ[N,N] is a singular
00624 * number (possibly with a wrong (that is, negative) sign). This is a
00625 * consequence of Frantsis' Theorem, see the book above. In that case, we can
00626 * eliminate the N-th row and column of JJ and carry out further transforms
00627 * with a smaller matrix. If any other superdiag element of JJ turns 0,
00628 * then JJ effectively falls into two independent matrices. We will process
00629 * them independently (the bottom one first).
00630 *
00631 * Since matrix J is a bidiagonal, it can be stored efficiently. As a matter
00632 * of fact, its N diagonal elements are in array Sig, and superdiag elements
00633 * are stored in array super_diag.
00634 */
00635
00636 // Carry out U * S with a rotation matrix
00637 // S (which combines i-th and j-th columns
00638 // of U, i>j)
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 * A diagonal element J[l-1,l-1] turns out 0 at the k-th step of the
00654 * algorithm. That means that one of the original matrix' singular numbers
00655 * shall be zero. In that case, we multiply J by specially selected
00656 * matrices S' of simple rotations to eliminate a superdiag element J[l-1,l].
00657 * After that, matrix J falls into two pieces, which can be dealt with
00658 * in a regular way (the bottom piece first).
00659 *
00660 * These special S transformations are accumulated into matrix U: since J
00661 * is left-multiplied by S', U would be right-multiplied by S. Transform
00662 * formulas for doing these rotations are similar to (5) above. See the
00663 * book cited above for more details.
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; // Accumulate cos,sin of Ph
00669 // The first step of the loop below
00670 // (when i==l) would eliminate J[l-1,l],
00671 // which is stored in super_diag(l)
00672 // However, it gives rise to J[l-1,l+1]
00673 // and J[l,l+2]
00674 // The following steps eliminate these
00675 // until they fall below
00676 // significance
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; // Current J[l-1,l] became unsignificant
00683 cos_ph = sig[i]; sin_ph = -f; // unnormalized sin/cos
00684 const double norm = (sig_[i] = hypot(cos_ph,sin_ph)); // sqrt(sin^2+cos^2)
00685 cos_ph /= norm, sin_ph /= norm; // Normalize sin/cos
00686 rotate(U_,i,l-1,cos_ph,sin_ph);
00687 }
00688 }
00689
00690 // We're about to proceed doing QR-transforms
00691 // on a (bidiag) matrix J[1:k,1:k]. It may happen
00692 // though that the matrix splits (or can be
00693 // split) into two independent pieces. This function
00694 // checks for splitting and returns the lowerbound
00695 // index l of the bottom piece, J[l:k,l:k]
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; // The breaking point: zero J[l-1,l]
00702 else if( absolute(sig[l-1]) <= eps ) // Diagonal J[l,l] turns out 0
00703 { // meaning J[l-1,l] _can_ be made
00704 rip_through(super_diag,k,l,eps); // zero after some rotations
00705 return l;
00706 }
00707 return 0; // Deal with J[1:k,1:k] as a whole
00708 }
00709
00710 // Diagonalize root module
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--) // QR-iterate upon J[l:k,l:k]
00715 {
00716 int l;
00717 // while(l=get_submatrix_to_work_on(super_diag,k,eps),
00718 // absolute(super_diag[k]) > eps) // until superdiag J[k-1,k] becomes 0
00719 // Phil
00720 while(absolute(super_diag[k]) > eps)// until superdiag J[k-1,k] becomes 0
00721 {
00722 l=get_submatrix_to_work_on(super_diag,k,eps) ;
00723 double shift; // Compute a QR-shift from a bottom
00724 { // corner minor of J[l:k,l:k] order 2
00725 T Jk2k1 = super_diag[k-1], // J[k-2,k-1]
00726 Jk1k = super_diag[k],
00727 Jk1k1 = sig[k-1], // J[k-1,k-1]
00728 Jkk = sig[k],
00729 Jll = sig[l]; // J[l,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 // Carry on multiplications by T2, S2, T3...
00736 double cos_th = 1, sin_th = 1;
00737 T Ji1i1 = sig[l]; // J[i-1,i-1] at i=l+1...k
00738 for(register int i=l+1; i<=k; i++)
00739 {
00740 T Ji1i = super_diag[i], Jii = sig[i]; // J[i-1,i] and J[i,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 // Rotate J[i-1:i,i-1:i] by Ti
00745 shift = cos_th*Ji1i1 + sin_th*Ji1i; // new J[i-1,i-1]
00746 Ji1i = -sin_th*Ji1i1 + cos_th*Ji1i; // J[i-1,i] after rotation
00747 const double Jii1 = Jii*sin_th; // Emerged J[i,i-1]
00748 Jii *= cos_th; // new J[i,i]
00749 rotate(V_,i,i-1,cos_th,sin_th); // Accumulate T rotations in V
00750
00751 double cos_ph = shift, sin_ph = Jii1;// Make Si to get rid of J[i,i-1]
00752 sig_[i-1] = (norm_f = hypot(cos_ph,sin_ph)); // New J[i-1,i-1]
00753 if( norm_f == 0 ) // If norm =0, rotation angle
00754 cos_ph = cos_th, sin_ph = sin_th; // can be anything now
00755 else
00756 cos_ph /= norm_f, sin_ph /= norm_f;
00757 // Rotate J[i-1:i,i-1:i] by Si
00758 shift = cos_ph * Ji1i + sin_ph*Jii; // New J[i-1,i]
00759 Ji1i1 = -sin_ph*Ji1i + cos_ph*Jii; // New Jii, would carry over
00760 // as J[i-1,i-1] for next i
00761 rotate(U_,i,i-1,cos_ph,sin_ph); // Accumulate S rotations in U
00762 // Jii1 disappears, sin_th would
00763 cos_th = cos_ph, sin_th = sin_ph; // carry over a (scaled) J[i-1,i+1]
00764 // to eliminate on the next i, cos_th
00765 // would carry over a scaled J[i,i+1]
00766 }
00767 super_diag[l] = 0; // Supposed to be eliminated by now
00768 super_diag[k] = shift;
00769 sig_[k] = Ji1i1;
00770 } // --- end-of-QR-iterations
00771 if( sig[k] < 0 ) // Correct the sign of the sing number
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; // Significance threshold
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 //A = V*S*transpose(U) ;
00932 A = U.transpose() ;
00933 A = (const Matrix<T>&)S*(const Matrix<T>&)A ; // transpose(U) ;
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 // doing one column from B at a time
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 // use LU decomposition to solve the problem
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
1.2.14 written by Dimitri van Heesch,
© 1997-2002