cgma
|
00001 //- Class: CubitMatrix 00002 //- Description: This file defines the CubitMatrix class. 00003 //- Owner: Dan Goodrich 00004 //- Checked by: 00005 00006 #include <cassert> 00007 00008 #include "CubitMatrix.hpp" 00009 #include "CubitMessage.hpp" 00010 #include "CubitVector.hpp" 00011 #include "CubitDefines.h" 00012 #include "CubitFile.hpp" 00013 00014 CubitMatrix::CubitMatrix() 00015 { 00016 matrixMem = NULL; 00017 matrixPtr = NULL; 00018 reset_size( 3, 3 ); 00019 } 00020 00021 CubitMatrix::CubitMatrix( const int n, const int m ) 00022 { 00023 matrixMem = NULL; 00024 matrixPtr = NULL; 00025 reset_size( n, m ); 00026 } 00027 00028 00029 CubitMatrix::CubitMatrix( const int n ) 00030 { 00031 matrixMem = NULL; 00032 matrixPtr = NULL; 00033 reset_size( n, n ); 00034 00035 // Initialize matrix to identity. 00036 set_to_identity(); 00037 } 00038 00039 CubitMatrix::CubitMatrix (const CubitVector& vec1, 00040 const CubitVector& vec2, 00041 const CubitVector& vec3 ) 00042 { 00043 matrixMem = NULL; 00044 matrixPtr = NULL; 00045 reset_size( 3, 3 ); 00046 00047 // Initialize the matrix columns to the three vectors 00048 matrixPtr[0][0] = vec1.x(); 00049 matrixPtr[1][0] = vec1.y(); 00050 matrixPtr[2][0] = vec1.z(); 00051 matrixPtr[0][1] = vec2.x(); 00052 matrixPtr[1][1] = vec2.y(); 00053 matrixPtr[2][1] = vec2.z(); 00054 matrixPtr[0][2] = vec3.x(); 00055 matrixPtr[1][2] = vec3.y(); 00056 matrixPtr[2][2] = vec3.z(); 00057 } 00058 00059 CubitMatrix::CubitMatrix (const CubitVector& vec1, 00060 const CubitVector& vec2, 00061 const CubitVector& vec3, 00062 const CubitVector& vec4 ) 00063 { 00064 matrixMem = NULL; 00065 matrixPtr = NULL; 00066 reset_size( 3, 4 ); 00067 00068 // Initialize the matrix columns to the four vectors 00069 matrixPtr[0][0] = vec1.x(); 00070 matrixPtr[1][0] = vec1.y(); 00071 matrixPtr[2][0] = vec1.z(); 00072 matrixPtr[0][1] = vec2.x(); 00073 matrixPtr[1][1] = vec2.y(); 00074 matrixPtr[2][1] = vec2.z(); 00075 matrixPtr[0][2] = vec3.x(); 00076 matrixPtr[1][2] = vec3.y(); 00077 matrixPtr[2][2] = vec3.z(); 00078 matrixPtr[0][3] = vec4.x(); 00079 matrixPtr[1][3] = vec4.y(); 00080 matrixPtr[2][3] = vec4.z(); 00081 } 00082 00083 CubitMatrix::CubitMatrix(const CubitVector& vec1, 00084 const CubitVector& vec2 ) 00085 { 00086 matrixMem = NULL; 00087 matrixPtr = NULL; 00088 reset_size( 3, 3 ); 00089 00090 this->vector_outer_product(vec1, vec2); 00091 } 00092 00093 CubitMatrix::CubitMatrix 00094 ( 00095 std::vector<int> &is, 00096 std::vector<int> &js, 00097 std::vector<double> &es, 00098 int n, 00099 int m 00100 ) 00101 { 00102 matrixMem = NULL; 00103 matrixPtr = NULL; 00104 reset_size( n, m ); 00105 int length = is.size(); 00106 for ( int k = 0; k < length; k++ ) 00107 { 00108 int i = is[k]; 00109 int j = js[k]; 00110 matrixPtr[i][j] += es[k]; 00111 } 00112 } 00113 00114 CubitMatrix::CubitMatrix( const CubitMatrix &matrix ) 00115 { 00116 matrixMem = NULL; 00117 matrixPtr = NULL; 00118 reset_size( matrix.num_rows(), matrix.num_cols() ); 00119 00120 int ii; 00121 for( ii = 0; ii < numRows; ii++ ) 00122 { 00123 for( int jj = 0; jj < numCols; jj++ ) 00124 matrixPtr[ii][jj] = matrix.get( ii, jj ); 00125 } 00126 } 00127 00128 00129 00130 CubitMatrix::~CubitMatrix() 00131 { 00132 delete [] matrixPtr; 00133 delete [] matrixMem; 00134 } 00135 00136 void CubitMatrix::reset_size( const int n, const int m, double default_value ) 00137 { 00138 if ( matrixPtr ) delete [] matrixPtr; 00139 if ( matrixMem ) delete [] matrixMem; 00140 00141 numRows = n; 00142 numCols = m; 00143 00144 matrixMem = new double[numRows*numCols]; 00145 matrixPtr = new double *[n]; 00146 00147 int ii; 00148 for( ii = 0; ii < n; ii++ ) 00149 { 00150 matrixPtr[ii] = &matrixMem[ii*numCols]; 00151 } 00152 00153 // Initialize matrix to zeros. 00154 for( ii = 0; ii < n; ii++ ) 00155 for( int jj = 0 ; jj < m; jj++ ) 00156 matrixPtr[ii][jj] = default_value; 00157 } 00158 00159 void CubitMatrix::print_matrix() const 00160 { 00161 printf( "\n\n" ); 00162 for( int row = 0; row < numRows; row++ ) 00163 { 00164 for( int col = 0; col < numCols; col++ ) 00165 PRINT_INFO("%25.15f", matrixPtr[row][col]); 00166 PRINT_INFO("\n"); 00167 } 00168 } 00169 void CubitMatrix::print_matrix( char *filename ) const 00170 { 00171 CubitFile fp( filename, "w" ); 00172 if ( !fp ) 00173 { 00174 printf( "CubitMatrix::print_matrix - Unable to open %s for writing\n", 00175 filename ); 00176 return; 00177 } 00178 00179 for( int row = 0; row < numRows; row++ ) 00180 { 00181 for( int col = 0; col < numCols; col++ ) 00182 fprintf( fp.file(), "%20.15f", matrixPtr[row][col] ); 00183 fprintf( fp.file(), "\n" ); 00184 } 00185 } 00186 00187 // Sets this matrix equal to 'matrix'. 'this' is 00188 // redimensioned if needed. 00189 CubitMatrix CubitMatrix::operator=(const CubitMatrix& matrix) 00190 { 00191 int i, j; 00192 00193 if (numRows != matrix.num_rows() || 00194 numCols != matrix.num_cols()) 00195 { 00196 delete [] matrixPtr; 00197 delete [] matrixMem; 00198 00199 numRows = matrix.num_rows(); 00200 numCols = matrix.num_cols(); 00201 matrixPtr = new double*[numRows]; 00202 matrixMem = new double[numRows*numCols]; 00203 for (i = 0; i < numRows; i++) 00204 matrixPtr[i] = &matrixMem[i*numCols]; 00205 } 00206 00207 for(i = 0; i < numRows; i++ ) 00208 for(j = 0; j < numCols; j++) 00209 matrixPtr[i][j] = matrix.get(i, j); 00210 00211 return *this; 00212 } 00213 00214 00215 // Multiply this ( size NxM ) with the input matrix ( size MxL ). 00216 // return matrix of size NxL 00217 CubitMatrix CubitMatrix::operator*(const CubitMatrix& matrix ) const 00218 { 00219 // Check that we can multiply them. 00220 if(numCols != matrix.num_rows()) 00221 throw std::invalid_argument ("# of columns in first MUST match # of rows of second"); 00222 //assert( numCols == matrix.num_rows() ); 00223 00224 CubitMatrix return_matrix( numRows, matrix.num_cols() ); 00225 00226 for( int ii = 0; ii < numRows; ii++ ) 00227 { 00228 for( int jj = 0; jj < matrix.num_cols(); jj++ ) 00229 { 00230 double temp = 0.0; 00231 for( int kk = 0; kk < numCols; kk++ ) 00232 { 00233 //temp += get( ii, kk ) * matrix.get( kk, jj ); 00234 temp += matrixPtr[ii][kk] * matrix.matrixPtr[kk][jj]; 00235 } 00236 return_matrix.set( ii, jj, temp ); 00237 } 00238 } 00239 return return_matrix; 00240 } 00241 00242 00243 00244 // multiply this times the input vector 00245 CubitVector CubitMatrix::operator* (const CubitVector& vector ) const 00246 { 00247 // Check that we can multiply them. 00248 if(numCols!=3) 00249 { 00250 throw std::invalid_argument("Matrix must have 3 columns"); 00251 } 00252 //assert( numCols == 3 ); 00253 00254 double vec1[3]; 00255 double vec2[3]; 00256 00257 vec2[0] = vector.x(); 00258 vec2[1] = vector.y(); 00259 vec2[2] = vector.z(); 00260 00261 for( int row = 0; row < numRows; row++ ) 00262 { 00263 vec1[row] = 0.0; 00264 for( int col = 0; col < numCols; col++ ) 00265 { 00266 vec1[row] += ( matrixPtr[row][col] * vec2[col] ); 00267 } 00268 } 00269 00270 return CubitVector( vec1[0], vec1[1], vec1[2] ); 00271 } 00272 00273 // multiply this times the input vector 00274 std::vector<double> CubitMatrix::operator* (const std::vector<double> & vector) const 00275 { 00276 // Check that we can multiply them. 00277 if(numCols != (int) vector.size()) 00278 throw std::invalid_argument ("Columns of Matrix do not match vector size"); 00279 //assert( numCols == vector.size() ); 00280 00281 std::vector<double> return_vec( numRows ); 00282 00283 for( int row = 0; row < numRows; row++ ) 00284 { 00285 return_vec[row] = 0.0; 00286 for( int col = 0; col < numCols; col++ ) 00287 { 00288 return_vec[row] += ( matrixPtr[row][col] * vector[col] ); 00289 } 00290 } 00291 00292 return return_vec; 00293 } 00294 00295 // multiply this times the input scalar 00296 CubitMatrix CubitMatrix::operator*( double val ) const 00297 { 00298 CubitMatrix matrix( numRows, numCols ); 00299 00300 for( int row = 0; row < numRows; row++ ) 00301 { 00302 for( int col = 0; col < numCols; col++ ) 00303 { 00304 matrix.set( row, col,( matrixPtr[row][col] * val ) ); 00305 } 00306 } 00307 return matrix; 00308 } 00309 00310 // multiply this times the input scalar 00311 CubitMatrix CubitMatrix::operator/( double val ) const 00312 { 00313 if(val==0) 00314 throw std::invalid_argument("Cannot Divide by Zero"); 00315 //assert( val != 0 ); 00316 CubitMatrix matrix( numRows, numCols ); 00317 00318 for( int ii = 0; ii < numRows; ii++ ) 00319 { 00320 for( int jj = 0; jj < numCols; jj++ ) 00321 { 00322 matrix.set( ii, jj,( matrixPtr[ii][jj] / val ) ); 00323 } 00324 } 00325 return matrix; 00326 } 00327 00328 00329 // subtract this ( size NxM ) with the input matrix ( size NxM ). 00330 // return matrix of size NxM 00331 CubitMatrix CubitMatrix::operator-(const CubitMatrix& matrix) const 00332 { 00333 CubitMatrix return_matrix( numRows, numCols ); 00334 00335 for( int ii = 0; ii < numRows; ii++ ) 00336 { 00337 for( int jj = 0; jj < numCols; jj++ ) 00338 { 00339 return_matrix.set( ii, jj, matrixPtr[ii][jj] - 00340 matrix.get( ii, jj )); 00341 } 00342 } 00343 00344 return return_matrix; 00345 } 00346 00347 // add this ( size NxM ) with the input matrix ( size NxM ). 00348 // return matrix of size NxM 00349 CubitMatrix CubitMatrix::operator+(const CubitMatrix& matrix ) const 00350 { 00351 CubitMatrix return_matrix( numRows, numCols ); 00352 00353 for( int ii = 0; ii < numRows; ii++ ) 00354 { 00355 for( int jj = 0; jj < numCols; jj++ ) 00356 { 00357 return_matrix.set( ii, jj, matrixPtr[ii][jj] + 00358 matrix.get( ii, jj )); 00359 } 00360 } 00361 00362 return return_matrix; 00363 } 00364 00365 00366 CubitMatrix& CubitMatrix::operator+=( const CubitMatrix &matrix ) 00367 { 00368 for( int ii = 0; ii < numRows; ii++ ) 00369 { 00370 for( int jj = 0; jj < numCols; jj++ ) 00371 { 00372 matrixPtr[ii][jj] += matrix.get( ii, jj ); 00373 } 00374 } 00375 return *this; 00376 } 00377 00378 CubitMatrix& CubitMatrix::operator*=(const double multiplier) 00379 { 00380 for( int ii = 0; ii < numRows; ii++ ) 00381 { 00382 for( int jj = 0; jj < numCols; jj++ ) 00383 { 00384 matrixPtr[ii][jj] *= multiplier; 00385 } 00386 } 00387 return *this; 00388 } 00389 00390 // Sets the matrix to all zeros except along diagonal. 00391 // Matrix doesn't have to be square. 00392 void CubitMatrix::set_to_identity() 00393 { 00394 for (int i = numRows; i--; ) 00395 for (int j = numCols; j--; ) 00396 { 00397 if (i == j) 00398 matrixPtr[i][j] = 1; 00399 else 00400 matrixPtr[i][j] = 0; 00401 } 00402 } 00403 00404 /* 00405 // Inverts this matrix, if it is of size NxN, and a 3x3 or 00406 // smaller. 00407 CubitMatrix CubitMatrix::inverse() 00408 { 00409 CubitMatrix adj_matrix( numRows, numCols ); 00410 double det; 00411 00412 if( numRows > 4 ) 00413 { 00414 // rval = recipie_inverse(); 00415 // return rval == CUBIT_TRUE ? CUBIT_TRUE : CUBIT_FALSE; 00416 PRINT_INFO("Can't handle matrice's greater than 3x3 yet.\n"); 00417 } 00418 00419 det = determinant(); 00420 assert( fabs(det) > CUBIT_DBL_MIN ); 00421 00422 adj_matrix = adjoint(); 00423 return adj_matrix * ( 1.0/det ); 00424 } 00425 */ 00426 00427 // Inverts this matrix, if it is size 4x4 or bigger 00428 // uses ludcmp and lubksb from numerical recipes. 00429 CubitMatrix CubitMatrix::inverse() 00430 { 00431 // can't invert a non-square matrix 00432 if(numRows!=numCols) 00433 throw std::invalid_argument ("Cannot invert a non-Square matrix"); 00434 //assert(numRows == numCols); 00435 00436 CubitMatrix matrix_inverse( numRows, numCols ); 00437 00438 if (numRows <4) 00439 { 00440 double det; 00441 det = determinant(); 00442 if(fabs(det) <= CUBIT_DBL_MIN) 00443 throw std::invalid_argument ("Determinants Absolute value must be greater that CUBIT_DBL_MIN"); 00444 //assert( fabs(det) > CUBIT_DBL_MIN ); 00445 double det_inv = 1./det; 00446 00447 if ( numRows == 1 ) { 00448 det = determinant(); 00449 if(fabs(det) <= CUBIT_DBL_MIN) 00450 throw std::invalid_argument ("Determinants Absolute value must be greater that CUBIT_DBL_MIN"); 00451 //assert( fabs(det) > CUBIT_DBL_MIN ); 00452 00453 matrix_inverse.set(0,0, matrixPtr[0][0]); 00454 } 00455 00456 if ( numRows == 2 ) { 00457 matrix_inverse.set(0,0, matrixPtr[1][1]); 00458 matrix_inverse.set(1,0,-matrixPtr[1][0]); 00459 matrix_inverse.set(0,1,-matrixPtr[0][1]); 00460 matrix_inverse.set(1,1, matrixPtr[0][0]); 00461 } 00462 00463 if ( numRows == 3 ) { 00464 matrix_inverse.set(0,0, matrixPtr[1][1] * matrixPtr[2][2] - matrixPtr[1][2] * matrixPtr[2][1] ); 00465 matrix_inverse.set(1,0, matrixPtr[2][0] * matrixPtr[1][2] - matrixPtr[1][0] * matrixPtr[2][2] ); 00466 matrix_inverse.set(2,0, matrixPtr[1][0] * matrixPtr[2][1] - matrixPtr[1][1] * matrixPtr[2][0] ); 00467 matrix_inverse.set(0,1, matrixPtr[2][1] * matrixPtr[0][2] - matrixPtr[0][1] * matrixPtr[2][2] ); 00468 matrix_inverse.set(1,1, matrixPtr[0][0] * matrixPtr[2][2] - matrixPtr[0][2] * matrixPtr[2][0] ); 00469 matrix_inverse.set(2,1, matrixPtr[0][1] * matrixPtr[2][0] - matrixPtr[0][0] * matrixPtr[2][1] ); 00470 matrix_inverse.set(0,2, matrixPtr[0][1] * matrixPtr[1][2] - matrixPtr[0][2] * matrixPtr[1][1] ); 00471 matrix_inverse.set(1,2, matrixPtr[1][0] * matrixPtr[0][2] - matrixPtr[0][0] * matrixPtr[1][2] ); 00472 matrix_inverse.set(2,2, matrixPtr[0][0] * matrixPtr[1][1] - matrixPtr[1][0] * matrixPtr[0][1] ); 00473 00474 } 00475 matrix_inverse *= det_inv; 00476 } 00477 else 00478 { 00479 00480 // use numerical recipes Inverse of a Matrix 00481 00482 int i, j; 00483 double d; 00484 std::vector<double> indx(numRows); 00485 std::vector<double> col(numRows); 00486 CubitMatrix save_matrix = *this; 00487 00488 CubitStatus rv = ludcmp(&indx[0], d); 00489 if(rv != CUBIT_SUCCESS) 00490 throw std::invalid_argument ("rv must equal CUBIT_SUCCESS"); 00491 //assert(rv == CUBIT_SUCCESS); 00492 for (j=0; j<numRows; j++) 00493 { 00494 for(i=0; i<numRows; i++) 00495 { 00496 col[i] = 0.0; 00497 } 00498 col[j] = 1.0; 00499 rv = lubksb(&indx[0], &col[0]); 00500 if(rv != CUBIT_SUCCESS) 00501 throw std::invalid_argument ("rv must equal CUBIT_SUCCESS"); 00502 //assert(rv == CUBIT_SUCCESS); 00503 for (i=0; i<numRows; i++) 00504 { 00505 matrix_inverse.set(i,j,col[i]); 00506 } 00507 } 00508 *this = save_matrix; 00509 } 00510 00511 return matrix_inverse; 00512 } 00513 00514 CubitBoolean CubitMatrix::positive_definite() const 00515 { 00516 00517 if ( matrixPtr[0][0] <= 0. ) { return CUBIT_FALSE; } 00518 00519 double det2x2 = matrixPtr[0][0] * matrixPtr[1][1] - matrixPtr[1][0] * matrixPtr[0][1]; 00520 if ( det2x2 <= 0. ) { return CUBIT_FALSE; } 00521 00522 if ( determinant() <= 0. ) { return CUBIT_FALSE; } 00523 00524 return CUBIT_TRUE; 00525 } 00526 00527 double CubitMatrix::determinant() const 00528 { 00529 double det = 0.0; 00530 00531 if( numRows == 1 ) 00532 det = matrixPtr[0][0]; 00533 else if( numRows == 2 ) 00534 det = matrixPtr[0][0] * matrixPtr[1][1] - matrixPtr[0][1] 00535 * matrixPtr[1][0]; 00536 else if (numRows == 3) 00537 det = matrixPtr[0][0] * matrixPtr[1][1] * matrixPtr[2][2] + 00538 matrixPtr[0][1] * matrixPtr[1][2] * matrixPtr[2][0] + 00539 matrixPtr[0][2] * matrixPtr[1][0] * matrixPtr[2][1] - 00540 matrixPtr[2][0] * matrixPtr[1][1] * matrixPtr[0][2] - 00541 matrixPtr[2][1] * matrixPtr[1][2] * matrixPtr[0][0] - 00542 matrixPtr[2][2] * matrixPtr[1][0] * matrixPtr[0][1]; 00543 else 00544 { 00545 for( int jj = 0; jj < numRows; jj++ ) 00546 { 00547 det += ( matrixPtr[0][jj] * cofactor( 0, jj ) ); 00548 } 00549 } 00550 return det; 00551 } 00552 00553 double CubitMatrix::cofactor( const int row, const int col ) const 00554 { 00555 double c = 0.0; 00556 CubitMatrix matrix_sub( numRows - 1, numCols -1 ); 00557 00558 matrix_sub = sub_matrix( row, col ); 00559 00560 c = matrix_sub.determinant(); 00561 c = (row+col)%2 ? -1*c : c; 00562 00563 return c; 00564 } 00565 00566 CubitMatrix CubitMatrix::adjoint() const 00567 { 00568 CubitMatrix matrix( numRows, numRows ); 00569 00570 for( int ii = 0; ii < numRows; ii++ ) 00571 { 00572 for( int jj = 0; jj < numRows; jj++ ) 00573 { 00574 matrix.set( ii, jj, cofactor( ii, jj ) ); 00575 } 00576 } 00577 return matrix.transpose(); 00578 } 00579 00580 CubitMatrix CubitMatrix::transpose() const 00581 { 00582 CubitMatrix return_matrix( numCols, numRows ); 00583 00584 for( int ii = 0; ii < numRows; ii++ ) 00585 { 00586 for( int jj = 0; jj < numCols; jj++ ) 00587 { 00588 return_matrix.set( jj, ii, matrixPtr[ii][jj] ); 00589 } 00590 } 00591 00592 return return_matrix; 00593 } 00594 00595 // Creates and returns a matrix that is a copy of 'this', 00596 // except that the indicated row and column are left out. 00597 CubitMatrix CubitMatrix::sub_matrix( const int row, const int col ) const 00598 { 00599 CubitMatrix matrix (numRows - 1, numCols - 1); 00600 00601 int copy_row = 0; 00602 for (int source_row = 0; source_row < numRows; source_row++) 00603 { 00604 if (source_row != row) 00605 { 00606 int copy_col = 0; 00607 for (int source_col = 0; source_col < numCols; source_col++) 00608 { 00609 if (source_col != col) 00610 { 00611 matrix.set (copy_row, copy_col, matrixPtr[source_row][source_col]); 00612 copy_col++; 00613 } 00614 } 00615 copy_row++; 00616 } 00617 } 00618 00619 return matrix; 00620 } 00621 00622 // Create a matrix containing the rows and cols of this that are true in 00623 // rows_to_include and cols_to_include. 00624 void CubitMatrix::sub_matrix 00625 ( 00626 const std::vector<bool> &rows_to_include, 00627 const std::vector<bool> &cols_to_include, 00628 CubitMatrix &submatrix 00629 ) 00630 { 00631 if(numRows != (int) rows_to_include.size()) 00632 throw std::invalid_argument ("rows_to_include size must match numRows"); 00633 //assert( numRows == rows_to_include.size() ); 00634 if(numCols != (int) cols_to_include.size()) 00635 throw std::invalid_argument ("cols_to_include size must match numCols"); 00636 //assert( numCols == cols_to_include.size() ); 00637 00638 int i; 00639 int nrow = 0, ncol = 0; 00640 for ( i = 0; i < numRows; i++ ) if ( rows_to_include[i] ) nrow++; 00641 for ( i = 0; i < numCols; i++ ) if ( cols_to_include[i] ) ncol++; 00642 submatrix.reset_size( nrow, ncol, 0.0 ); 00643 00644 for ( int r = 0, new_r = 0; r < numRows; r++ ) 00645 { 00646 if ( !rows_to_include[r] ) continue; 00647 for ( int c = 0, new_c = 0; c < numCols; c++ ) 00648 { 00649 if ( !cols_to_include[c] ) continue; 00650 submatrix.set( new_r, new_c, get(r,c) ); 00651 new_c++; 00652 } 00653 new_r++; 00654 } 00655 } 00656 00657 double CubitMatrix::inf_norm() const 00658 { 00659 // infinity norm = max_i sum_j | A_ij | 00660 double matrix_norm = 0., row_norm, v; 00661 for ( int ii = 0; ii < numRows; ii++ ) { 00662 row_norm = 0.; 00663 for( int jj = 0; jj < numCols; jj++ ) 00664 { 00665 v = fabs( get( ii, jj ) ); 00666 row_norm += v; 00667 } 00668 if ( row_norm > matrix_norm ) 00669 matrix_norm = row_norm; 00670 } 00671 return matrix_norm; 00672 } 00673 00674 double CubitMatrix::frobenius_norm_squared() const 00675 { 00676 // frobenius norm-squared = trace( M^T M ) 00677 00678 double matrix_norm=0; 00679 for ( int ii = 0; ii < numRows; ii++ ) { 00680 00681 for( int jj = 0; jj < numCols; jj++ ) 00682 { 00683 matrix_norm += matrixPtr[ii][jj] * matrixPtr[ii][jj]; 00684 } 00685 00686 } 00687 00688 return matrix_norm; 00689 00690 } 00691 00692 double CubitMatrix::frobenius_norm_squared_symm() const 00693 { 00694 // frobenius norm-squared 2 = trace[( M^T M )( M^T M )] 00695 00696 double matrix_norm=0; 00697 for ( int ii = 0; ii < numRows; ii++ ) 00698 { 00699 for( int jj = 0; jj < numCols; jj++ ) 00700 { 00701 double b=0; 00702 for ( int kk = 0; kk < numRows; kk++ ) 00703 { 00704 b += matrixPtr[kk][ii] * matrixPtr[kk][jj]; 00705 } 00706 matrix_norm += b*b; 00707 } 00708 00709 } 00710 00711 return matrix_norm; 00712 00713 } 00714 00715 double CubitMatrix::frobenius_norm_squared_adj() const 00716 { 00717 // square of frobenius norm of adjoint 00718 00719 double norm=0; 00720 00721 if ( numRows == 1 ) { norm=1; } 00722 00723 if ( numRows == 2 ) { 00724 norm = this->frobenius_norm_squared(); 00725 } 00726 00727 if ( numRows == 3 ) { 00728 norm = 0.5 * ( pow( this->frobenius_norm_squared(), 2 ) - this->frobenius_norm_squared_symm() ); 00729 } 00730 00731 if ( numRows > 3 ) { 00732 CubitMatrix adj = this->adjoint(); 00733 norm = adj.frobenius_norm_squared(); 00734 } 00735 00736 return norm; 00737 00738 } 00739 00740 double CubitMatrix::frobenius_norm_squared_inv() const 00741 { 00742 // square of frobenius norm of A-inverse 00743 00744 double det = this->determinant(); 00745 00746 if(det==0) 00747 throw std::invalid_argument ("Determinant cannot be 0"); 00748 //assert( det != 0 ); 00749 00750 double norm=this->frobenius_norm_squared_adj()/pow(det,2); 00751 00752 return norm; 00753 00754 } 00755 00756 double CubitMatrix::condition() const 00757 { 00758 // condition number of A using frobenius norm 00759 00760 double norm = ( this->frobenius_norm_squared() ) * (this->frobenius_norm_squared_inv() ); 00761 00762 return sqrt( norm ); 00763 00764 } 00765 00766 int CubitMatrix::rank() const 00767 { 00768 const double tol = 1E-12; 00769 int rank = 0; 00770 CubitMatrix tmp = *this; 00771 00772 int irow; 00773 for ( irow = 0; irow < numRows; irow++ ) 00774 { 00775 // make sure tmp[irow][irow] is non-zero. If it isn't, swap a row to 00776 // make it so. 00777 double val = tmp.get(irow,irow); 00778 if ( fabs(val) < tol ) 00779 { 00780 bool found = false; 00781 for ( int i = irow+1; i < numRows; i++ ) 00782 { 00783 if ( fabs(tmp.get(i,irow)) > 1E-4 ) 00784 { 00785 // swap row (irow) with row (irow+i). 00786 for ( int icol = 0; icol < numCols; icol++ ) 00787 { 00788 double tmp1 = tmp.get(irow, icol); 00789 double tmp2 = tmp.get(i, icol); 00790 tmp.set(irow, icol, tmp2 ); 00791 tmp.set(i, icol, tmp1 ); 00792 found = true; 00793 } 00794 } 00795 if ( found ) break; 00796 } 00797 val = tmp.get(irow,irow); 00798 } 00799 if ( fabs(val) < tol ) 00800 continue; 00801 00802 rank++; 00803 00804 for ( int icol = 0; icol < numCols; icol++ ) 00805 { 00806 double col_val = tmp.get(irow, icol); 00807 tmp.set(irow,icol, col_val/val ); 00808 } 00809 00810 for ( int jrow = irow+1; jrow < numRows; jrow++ ) 00811 { 00812 val = tmp.get(jrow,irow); 00813 if ( fabs(val) < tol ) 00814 continue; 00815 00816 for ( int icol = 0; icol < numCols; icol++ ) 00817 { 00818 double tmp1 = tmp.get(jrow,icol) / val; 00819 tmp1 -= tmp.get(irow, icol); 00820 tmp.set(jrow,icol,tmp1 ); 00821 } 00822 } 00823 } 00824 return rank; 00825 } 00826 00827 int CubitMatrix::gauss_elim( CubitVector &b ) 00828 { 00829 CubitVector pivot; 00830 int ierr = factor( pivot ); 00831 if ( ierr == 0 ) { solve( b, pivot ); } 00832 return ierr; 00833 } 00834 00835 int CubitMatrix::factor( CubitVector &pivot ) 00836 { 00837 double pvt[3]; 00838 00839 const int n=3; 00840 double s[3], tmp; 00841 00842 int i,j; 00843 for ( i=0; i<n; i++ ) 00844 { 00845 s[i] = 0.0; 00846 for ( j=0; j<n; j++ ) 00847 { 00848 tmp = fabs( matrixPtr[i][j] ); 00849 if ( tmp > s[i] ) 00850 { 00851 s[i] = tmp; 00852 } 00853 } 00854 00855 if ( s[i] == 0.0 ) 00856 { 00857 return(1); 00858 } 00859 } 00860 00861 for ( int k=0; k<n-1; k++ ) 00862 { 00863 double ck = 0.0; 00864 int i0 = -1; 00865 for ( i=k; i<n; i++ ) 00866 { 00867 tmp = fabs( matrixPtr[i][k] / s[i] ); 00868 if ( tmp > ck ) 00869 { 00870 ck = tmp; 00871 i0 = i; 00872 } 00873 } 00874 00875 pvt[k] = i0; 00876 if ( ck == 0.0 ) { return(1); } 00877 00878 if ( i0 != k ) 00879 { 00880 for ( j=k; j<n; j++ ) 00881 { 00882 double swap = matrixPtr[i0][j]; 00883 matrixPtr[i0][j] = matrixPtr[k][j]; 00884 matrixPtr[k][j] = swap; 00885 } 00886 } 00887 00888 for ( i=k+1; i<n; i++ ) 00889 { 00890 double r = matrixPtr[i][k] / matrixPtr[k][k]; 00891 matrixPtr[i][k] = r; 00892 for ( j=k+1; j<n; j++ ) 00893 { 00894 matrixPtr[i][j] -= r * matrixPtr[k][j]; 00895 } 00896 } 00897 } 00898 00899 pivot.set( pvt[0], pvt[1], pvt[2] ); 00900 return(0); 00901 } 00902 00903 void CubitMatrix::solve( CubitVector &b, const CubitVector& pivot ) 00904 { 00905 double rhs[3]; 00906 rhs[0] = b.x(); 00907 rhs[1] = b.y(); 00908 rhs[2] = b.z(); 00909 00910 double pvt[3]; 00911 pvt[0] = pivot.x(); 00912 pvt[1] = pivot.y(); 00913 pvt[2] = pivot.z(); 00914 00915 int j; 00916 const int n=3; 00917 for ( int k=0; k<n-1; k++ ) 00918 { 00919 j=(int)pvt[k]; 00920 if ( j != k ) 00921 { 00922 double swap = rhs[k]; 00923 rhs[k] = rhs[j]; 00924 rhs[j] = swap; 00925 } 00926 00927 for ( int i=k+1; i<n; i++ ) 00928 { 00929 rhs[i] -= matrixPtr[i][k] * rhs[k]; 00930 } 00931 00932 } 00933 00934 rhs[n-1] /= matrixPtr[n-1][n-1]; 00935 00936 for ( int i=n-2; i>-1; i-- ) 00937 { 00938 double sum=0.; 00939 for ( j=i+1; j<n; j++ ) 00940 { 00941 sum += matrixPtr[i][j] * rhs[j]; 00942 } 00943 rhs[i] = ( rhs[i] - sum ) / matrixPtr[i][i]; 00944 } 00945 00946 b.set( rhs[0], rhs[1], rhs[2] ); 00947 00948 } 00949 00950 00951 // Here is the recipe for inverting a NxM matrice. 00952 // I did not spend the time trying to convert it to Cubit style. 00953 // Matrix is a double** 00954 // Vector is a double* 00955 // Scalar is a double 00956 // int mxiRecipieInverse(Matrix M1, Matrix M2, int N) 00957 // { 00958 // Matrix M1_loc, M2_loc, M3_loc; 00959 // Vector col, copycol; 00960 // Scalar d; 00961 // int i, j, *indx; 00962 00963 // indx = ((int*)malloc((unsigned long)N*sizeof(int)))-1; 00964 00965 // M1_loc = mxInitMatrixR(1, N, 1, N); 00966 // M2_loc = mxInitMatrixR(1, N, 1, N); 00967 // M3_loc = mxInitMatrixR(1, N, 1, N); 00968 // col = mxInitVectorR(1, N); 00969 // copycol = mxInitVectorR(1, N); 00970 // if (M1_loc == NULL || M2_loc == NULL || col == NULL || indx == NULL) 00971 // return 0; 00972 // if (M3_loc == NULL || copycol == NULL) 00973 // printf("\n\nCannot use Improve function\n\n"); 00974 00975 // /* copy the input matrix */ 00976 // for( i = 1; i <= N; i++ ) 00977 // for( j = 1; j <= N; j++ ) { 00978 // M1_loc[i][j] = M1[i-1][j-1]; 00979 // if (M3_loc != NULL) 00980 // M3_loc[i][j] = M1[i-1][j-1]; 00981 // M2_loc[i][j] = 0.0; 00982 // } 00983 00984 // if (!mxiLudcmp(M1_loc, N, indx, &d)) return 0; 00985 // for (j=1; j<=N; j++) { 00986 // for (i=1; i<=N; i++) { 00987 // col[i]=0.0; 00988 // if (copycol != NULL) 00989 // copycol[i] = 0.0; 00990 // } 00991 // col[j] = 1.0; 00992 // if (copycol != NULL) copycol[j] = 1.0; 00993 // mxiLubksb(M1_loc, N, indx, col); 00994 // if (copycol != NULL && M3_loc != NULL) 00995 // if (!mxiImprove(M3_loc, M1_loc, N, indx, copycol, col)) 00996 // return 0; 00997 // for (i=1; i<=N; i++) M2_loc[i][j]=col[i]; 00998 // } 00999 // /* copy the inverted matrix */ 01000 // for( i = 1; i <= N; i++ ) 01001 // for( j = 1; j <= N; j++ ) 01002 // M2[i-1][j-1] = M2_loc[i][j]; 01003 01004 // mxFreeMatrixR(M1_loc, 1, N, 1, N); 01005 // mxFreeMatrixR(M2_loc, 1, N, 1, N); 01006 // mxFreeMatrixR(M3_loc, 1, N, 1, N); 01007 // mxFreeVectorR(col, 1, N); 01008 // mxFreeVectorR(copycol, 1, N); 01009 // free(indx+1); 01010 // return 1; 01011 // } /* mxiRecipieInverse */ 01012 01013 CubitStatus CubitMatrix::solveNxN( CubitMatrix& rhs, CubitMatrix& coef ) 01014 { 01015 if (numRows != rhs.num_rows() || 01016 numRows != numCols) { 01017 return CUBIT_FAILURE; 01018 } 01019 int i,j; 01020 double d; 01021 double *indx = new double [numRows]; 01022 double *b = new double [numRows]; 01023 01024 CubitStatus status = ludcmp(indx, d); 01025 if (status == CUBIT_SUCCESS) 01026 { 01027 coef.reset_size( rhs.num_rows(), rhs.num_cols(), 0.0 ); 01028 for ( j = 0; j < rhs.num_cols(); j++ ) 01029 { 01030 for(i=0; i<numRows; i++) 01031 { 01032 b[i] = rhs.get(i,j); 01033 } 01034 status = lubksb(indx, b); 01035 for (i=0; i<numRows; i++) 01036 { 01037 coef.set(i,j,b[i]); 01038 } 01039 } 01040 } 01041 delete [] indx; 01042 delete [] b; 01043 return status; 01044 } 01045 01046 CubitStatus CubitMatrix::solveNxN( const std::vector<double> &rhs, std::vector<double> &coef ) 01047 { 01048 if (numRows != (int) rhs.size() || 01049 numRows != numCols) { 01050 return CUBIT_FAILURE; 01051 } 01052 int i; 01053 double d; 01054 double *indx = new double [numRows]; 01055 double *b = new double [numRows]; 01056 01057 CubitStatus status = ludcmp(indx, d); 01058 if (status == CUBIT_SUCCESS) 01059 { 01060 coef.clear(); 01061 for(i=0; i<numRows; i++) 01062 { 01063 b[i] = rhs[i]; 01064 } 01065 status = lubksb(indx, b); 01066 for (i=0; i<numRows; i++) 01067 { 01068 coef.push_back( b[i] ); 01069 } 01070 } 01071 delete [] indx; 01072 delete [] b; 01073 return status; 01074 } 01075 01076 // from numerical recipies in C: Decompose a NxN matrix into 01077 // Upper and Lower trianglar (in place) 01078 CubitStatus CubitMatrix::ludcmp( double *indx, double& d ) 01079 { 01080 int i, j, k, imax = -1; 01081 double big, tmp, sum; 01082 double *vv = new double [numRows]; 01083 if (!vv) { 01084 return CUBIT_FAILURE; 01085 } 01086 01087 d = 1.0; // no row interchanges yet 01088 01089 // loop over rows to get implicit scale info 01090 01091 for (i=0; i<numRows; ++i){ 01092 big = 0.0; 01093 for (j=0; j<numRows; ++j) 01094 if ((tmp = fabs(matrixPtr[i][j])) > big) 01095 big = tmp; 01096 if (big == 0.0) { 01097 // note (vvyas, 3/2006): corrected array deletion 01098 // delete vv; 01099 delete [] vv; 01100 return CUBIT_FAILURE; 01101 } 01102 vv[i] = 1.0/big; 01103 } 01104 01105 // loop over columns-Crout's method 01106 01107 for (j=0; j<numRows; ++j){ 01108 for (i=0; i<j; ++i){ 01109 sum = matrixPtr[i][j]; 01110 for (k=0; k<i; ++k) 01111 sum -= matrixPtr[i][k]*matrixPtr[k][j]; 01112 matrixPtr[i][j] = sum; 01113 } 01114 big = 0.0; // initialize pivot search 01115 for (i=j; i<numRows; ++i){ 01116 sum = matrixPtr[i][j]; 01117 for (k=0; k<j; ++k) 01118 sum -= matrixPtr[i][k]*matrixPtr[k][j]; 01119 matrixPtr[i][j] = sum; 01120 if ((tmp = vv[i]*fabs(sum)) > big) { 01121 big = tmp; 01122 imax = i; 01123 } 01124 } 01125 if (j != imax) { // do we need to change rows 01126 for (k=0; k<numRows; ++k) { 01127 tmp = matrixPtr[imax][k]; 01128 matrixPtr[imax][k] = matrixPtr[j][k]; 01129 matrixPtr[j][k] = tmp; 01130 } 01131 d = -d; 01132 vv[imax] = vv[j]; 01133 } 01134 indx[j] = imax; 01135 if (matrixPtr[j][j] == 0.0) matrixPtr[0][0] = 1.0e-20; 01136 if (j != numRows-1) { // divide by the pivot element 01137 tmp = 1.0/matrixPtr[j][j]; 01138 for (i=j+1; i<numRows; ++i) 01139 matrixPtr[i][j] *= tmp; 01140 } 01141 } // go back for next column 01142 01143 // note (vvyas 3/2006): corrected array deletion 01144 // delete vv; 01145 delete [] vv; 01146 01147 return CUBIT_SUCCESS; 01148 } 01149 01150 // from numerical recipies in C: solve [mat]{x} = {b} by back 01151 // substitution (mat = LU of mat) 01152 CubitStatus CubitMatrix::lubksb( double *indx, double *b ) 01153 { 01154 int i, j, ii, ip; 01155 double sum; 01156 01157 // do the forward substitution 01158 01159 ii = -1; 01160 for (i=0; i<numRows; ++i){ 01161 ip = (int)indx[i]; 01162 sum = b[ip]; 01163 b[ip] = b[i]; 01164 if (ii >= 0) 01165 for (j=ii; j<=i-1; ++j) 01166 sum -= matrixPtr[i][j]*b[j]; 01167 else if (sum) 01168 ii = i; 01169 b[i] = sum; 01170 } 01171 01172 // do the back substitution 01173 01174 for (i=numRows-1; i>=0; --i){ 01175 sum = b[i]; 01176 for (j=i+1; j<numRows; ++j) 01177 sum -= matrixPtr[i][j]*b[j]; 01178 b[i] = sum/matrixPtr[i][i]; // store a component of solution 01179 } 01180 return CUBIT_SUCCESS; 01181 } 01182 01183 bool CubitMatrix::is_identity( double tol ) const 01184 { 01185 bool ident = true; 01186 01187 for (int i=0; i<numRows && ident; i++) 01188 { 01189 for (int j=0; j<numCols && ident; j++) 01190 { 01191 if (i == j) 01192 { 01193 if( fabs(matrixPtr[i][j] - 1.0) > tol) 01194 ident = false; 01195 } 01196 else 01197 { 01198 if(matrixPtr[i][j] > tol) 01199 ident = false; 01200 } 01201 } 01202 } 01203 01204 return ident; 01205 } 01206 01207 bool CubitMatrix::is_equal( const CubitMatrix &other, double tol ) const 01208 { 01209 if ( numRows != other.numRows ) return false; 01210 if ( numCols != other.numCols ) return false; 01211 01212 for (int i=0; i<numRows; i++) 01213 { 01214 for (int j=0; j<numCols; j++) 01215 { 01216 double diff = fabs(matrixPtr[i][j] - other.matrixPtr[i][j]); 01217 if(diff > tol) 01218 return false; 01219 } 01220 } 01221 return true; 01222 } 01223 01224 void CubitMatrix::plus_identity() 01225 { 01226 for (int i=0; i<numRows; i++) 01227 { 01228 if ( i == numCols ) break; 01229 matrixPtr[i][i] += 1.0; 01230 } 01231 } 01232 01233 bool CubitMatrix::vector_outer_product(const CubitVector& vec1, 01234 const CubitVector& vec2 ) 01235 { 01236 if ( numRows != 3 || numCols != 3 ) 01237 return false; 01238 01239 // Initialize the matrix elements using otimes (outer product) 01240 matrixPtr[0][0] = vec1.x() * vec2.x(); 01241 matrixPtr[1][0] = vec1.y() * vec2.x(); 01242 matrixPtr[2][0] = vec1.z() * vec2.x(); 01243 matrixPtr[0][1] = vec1.x() * vec2.y(); 01244 matrixPtr[1][1] = vec1.y() * vec2.y(); 01245 matrixPtr[2][1] = vec1.z() * vec2.y(); 01246 matrixPtr[0][2] = vec1.x() * vec2.z(); 01247 matrixPtr[1][2] = vec1.y() * vec2.z(); 01248 matrixPtr[2][2] = vec1.z() * vec2.z(); 01249 return true; 01250 }