cgma
CubitMatrix.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines