00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * David Wong 00008 * Side Effects 00009 * 477 Richmond Street West 00010 * Toronto, Ontario 00011 * Canada M5V 3E7 00012 * 416-504-9876 00013 * 00014 * NAME: Matrix Solver (C++) 00015 * 00016 * COMMENTS: 00017 * 00018 */ 00019 00020 #ifndef __UT_MatrixSolver_H__ 00021 #define __UT_MatrixSolver_H__ 00022 00023 #include "UT_API.h" 00024 #include "UT_Assert.h" 00025 00026 #include "UT_Functor.h" 00027 #include "UT_Matrix.h" 00028 #include "UT_Vector.h" 00029 00030 // Set below to 1 in order to use old version of LUDecomp 00031 #define USE_OLD_LUDECOMP 0 00032 00033 class UT_API UT_MatrixSolver { 00034 public: 00035 /// LU Decomposition of a[1..n][1..n] where a has full rank. 00036 /// Output: index[1..n] is the row permutation 00037 /// d = +/-1 indicating row interchanges was even or odd, resp. 00038 /// return 0 if the matrix is truly singular 00039 /// 1 on success 00040 /// 2 if the matrix is singular to the precision of the 00041 /// algorithm, where tol is the zero tolerance. 00042 int LUDecompOld(UT_Matrix &a, UT_Permutation &index, float &d, 00043 float tol = 1e-20F); 00044 00045 /// Solve Ax=b 00046 /// a[1..n][1..n] is a LU Decomposition of matrix A (eg. from LUDecomp()) 00047 /// index describes the row permutations as output from LUDecomp() 00048 /// b[1..n] is input as rhs, and on output contains the solution x 00049 void LUBackSubOld(const UT_Matrix &a, const UT_Permutation &index, 00050 UT_Vector &b); 00051 00052 #if USE_OLD_LUDECOMP 00053 int LUDecomp(UT_Matrix &a, UT_Permutation &index, float &d, 00054 float tol = 1e-20F) 00055 { 00056 return LUDecompOld(a, index, d, tol); 00057 } 00058 void LUBackSub(const UT_Matrix &a, const UT_Permutation &index, 00059 UT_Vector &b) 00060 { 00061 return LUBackSubOld(a, index, b); 00062 } 00063 #else 00064 int LUDecomp(UT_Matrix &a, UT_Permutation &index, float &d, 00065 float tol = 1e-20F) 00066 { 00067 return LUDecompRect(a, index, d, tol); 00068 } 00069 void LUBackSub(const UT_Matrix &a, const UT_Permutation &index, 00070 UT_Vector &b) 00071 { 00072 return LUDecompBackSub(a, index, b); 00073 } 00074 #endif 00075 00076 /// LU decomposition of rectangular A[1..m][1..n] with partial pivoting. 00077 /// Unlike LUDecomp(), this handles pivot values of 0. 00078 /// ie. it performs the decomposition of A = P.L.U for unit lower 00079 /// triangular L and upper triangular U. 00080 /// Input: A[1..m][1..n] 00081 /// Output: A contains the matrices L and U in compact form, without 00082 /// the unit diagonal. 00083 /// L is of size min(m,n) by n. U is of size m by min(m,n) 00084 /// pivots[1..n] is the row permulation P 00085 /// tol is scaled by the largest pivot element 00086 /// detsign is the sign of the determinant used by det() 00087 /// its +1 if row interchanges was even, -1 if odd 00088 /// Returns 0 if the matrix is truly singular 00089 /// 1 on success 00090 /// 2 if the matrix is singular to the precision of the 00091 /// algorithm, where tol is the zero tolerance. 00092 /// This algorithm takes roughly O(m*n^2 - n^3/3) flops 00093 int LUDecompRect(UT_Matrix &A, UT_Permutation &pivots, 00094 float &detsign, 00095 float tol = 1e-6F); 00096 00097 /// Performs back substitution using the output of LUDecomp() for a square 00098 /// matrix. 00099 /// Input: A[1..n][1..n] and pivots as output from LUDecompRect() 00100 /// b[1..n] is the right hand side for solving A.x = b 00101 /// Output: b is modified to contain the solution x 00102 void LUDecompBackSub(const UT_Matrix &A, 00103 const UT_Permutation &pivots, 00104 UT_Vector &b); 00105 00106 /// LU decompose a companion matrix 00107 /// The matrix given is the base of the companion matrix: 00108 /// [aI bI 0 0 ] 00109 /// [0 aI bI 0 ] 00110 /// [0 0 aI bI] 00111 /// [P1 P2 P3 P4] 00112 /// ie: [P1 P2 P3 P4] 00113 /// The resulting LU decompostion is written into the R matrix and 00114 /// is: 00115 /// [aI 0 0 0] [I b/aI 0 0 ] 00116 /// [0 aI 0 0] [0 I b/aI 0 ] 00117 /// [0 0 aI 0] [0 0 I b/aI] 00118 /// [R1 R2 R3 L] [0 0 0 U ] 00119 /// LU is stored in the last portion of the matrix & index is the 00120 /// permuation that resulted in it. Thus, index should be the height 00121 /// of P, NOT the entire companion matrix. 00122 /// 00123 /// Return 0 on success, -1 for singular, and -2 for singular to 00124 /// machine precision (As judged by tol), and -3 for a being near zero. 00125 int LUDecompCompanion(const UT_Matrix &P, float a, float b, 00126 UT_Matrix &R, UT_Permutation &index, 00127 float tol=1e-20F); 00128 00129 /// This takes the result of the previous operation and does a 00130 /// back substitution. 00131 void LUBackSubCompanion(const UT_Matrix &R, float a, float b, 00132 const UT_Permutation &index, 00133 UT_Vector &y); 00134 00135 /// 00136 /// Cholesky factorization 00137 /// 00138 /// To solve a full rank system A . x = b where A can be undertermined 00139 /// (ie. A has less rows than columns), we can make use of the Cholesky 00140 /// factorization functions below by way of the normal equations like so: 00141 /// 1. Left multiply both sides by the tranpose of A, A^T to get 00142 /// (A^T . A) . x = (A^T . b) 00143 /// 2. Now solve for x using P . x = c where P = A^T . A and c = A^T . b 00144 /// This is done by first calling choleskyDecomp() using P since it 00145 /// will be symmetric non-negative definite. Then use choleskyBackSub() 00146 /// to obtain x for particular values of c. 00147 00148 /// Performs a Cholesky decomposition of the symmetric non-negative definite 00149 /// matrix A such that A = L . L^T where L^T is tranpose of the lower 00150 /// triangular matrix L. 00151 /// Input: Symmetric non-negative definite matrix a[1..n][1..n]. 00152 /// Only the upper triangle of a is read from. 00153 /// tol is the tolerance check for when a sum is deemed 0 00154 /// Output: Cholesky factor L is returned in the lower triangle of A, except 00155 /// for its diagonal elements which is returned in d[1..n] 00156 /// Returns the number of articial zero's placed into d. If we 00157 /// encounter negative diagonal values, they are zeroed out and we 00158 /// return -N where N is the number of negative values found. 00159 int choleskyDecomp(UT_Matrix &a, UT_Vector &d, float tol=1e-5F); 00160 00161 /// Solves the set of n linear equations, A.x = b, where a is a nonnegative 00162 /// definite symmetric matrix. 00163 /// Input: a[1..n][1..n] and d[1..n] as output from choleskyDecomp() above. 00164 /// Only the lower triangle of a is read from. 00165 /// b[1..n] is the right-hand side of A.x = b to solve for 00166 /// tol is the tolerance check for when an element of d is deemed 0 00167 /// Output: x[1..n], the solution of A.x = b 00168 /// Returns the number of articial zero's placed into x. 00169 int choleskyBackSub(const UT_Matrix &a, const UT_Vector &d, 00170 const UT_Vector &b, UT_Vector &x, 00171 float tol=1e-5F); 00172 00173 /// Performs inverse iteration to find the closest eigenvalue(s) 00174 /// to s. 00175 /// Does a two pass method, first using single iterations until 00176 /// starttol is reached, in which case singles are used to 00177 /// achieve final tolerance. If starttol is not reached in 00178 /// startiter iterations, uses double method to find using 00179 /// final tolerance/iterations. 00180 /// 00181 /// The vector q is updated with the newest eigenvector. 00182 /// Source matrices are: 00183 /// [1 0 0] [0 1 0] 00184 /// C1' = [0 1 0] C2' = [0 0 1] 00185 /// [0 0 C1] [ C2 ] 00186 /// Thus, the initial sizes of the matrices/vectors are (row*col): 00187 /// C1: n*n, C2: n*(n*deg), R: n*(n*deg), tmp: n*(n*deg), 00188 /// index: n, q: n*deg, Aq: n*deg 00189 /// The result code determines how s1 & s2 are to be interpreted: 00190 /// Result: 00191 /// 0 - One eigenvalue found at s1, eigenvector q. 00192 /// 1 - Two real eigenvalues found: s1 & s2. 00193 /// 2 - Complex conjugate eigenvalues found: s1 +- s2i. 00194 /// -1 - Failed to converge to final tolerance using single method. 00195 /// -2 - Failed to converge to final tolerance using double method. 00196 int inversePowerIterate(const UT_Matrix &C1, 00197 const UT_Matrix &C2, 00198 UT_Matrix &R, UT_Matrix &tmp, 00199 UT_Permutation &index, 00200 float s, 00201 float &s1, float &s2, 00202 UT_Vector &q, UT_Vector &Aq, 00203 float starttol = 1e-2F, int startiter = 5, 00204 float finaltol = 1e-5F, 00205 float doubletol = 1e-4F, int finaliter = 50); 00206 00207 /// Compute the inverse of a LU decomposed matrix. 00208 /// If you want to solve systems of equations AX=B, 00209 /// where B is a matrix. It is better (faster) to do a 00210 /// LU decomposition and use back substituation for columns of B. 00211 void inverse(UT_Matrix &a, UT_Permutation &index, UT_Matrix &ia); 00212 00213 /// Finds all linearly independent rows in A, does NOT require 00214 /// A to be any particular shape. Returns the number of independent 00215 /// rows & first entries of index are their indices in the original 00216 /// matrix. 00217 /// Destroys A. 00218 int findLinIndRows(UT_Matrix &A, UT_Permutation &index, 00219 float tol = 1E-6F); 00220 00221 /// Similar to findLinIndRows, performs gaussian elimination 00222 /// with full pivoting on G. Updates as well Gu, and Gv, the 00223 /// partial derivitive matrix of G(u, v). After this is done, 00224 /// the determinant of G & partials of the determinant can 00225 /// be computed. 00226 void fullGaussianElimination(UT_Matrix &G, UT_Matrix &Gu, 00227 UT_Matrix &Gv, 00228 UT_Permutation &rowperm, 00229 UT_Permutation &colperm, 00230 float &detsign); 00231 00232 /// After full Gaussian Elimination, this finds the determinant 00233 /// and partials thereof: 00234 void detWithPartials(const UT_Matrix &G, const UT_Matrix &Gu, 00235 const UT_Matrix &Gv, 00236 const UT_Permutation &rowperm, 00237 const UT_Permutation &colperm, 00238 float detsign, 00239 float &retdet, float &detu, float &detv); 00240 00241 00242 /// Compute the determinant of a LU decomposed matrix. 00243 /// The d is what one gets from LU decomposition. 00244 float det(UT_Matrix &a, float d); 00245 00246 /// Find the determiment: 00247 /// (A(p,q), B(r,s), C(t,u))) 00248 inline float det3x3(const UT_Matrix &A, const UT_Matrix &B, 00249 const UT_Matrix &C, int p, int q, int r, int s, 00250 int t, int u) 00251 { 00252 return (A(p,q) * (B(r,s) * C(t,u) - B(t,u) * C(r,s)) - 00253 B(p,q) * (A(r,s) * C(t,u) - A(t,u) * C(r,s)) + 00254 C(p,q) * (A(r,s) * B(t,u) - A(t,u) * B(r,s)) ); 00255 } 00256 00257 /// Estimates condtion number of upper triangular matrix: 00258 void condEstimate(const UT_Matrix &A, UT_Vector &y); 00259 00260 /// Finds the condition number of a LUDecomposed matrix. 00261 /// This is just an approximation 00262 /// You must provide the infinite norm of A before LUDecomposition. 00263 float getConditionLUD(const UT_Matrix &A, 00264 const UT_Permutation &index, float anorm); 00265 00266 /// Find householder vector of x. 00267 void house(const UT_Vector &x, UT_Vector &v, float &b); 00268 void house(const UT_Matrix &x, UT_Vector &v, float &b); 00269 00270 /// Finds the givens rotation required to 0 b: 00271 void findGivens(float a, float b, float &c, float &s, 00272 float zerotol = 1e-20F); 00273 00274 /// Find half givens, return 0 if success, otherwise the required 00275 /// rotation is impossible (ie:complex eigenvalue) 00276 int findHalfGivens(const UT_Matrix &A, float &c, float &s, 00277 float tol = 0.0F); 00278 00279 /// Upper triangulizes A with householder transforms, applying 00280 /// simultaneously to A and optionally Q. 00281 void triangularize(UT_Matrix &A, UT_Matrix &B, UT_Matrix *Q = 0); 00282 00283 /// Transforms A into upper hessenburg and B into upper triangular. 00284 void hessentri(UT_Matrix &A, UT_Matrix &B); 00285 00286 /// Converts A into quasi upper triangular & B into upper triangular 00287 /// form using the QZ algorithm. 00288 int realSchurFormQZ(UT_Matrix &oA, UT_Matrix &oB, float tol=1e-6F, 00289 int maxIteration = 30); 00290 00291 /// Transform A into a hessenberg matrix through a series of 00292 /// householder reflections. 00293 void hessenberg(UT_Matrix &A); 00294 /// Computes P st A' = P^T A P 00295 void hessenberg(UT_Matrix &A, UT_Matrix &P); 00296 00297 /// Transforms A into a bidiagonal matrix via householder transformations. 00298 int bidiagonalize(UT_Matrix &A); 00299 00300 /// Reduces the matrix to real Schur form: 00301 /// Orthogonal transform responible for getting to real schur form 00302 /// is accumulated in Q, if it is non-zero. 00303 int realSchurForm(UT_Matrix &A, UT_Matrix *Q = 0, 00304 float tol = 1E-6F, 00305 int maxIteration = 30); 00306 00307 /// Golub-Kahan SVD algorithm. Resulting SVD matrix found in 00308 /// diaganol of A. 00309 int gkSVD(UT_Matrix &A, float tol = 1e-6F, 00310 int maxIteration = 30); 00311 00312 /// Use Numerical Recipes method for SVD decomposition, with results 00313 /// that are suitable for doing back substitution. 00314 /// NOTE: The UT_Matrix should start with 1,1! 00315 /// 00316 /// Decomposition a = u * w * v^T 00317 /// a[1..m][1..n] also stores the result u[1..m][1..n] 00318 /// w[1..n][1..n] is a diagonal matrix, stored as a vector 00319 /// v[1..n][1..n] 00320 int SVDDecomp(UT_Matrix &a, UT_Vector &w, UT_Matrix &v, 00321 int maxIterstion = 30); 00322 /// Perform back substitution on an SVD decomposed matrix. Solves 00323 /// equation Ax = b. 00324 int SVDBackSub(UT_Matrix &u, UT_Vector &w, UT_Matrix &v, 00325 UT_Vector &b, UT_Vector &x, float tol = 1e-6F); 00326 00327 /// Finds eigenvalues from a real schur form matrix: 00328 void findEigenValues(const UT_Matrix &A, 00329 UT_Vector &vreal, UT_Vector &vimg); 00330 /// Finds eigenvalues from generalized system (A - lambdaB) 00331 void findEigenValues(const UT_Matrix &A, const UT_Matrix &B, 00332 UT_Vector &sreal, UT_Vector &simg, 00333 UT_Vector &treal, UT_Vector &timg); 00334 00335 /// Finds the u & v eigenvalues from an eigenvector, whose udeg, 00336 /// vdeg, and tdeg are as specified. Returns 0 if fails. 00337 /// NB: Does the s/(1+s) transformation! 00338 int findUVfromEigenvector(const UT_Vector &vect, 00339 int udeg, int vdeg, int tdeg, float &u, float &v); 00340 00341 /// Finds a specified eigenvector from a real schur form matrix. 00342 /// The eigenvector must be real! 00343 void findRightEigenVector(const UT_Matrix &A, const UT_Matrix &Q, 00344 UT_Vector &vector, int i); 00345 00346 00347 private: 00348 /// Pushes down zeros, causing A to be a reduced hessenberg. 00349 void chaseZerosQZ(UT_Matrix &A, UT_Matrix &B, int zeropos); 00350 00351 /// Pushes across zeros generated in Golub-Kahan SVD method 00352 void chaseZerosGK(UT_Matrix &B, int zeropos); 00353 00354 /// Applies one iteration of the QZ algorithm to unreduced 00355 /// upper hessenberg A & non-singular upper triangular B. 00356 void QZStep(UT_Matrix &A, UT_Matrix &B); 00357 00358 /// Performs the francisQRStep on H. 00359 void francisQRStep(UT_Matrix &H); 00360 00361 // Performs francisQRStep, updating H12 = H12*Z, 00362 // Q = Q*Z, H23 = ZT * H23 simultaneously with finding H = ZT H Z 00363 void francisQRStep(UT_Matrix &H, 00364 UT_Matrix &H12, UT_Matrix &H23, UT_Matrix &Q); 00365 00366 /// Performs one step in the Golub-Kahan SVD algorithm: 00367 /// B is a bidiagonal matrix with no zeros on diagonal nor supradiagonal, 00368 void golubKahanSVDStep(UT_Matrix &B); 00369 00370 /// Solves (A - lambda I) x = gamma B for x, requires A is quasi triangular. 00371 /// B is column. 00372 void solveQuasiUpperTriangular(const UT_Matrix &A, float lambda, 00373 float gamma, 00374 const UT_Matrix &B, UT_Vector &x, 00375 float tol = 1e-6F); 00376 00377 /// Performs inverse iteration until convergence or maxiter is reached. 00378 /// The vector is updated with the newest eigenvector. 00379 /// Call with findDecomp = 0 to use R directly as opposed to decomposing 00380 /// it. Source matrices are: 00381 /// [1 0 0] [0 1 0] 00382 /// C1' = [0 1 0] C2' = [0 0 1] 00383 /// [0 0 C1] [ C2 ] 00384 /// Returns: 00385 /// 1: Decomp found the pencil to be degenerate, perfect solution. 00386 /// 0: Successfully converged 00387 /// <0: Failed to converge 00388 int inversePowerSingle( const UT_Matrix &C1, 00389 const UT_Matrix &C2, 00390 UT_Matrix &R, UT_Matrix &tmp, 00391 UT_Permutation &index, 00392 float &s, float lasts, 00393 UT_Vector &q, UT_Vector &Aq, 00394 int findDecomp = 1, 00395 float tol = 1e-5F, int maxiter = 50); 00396 00397 /// Performs inverse iteration until convergence or maxiter is reached. 00398 /// The vector is updated with the newest eigenvector. 00399 /// Call with findDecomp = 0 to use R directly as opposed to decomposing 00400 /// it. Source matrices are: 00401 /// [1 0 0] [0 1 0] 00402 /// C1' = [0 1 0] C2' = [0 0 1] 00403 /// [0 0 C1] [ C2 ] 00404 /// Computes two solutions, namely P & Q such that 00405 /// A = (C2 - sC1), and 00406 /// lim i->inf (A^i+2 - pA^i+1 - qA^i) u = 0 00407 /// Returns: 00408 /// 1: Decomp found the pencil to be degenerate, perfect solution. 00409 /// 0: Successfully converged 00410 /// <0: Failed to converge 00411 int inversePowerDouble( const UT_Matrix &C1, 00412 const UT_Matrix &C2, 00413 UT_Matrix &R, UT_Matrix &tmp, 00414 UT_Permutation &index, 00415 float s, 00416 float &p, float &q, 00417 UT_Vector &u, UT_Vector &Au, 00418 int findDecomp = 1, 00419 float tol = 1e-5F, int maxiter = 50); 00420 }; 00421 00422 00423 // UT_MatrixIterSolver class is mainly for sparse matrices. 00424 // The sparse matrices may be defined explicitly with UT_SparseMatrix, 00425 // or implicitly with functions. 00426 00427 class UT_API UT_MatrixIterSolver { 00428 public: 00429 /// Preconditioned Conjugate Gradient method for solving Ax=b, 00430 /// given the symmetric positive definite matrix A[0..n-1][0..n-1] 00431 /// indirectly through AMult (ie. Ax), 00432 /// a preconditioner for A through ASolve, 00433 /// the vector b[0..n-1] and an initial guess x[0..n-1]. 00434 /// maxIter defaults to 2n. 00435 /// error |b-Ax|/|b| < tol. 00436 /// normType indicates the type of norm used for error: 00437 /// 0 L-infinity norm (ie. max) 00438 /// 1 L1-norm (ie. sum of abs) 00439 /// 2 L2-norm (ie. Euclidean distance) 00440 /// Output: x[0..n-1] and error. 00441 float PCG(void (*AMult)(const UT_VectorD &x, UT_VectorD &result), 00442 void (*ASolve)(const UT_VectorD &b, UT_VectorD &x), 00443 int n, UT_VectorD &x, const UT_VectorD &b, 00444 float tol=1e-3F, int normType=2, int maxIter=-1); 00445 float PCG(void (*AMult)(const UT_VectorF &x, UT_VectorF &result), 00446 void (*ASolve)(const UT_VectorF &b, UT_VectorF &x), 00447 int n, UT_VectorF &x, const UT_VectorF &b, 00448 float tol=1e-3F, int normType=2, int maxIter=-1); 00449 00450 /// Preconditioned Conjugate Gradient method for solving Ax=b with 00451 /// the symmetric positive definite matrix A, preconditioner, and iteration 00452 /// conditions implicitly defined by functors. 00453 static void PCG(UT_Vector &x, const UT_Vector &b, 00454 const UT_Functor2<void, const UT_Vector &, UT_Vector &> &AMult, 00455 const UT_Functor2<void, const UT_Vector &, UT_Vector &> &ASolve, 00456 const UT_Functor2<bool, int, const UT_Vector &> &iterateTest); 00457 00458 /// Preconditioned Conjugate Gradient method for solving least squares Ax=b, 00459 /// given the matrix A[0..m-1][0..n-1] indirectly through AMult 00460 /// (ie. Ax if int = 0 or A^tx if int = 1), 00461 /// a preconditioner for A^tA through AtASolve, 00462 /// the vector b[0..m-1] and an initial guess x[0..n-1]. 00463 /// maxIter defaults to 2n. 00464 /// error |A^t(b-Ax)|/|A^tb| < tol. 00465 /// normType indicates the type of norm used for error: 00466 /// 0 L-infinity norm (ie. max) 00467 /// 1 L1-norm (ie. sum of abs) 00468 /// 2 L2-norm (ie. Euclidean distance) 00469 /// Output: x[0..n-1] and error. 00470 float PCGLS(void (*AMult)(const UT_Vector &x, UT_Vector &result, 00471 int transpose), 00472 void (*AtASolve)(const UT_Vector &b, UT_Vector &x), 00473 int m, int n, 00474 UT_Vector &x, const UT_Vector &b, 00475 float tol=1e-3F, int normType=2, int maxIter=-1); 00476 00477 /// Preconditioned Conjugate Gradient method for solving Ax=b, 00478 /// given the matrix A[0..m-1][0..n-1] indirectly through AMult 00479 /// (ie. Ax if int = 0 or A^tx if int = 1), 00480 /// a preconditioner for A through ASolve, 00481 /// the vector b[0..m-1] and an initial guess x[0..n-1]. 00482 /// maxIter defaults to 2n. 00483 /// error |b-Ax|/|b| < tol. 00484 /// normType indicates the type of norm used for error: 00485 /// 0 L-infinity norm (ie. max) 00486 /// 1 L1-norm (ie. sum of abs) 00487 /// 2 L2-norm (ie. Euclidean distance) 00488 /// Output: x[0..n-1] and error. 00489 float biPCG(void (*AMult)(const UT_Vector &x, UT_Vector &result, 00490 int transpose), 00491 void (*ASolve)(const UT_Vector &b, UT_Vector &x, 00492 int transpose), 00493 int n, 00494 UT_Vector &x, const UT_Vector &b, 00495 float tol=1e-3F, int normType=2, int maxIter=-1); 00496 }; 00497 00498 00499 #endif
1.5.9