00001 /* $NoKeywords: $ */ 00002 /* 00003 // 00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved. 00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert 00006 // McNeel & Associates. 00007 // 00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. 00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF 00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED. 00011 // 00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>. 00013 // 00015 */ 00016 00017 #if !defined(ON_MATRIX_INC_) 00018 #define ON_MATRIX_INC_ 00019 00020 class ON_Xform; 00021 00022 class ON_CLASS ON_Matrix 00023 { 00024 public: 00025 ON_Matrix(); 00026 ON_Matrix( 00027 int row_count, 00028 int col_count 00029 ); 00030 ON_Matrix( // see ON_Matrix::Create(int,int,int,int) for details 00031 int, // first valid row index 00032 int, // last valid row index 00033 int, // first valid column index 00034 int // last valid column index 00035 ); 00036 ON_Matrix( const ON_Xform& ); 00037 ON_Matrix( const ON_Matrix& ); 00038 00039 /* 00040 Description: 00041 This constructor is for experts who have storage for a matrix 00042 and need to use it in ON_Matrix form. 00043 Parameters: 00044 row_count - [in] 00045 col_count - [in] 00046 M - [in] 00047 bDestructorFreeM - [in] 00048 If true, ~ON_Matrix will call onfree(M). 00049 If false, caller is managing M's memory. 00050 Remarks: 00051 ON_Matrix functions that increase the value of row_count or col_count 00052 will fail on a matrix created with this constructor. 00053 */ 00054 ON_Matrix( 00055 int row_count, 00056 int col_count, 00057 double** M, 00058 bool bDestructorFreeM 00059 ); 00060 00061 virtual ~ON_Matrix(); 00062 void EmergencyDestroy(); // call if memory pool used matrix by becomes invalid 00063 00064 // ON_Matrix[i][j] = value at row i and column j 00065 // 0 <= i < RowCount() 00066 // 0 <= j < ColCount() 00067 double* operator[](int); 00068 const double* operator[](int) const; 00069 00070 ON_Matrix& operator=(const ON_Matrix&); 00071 ON_Matrix& operator=(const ON_Xform&); 00072 00073 bool IsValid() const; 00074 int IsSquare() const; // returns 0 for no and m_row_count (= m_col_count) for yes 00075 int RowCount() const; 00076 int ColCount() const; 00077 int MinCount() const; // smallest of row and column count 00078 int MaxCount() const; // largest of row and column count 00079 00080 void RowScale(int,double); 00081 void ColScale(int,double); 00082 void RowOp(int,double,int); 00083 void ColOp(int,double,int); 00084 00085 bool Create( 00086 int, // number of rows 00087 int // number of columns 00088 ); 00089 00090 bool Create( // E.g., Create(1,5,1,7) creates a 5x7 sized matrix that with 00091 // "top" row = m[1][1],...,m[1][7] and "bottom" row 00092 // = m[5][1],...,m[5][7]. The result of Create(0,m,0,n) is 00093 // identical to the result of Create(m+1,n+1). 00094 int, // first valid row index 00095 int, // last valid row index 00096 int, // first valid column index 00097 int // last valid column index 00098 ); 00099 00100 /* 00101 Description: 00102 This constructor is for experts who have storage for a matrix 00103 and need to use it in ON_Matrix form. 00104 Parameters: 00105 row_count - [in] 00106 col_count - [in] 00107 M - [in] 00108 bDestructorFreeM - [in] 00109 If true, ~ON_Matrix will call onfree(M). 00110 If false, caller is managing M's memory. 00111 Remarks: 00112 ON_Matrix functions that increase the value of row_count or col_count 00113 will fail on a matrix created with this constructor. 00114 */ 00115 bool Create( 00116 int row_count, 00117 int col_count, 00118 double** M, 00119 bool bDestructorFreeM 00120 ); 00121 00122 00123 void Destroy(); 00124 00125 void Zero(); 00126 00127 void SetDiagonal(double); // sets diagonal value and zeros off diagonal values 00128 void SetDiagonal(const double*); // sets diagonal values and zeros off diagonal values 00129 void SetDiagonal(int, const double*); // sets size to count x count and diagonal values and zeros off diagonal values 00130 void SetDiagonal(const ON_SimpleArray<double>&); // sets size to length X lengthdiagonal values and zeros off diagonal values 00131 00132 bool Transpose(); 00133 00134 bool SwapRows( int, int ); // ints are row indices to swap 00135 bool SwapCols( int, int ); // ints are col indices to swap 00136 bool Invert( 00137 double // zero tolerance 00138 ); 00139 00140 /* 00141 Description: 00142 Set this = A*B. 00143 Parameters: 00144 A - [in] 00145 (Can be this) 00146 B - [in] 00147 (Can be this) 00148 Returns: 00149 True when A is an mXk matrix and B is a k X n matrix; in which case 00150 "this" will be an mXn matrix = A*B. 00151 False when A.ColCount() != B.RowCount(). 00152 */ 00153 bool Multiply( const ON_Matrix& A, const ON_Matrix& B ); 00154 00155 /* 00156 Description: 00157 Set this = A+B. 00158 Parameters: 00159 A - [in] 00160 (Can be this) 00161 B - [in] 00162 (Can be this) 00163 Returns: 00164 True when A and B are mXn matrices; in which case 00165 "this" will be an mXn matrix = A+B. 00166 False when A and B have different sizes. 00167 */ 00168 bool Add( const ON_Matrix& A, const ON_Matrix& B ); 00169 00170 00171 /* 00172 Description: 00173 Set this = s*this. 00174 Parameters: 00175 s - [in] 00176 Returns: 00177 True when A and s are valid. 00178 */ 00179 bool Scale( double s ); 00180 00181 00182 // Description: 00183 // Row reduce a matrix to calculate rank and determinant. 00184 // Parameters: 00185 // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test 00186 // If the absolute value of a pivot is <= zero_tolerance, 00187 // then the pivot is assumed to be zero. 00188 // determinant - [out] value of determinant is returned here. 00189 // pivot - [out] value of the smallest pivot is returned here 00190 // Returns: 00191 // Rank of the matrix. 00192 // Remarks: 00193 // The matrix itself is row reduced so that the result is 00194 // an upper triangular matrix with 1's on the diagonal. 00195 int RowReduce( // returns rank 00196 double, // zero_tolerance 00197 double&, // determinant 00198 double& // pivot 00199 ); 00200 00201 // Description: 00202 // Row reduce a matrix as the first step in solving M*X=B where 00203 // B is a column of values. 00204 // Parameters: 00205 // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test 00206 // If the absolute value of a pivot is <= zero_tolerance, 00207 // then the pivot is assumed to be zero. 00208 // B - [in/out] an array of m_row_count values that is row reduced 00209 // with the matrix. 00210 // determinant - [out] value of determinant is returned here. 00211 // pivot - [out] If not NULL, then the value of the smallest 00212 // pivot is returned here 00213 // Returns: 00214 // Rank of the matrix. 00215 // Remarks: 00216 // The matrix itself is row reduced so that the result is 00217 // an upper triangular matrix with 1's on the diagonal. 00218 // Example: 00219 // Solve M*X=B; 00220 // double B[m] = ...; 00221 // double B[n] = ...; 00222 // ON_Matrix M(m,n) = ...; 00223 // M.RowReduce(ON_ZERO_TOLERANCE,B); // modifies M and B 00224 // M.BackSolve(m,B,X); // solution is in X 00225 // See Also: 00226 // ON_Matrix::BackSolve 00227 int RowReduce( 00228 double, // zero_tolerance 00229 double*, // B 00230 double* = NULL // pivot 00231 ); 00232 00233 // Description: 00234 // Row reduce a matrix as the first step in solving M*X=B where 00235 // B is a column of 3d points 00236 // Parameters: 00237 // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test 00238 // If the absolute value of a pivot is <= zero_tolerance, 00239 // then the pivot is assumed to be zero. 00240 // B - [in/out] an array of m_row_count 3d points that is 00241 // row reduced with the matrix. 00242 // determinant - [out] value of determinant is returned here. 00243 // pivot - [out] If not NULL, then the value of the smallest 00244 // pivot is returned here 00245 // Returns: 00246 // Rank of the matrix. 00247 // Remarks: 00248 // The matrix itself is row reduced so that the result is 00249 // an upper triangular matrix with 1's on the diagonal. 00250 // See Also: 00251 // ON_Matrix::BackSolve 00252 int RowReduce( 00253 double, // zero_tolerance 00254 ON_3dPoint*, // B 00255 double* = NULL // pivot 00256 ); 00257 00258 // Description: 00259 // Row reduce a matrix as the first step in solving M*X=B where 00260 // B is a column arbitrary dimension points. 00261 // Parameters: 00262 // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test 00263 // If a the absolute value of a pivot is <= zero_tolerance, 00264 // then the pivoit is assumed to be zero. 00265 // pt_dim - [in] dimension of points 00266 // pt_stride - [in] stride between points (>=pt_dim) 00267 // pt - [in/out] array of m_row_count*pt_stride values. 00268 // The i-th point is 00269 // (pt[i*pt_stride],...,pt[i*pt_stride+pt_dim-1]). 00270 // This array of points is row reduced along with the 00271 // matrix. 00272 // pivot - [out] If not NULL, then the value of the smallest 00273 // pivot is returned here 00274 // Returns: 00275 // Rank of the matrix. 00276 // Remarks: 00277 // The matrix itself is row reduced so that the result is 00278 // an upper triangular matrix with 1's on the diagonal. 00279 // See Also: 00280 // ON_Matrix::BackSolve 00281 int RowReduce( // returns rank 00282 double, // zero_tolerance 00283 int, // pt_dim 00284 int, // pt_stride 00285 double*, // pt 00286 double* = NULL // pivot 00287 ); 00288 00289 // Description: 00290 // Solve M*X=B where M is upper triangular with a unit diagonal and 00291 // B is a column of values. 00292 // Parameters: 00293 // zero_tolerance - [in] (>=0.0) used to test for "zero" values in B 00294 // in under determined systems of equations. 00295 // Bsize - [in] (>=m_row_count) length of B. The values in 00296 // B[m_row_count],...,B[Bsize-1] are tested to make sure they are 00297 // "zero". 00298 // B - [in] array of length Bsize. 00299 // X - [out] array of length m_col_count. Solutions returned here. 00300 // Remarks: 00301 // Actual values M[i][j] with i <= j are ignored. 00302 // M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero. 00303 // For square M, B and X can point to the same memory. 00304 // See Also: 00305 // ON_Matrix::RowReduce 00306 bool BackSolve( 00307 double, // zero_tolerance 00308 int, // Bsize 00309 const double*, // B 00310 double* // X 00311 ) const; 00312 00313 // Description: 00314 // Solve M*X=B where M is upper triangular with a unit diagonal and 00315 // B is a column of 3d points. 00316 // Parameters: 00317 // zero_tolerance - [in] (>=0.0) used to test for "zero" values in B 00318 // in under determined systems of equations. 00319 // Bsize - [in] (>=m_row_count) length of B. The values in 00320 // B[m_row_count],...,B[Bsize-1] are tested to make sure they are 00321 // "zero". 00322 // B - [in] array of length Bsize. 00323 // X - [out] array of length m_col_count. Solutions returned here. 00324 // Remarks: 00325 // Actual values M[i][j] with i <= j are ignored. 00326 // M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero. 00327 // For square M, B and X can point to the same memory. 00328 // See Also: 00329 // ON_Matrix::RowReduce 00330 bool BackSolve( 00331 double, // zero_tolerance 00332 int, // Bsize 00333 const ON_3dPoint*, // B 00334 ON_3dPoint* // X 00335 ) const; 00336 00337 // Description: 00338 // Solve M*X=B where M is upper triangular with a unit diagonal and 00339 // B is a column of points 00340 // Parameters: 00341 // zero_tolerance - [in] (>=0.0) used to test for "zero" values in B 00342 // in under determined systems of equations. 00343 // pt_dim - [in] dimension of points 00344 // Bsize - [in] (>=m_row_count) number of points in B[]. The points 00345 // correspoinding to indices m_row_count, ..., (Bsize-1) 00346 // are tested to make sure they are "zero". 00347 // Bpt_stride - [in] stride between B points (>=pt_dim) 00348 // Bpt - [in/out] array of m_row_count*Bpt_stride values. 00349 // The i-th B point is 00350 // (Bpt[i*Bpt_stride],...,Bpt[i*Bpt_stride+pt_dim-1]). 00351 // Xpt_stride - [in] stride between X points (>=pt_dim) 00352 // Xpt - [out] array of m_col_count*Xpt_stride values. 00353 // The i-th X point is 00354 // (Xpt[i*Xpt_stride],...,Xpt[i*Xpt_stride+pt_dim-1]). 00355 // Remarks: 00356 // Actual values M[i][j] with i <= j are ignored. 00357 // M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero. 00358 // For square M, B and X can point to the same memory. 00359 // See Also: 00360 // ON_Matrix::RowReduce 00361 bool BackSolve( 00362 double, // zero_tolerance 00363 int, // pt_dim 00364 int, // Bsize 00365 int, // Bpt_stride 00366 const double*,// Bpt 00367 int, // Xpt_stride 00368 double* // Xpt 00369 ) const; 00370 00371 bool IsRowOrthoganal() const; 00372 bool IsRowOrthoNormal() const; 00373 00374 bool IsColOrthoganal() const; 00375 bool IsColOrthoNormal() const; 00376 00377 00378 double** m; // m[i][j] = value at row i and column j 00379 // 0 <= i < RowCount() 00380 // 0 <= j < ColCount() 00381 private: 00382 int m_row_count; 00383 int m_col_count; 00384 // m_rowmem[i][j] = row i+m_row_offset and column j+m_col_offset. 00385 ON_SimpleArray<double*> m_rowmem; 00386 double** m_Mmem; // used by Create(row_count,col_count,user_memory,true); 00387 int m_row_offset; // = ri0 when sub-matrix constructor is used 00388 int m_col_offset; // = ci0 when sub-matrix constructor is used 00389 void* m_cmem; 00390 // returns 0 based arrays, even in submatrix case. 00391 double const * const * ThisM() const; 00392 double * * ThisM(); 00393 }; 00394 00395 /* 00396 Description: 00397 Calculate the singular value decomposition of a matrix. 00398 00399 Parameters: 00400 row_count - [in] 00401 number of rows in matrix A 00402 col_count - [in] 00403 number of columns in matrix A 00404 A - [in] 00405 Matrix for which you want the singular value decomposition. 00406 A[0][0] = coefficeint in the first row and first column. 00407 A[row_count-1][col_count-1] = coefficeint in the last row 00408 and last column. 00409 U - [out] 00410 The singular value decomposition of A is U*Diag(W)*Transpose(V), 00411 where U has the same size as A, Diag(W) is a col_count X col_count 00412 diagonal matrix with (W[0],...,W[col_count-1]) on the diagonal 00413 and V is a col_count X col_count matrix. 00414 U and A may be the same pointer. If the input value of U is 00415 null, heap storage will be allocated using onmalloc() 00416 and the calling function must call onfree(U). If the input 00417 value of U is not null, U[i] must point to an array of col_count 00418 doubles. 00419 W - [out] 00420 If the input value W is null, then heap storage will be allocated 00421 using onmalloc() and the calling function must call onfree(W). 00422 If the input value of W is not null, then W must point to 00423 an array of col_count doubles. 00424 V - [out] 00425 If the input value V is null, then heap storage will be allocated 00426 using onmalloc() and the calling function must call onfree(V). 00427 If the input value of V is not null, then V[i] must point 00428 to an array of col_count doubles. 00429 00430 Example: 00431 00432 int m = row_count; 00433 int n = col_count; 00434 ON_Matrix A(m,n); 00435 for (i = 0; i < m; i++ ) for ( j = 0; j < n; j++ ) 00436 { 00437 A[i][j] = ...; 00438 } 00439 ON_Matrix U(m,n); 00440 double* W = 0; // ON_GetMatrixSVD() will allocate W 00441 ON_Matrix V(n,n); 00442 bool rc = ON_GetMatrixSVD(m,n,A.m,U.m,W,V.m); 00443 ... 00444 onfree(W); // W allocated in ON_GetMatrixSVD() 00445 00446 Returns: 00447 True if the singular value decomposition was cacluated. 00448 False if the algorithm failed to converge. 00449 */ 00450 ON_DECL 00451 bool ON_GetMatrixSVD( 00452 int row_count, 00453 int col_count, 00454 double const * const * A, 00455 double**& U, 00456 double*& W, 00457 double**& V 00458 ); 00459 00460 /* 00461 Description: 00462 Invert the diagonal matrix in a the singular value decomposition. 00463 Parameters: 00464 count - [in] number of elements in W 00465 W - [in] 00466 diagonal values in the singular value decomposition. 00467 invW - [out] 00468 The inverted diagonal is returned here. invW may be the same 00469 pointer as W. If the input value of invW is not null, it must 00470 point to an array of count doubles. If the input value of 00471 invW is null, heap storage will be allocated using onmalloc() 00472 and the calling function must call onfree(invW). 00473 Remarks: 00474 If the singular value decomposition were mathematically perfect, then 00475 this function would be: 00476 for (i = 0; i < count; i++) 00477 invW[i] = (W[i] != 0.0) ? 1.0/W[i] : 0.0; 00478 Because the double precision arithmetic is not mathematically perfect, 00479 very small values of W[i] may well be zero and this function makes 00480 a reasonable guess as to when W[i] should be treated as zero. 00481 Returns: 00482 Number of non-zero elements in invW, which, in a mathematically perfect 00483 situation, is the rank of Diag(W). 00484 */ 00485 ON_DECL 00486 int ON_InvertSVDW( 00487 int count, 00488 const double* W, 00489 double*& invW 00490 ); 00491 00492 /* 00493 Description: 00494 Solve a linear system of equations using the singular value decomposition. 00495 Parameters: 00496 row_count - [in] 00497 number of rows in matrix U 00498 col_count - [in] 00499 number of columns in matrix U 00500 U - [in] 00501 row_count X col_count matix. 00502 See the remarks section for the definition of U. 00503 invW - [in] 00504 inverted DVD diagonal. 00505 See the remarks section for the definition of invW. 00506 V - [in] 00507 col_count X col_count matrix. 00508 See the remarks section for the definition of V. 00509 B - [in] 00510 An array of row_count values. 00511 X - [out] 00512 The solution array of col_count values is returned here. 00513 If the input value of X is not null, it must point to an 00514 array of col_count doubles. If the input value of X is 00515 null, heap storage will be allocated using onmalloc() and 00516 the calling function must call onfree(X). 00517 Remarks: 00518 If A*X = B is an m X n system of equations (m = row_count, n = col_count) 00519 and A = U*Diag(W)*Transpose(V) is the singular value decompostion of A, 00520 then a solution is X = V*Diag(1/W)*Transpose(U). 00521 Example: 00522 00523 int m = row_count; 00524 int n = col_count; 00525 ON_Matrix A(m,n); 00526 for (i = 0; i < m; i++ ) for ( j = 0; j < n; j++ ) 00527 { 00528 A[i][j] = ...; 00529 } 00530 ON_SimpleArray<double> B(m); 00531 for (i = 0; i < m; i++ ) 00532 { 00533 B[i] = ...; 00534 } 00535 00536 ON_SimpleArray<double> X; // solution returned here. 00537 { 00538 double** U = 0; 00539 double* W = 0; 00540 double** V = 0; 00541 if ( ON_GetMatrixSVD(m,n,A.m,U,W,V) ) 00542 { 00543 double* invW = 0; 00544 int rankW = ON_InvertSVDW(n,W,W); // save invW into W 00545 X.Reserve(n); 00546 if ( ON_SolveSVD(m,n,U,W,V,B,X.Array()) ) 00547 X.SetCount(n); 00548 } 00549 onfree(U); // U allocated in ON_GetMatrixSVD() 00550 onfree(W); // W allocated in ON_GetMatrixSVD() 00551 onfree(V); // V allocated in ON_GetMatrixSVD() 00552 } 00553 00554 if ( n == X.Count() ) 00555 { 00556 ... use solution 00557 } 00558 Returns: 00559 True if input is valid and X[] was calculated. 00560 False if input is not valid. 00561 */ 00562 ON_DECL 00563 bool ON_SolveSVD( 00564 int row_count, 00565 int col_count, 00566 double const * const * U, 00567 const double* invW, 00568 double const * const * V, 00569 const double* B, 00570 double*& X 00571 ); 00572 00573 00574 /* 00575 Description: 00576 Perform simple row reduction on a matrix. If A is square, positive 00577 definite, and really really nice, then the returned B is the inverse 00578 of A. If A is not positive definite and really really nice, then it 00579 is probably a waste of time to call this function. 00580 Parameters: 00581 row_count - [in] 00582 col_count - [in] 00583 zero_pivot - [in] 00584 absolute values <= zero_pivot are considered to be zero 00585 A - [in/out] 00586 A row_count X col_count matrix. Input is the matrix to be 00587 row reduced. The calculation destroys A, so output A is garbage. 00588 B - [out] 00589 A a row_count X row_count matrix. That records the row reduction. 00590 pivots - [out] 00591 minimum and maximum absolute values of pivots. 00592 Returns: 00593 Rank of A. If the returned value < min(row_count,col_count), 00594 then a zero pivot was encountered. 00595 If C = input value of A, then B*C = (I,*) 00596 */ 00597 ON_DECL 00598 int ON_RowReduce( 00599 int row_count, 00600 int col_count, 00601 double zero_pivot, 00602 double** A, 00603 double** B, 00604 double pivots[2] 00605 ); 00606 00607 #endif