source/numeric/matrix.cxx

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  The Contents of this file are made available subject to
00004  *  the terms of GNU Lesser General Public License Version 2.1.
00005  *
00006  *
00007  *    GNU Lesser General Public License Version 2.1
00008  *    =============================================
00009  *    Copyright 2005 by Kohei Yoshida.
00010  *    1039 Kingsway Dr., Apex, NC 27502, USA
00011  *
00012  *    This library is free software; you can redistribute it and/or
00013  *    modify it under the terms of the GNU Lesser General Public
00014  *    License version 2.1, as published by the Free Software Foundation.
00015  *
00016  *    This library is distributed in the hope that it will be useful,
00017  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *    Lesser General Public License for more details.
00020  *
00021  *    You should have received a copy of the GNU Lesser General Public
00022  *    License along with this library; if not, write to the Free Software
00023  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00024  *    MA  02111-1307  USA
00025  *
00026  ************************************************************************/
00027 
00028 
00029 #include "numeric/matrix.hxx"
00030 #include "tool/global.hxx"
00031 #include <iostream>
00032 #include <iomanip>
00033 #include <string>
00034 #include <set>
00035 #include <exception>
00036 #include <iterator>
00037 #include <sstream>
00038 
00039 namespace bnu = ::boost::numeric::ublas;
00040 
00041 using ::std::cout;
00042 using ::std::endl;
00043 using ::boost::numeric::ublas::prod;
00044 using ::std::vector;
00045 
00046 namespace scsolver { namespace numeric {
00047 
00048 const char* BadIndex::what() const throw()
00049 {
00050     return "Bad index";
00051 }
00052 
00053 const char* MatrixSizeMismatch::what() const throw()
00054 {
00055     return "Matrix size mismatch";
00056 }
00057 
00058 const char* MatrixNotDiagonal::what() const throw()
00059 {
00060     return "Matrix not diagonal";
00061 }
00062 
00063 const char* OperationOnEmptyMatrix::what() const throw()
00064 {
00065     return "Operation on empty matrix";
00066 }
00067 
00068 const char* SingularMatrix::what() const throw()
00069 {
00070     return "Singular matrix encountered";
00071 }
00072 
00073 const char* NonSquareMatrix::what() const throw()
00074 {
00075     return "Matrix not square where a square matrix is required";
00076 }
00077 
00078 //---------------------------------------------------------------------------
00079 // Local helper functions
00080 
00081 namespace mxhelper {
00082 
00083 void print( const bnu::matrix<double>& mx )
00084 {
00085 #ifdef DEBUG
00086     for ( size_t i = 0; i < mx.size1(); ++i )
00087     {
00088         printf( "|" );
00089         for ( size_t j = 0; j < mx.size2(); ++j )
00090             printf( " %f", mx( i, j ) );
00091         printf( " |\n" );
00092     }
00093 #endif
00094 }
00095 
00096 typedef bnu::matrix_range< bnu::matrix<double> >  MxRange;
00097 typedef bnu::matrix_row< bnu::matrix<double> >    MxRow;
00098 typedef bnu::matrix_column< bnu::matrix<double> > MxColumn;
00099 
00100 bool isRowEmpty( const bnu::matrix<double>& A, size_t nRowId )
00101 {
00102     if ( nRowId >= A.size1() )
00103         throw MatrixSizeMismatch();
00104 
00105     size_t nColSize = A.size2();
00106     for ( size_t i = 0; i < nColSize; ++i )
00107         if ( A( nRowId, i ) )
00108             return false;
00109 
00110     return true;
00111 }
00112 
00113 bool isColumnEmpty( const bnu::matrix<double>& A, size_t nColId )
00114 {
00115     if ( nColId >= A.size2() )
00116         throw MatrixSizeMismatch();
00117 
00118     size_t nRowSize = A.size1();
00119     for ( size_t i = 0; i < nRowSize; ++i )
00120         if ( A( i, nColId ) )
00121             return false;
00122 
00123     return true;
00124 }
00125 
00126 void swapRows( bnu::matrix<double>& A, size_t nRow1, size_t nRow2 )
00127 {
00128     MxRow row1( A, nRow1 );
00129     MxRow row2( A, nRow2 );
00130     row1.swap( row2 );
00131 }
00132 
00133 void factorize( const bnu::matrix<double>& mxA, bnu::matrix<double>& mxL, 
00134         bnu::matrix<double>& mxU, bnu::matrix<double>& mxP )
00135 {
00136     if ( mxA.size1() != mxA.size2() )
00137         throw NonSquareMatrix();
00138 
00139 #if 0
00140     size_t n = mxA.size1();
00141     bnu::matrix<double> A( mxA );
00142     bnu::identity_matrix<double> I( A.size1(), A.size2() );
00143     bnu::matrix<double> P( I );
00144 
00145     for ( unsigned int k = 0; k < n; ++k )
00146     {
00147         // Partial pivoting ( get column k and scan row(s) k:n )
00148         if ( n - k > 1 )
00149         {
00150             MxColumn cl( A, k );
00151             for ( unsigned int i = k + 1; i < n; ++i )
00152             {
00153                 size_t nSwapRowId = k;
00154                 double fVal = cl( k );
00155                 for ( size_t nRowId = k; nRowId < n; ++nRowId )
00156                 {
00157                     double fTemp = cl( nRowId );
00158                     if ( fTemp > fVal )
00159                     {
00160                         nSwapRowId = nRowId;
00161                         fVal = fTemp;
00162                     }
00163                 }
00164 
00165                 if ( nSwapRowId != k )
00166                 {
00167                     swapRows( A, k, nSwapRowId );
00168                     swapRows( P, k, nSwapRowId );
00169                 }   
00170             }
00171         }
00172 
00173         double fPivot = A( k, k );
00174         if ( fPivot == 0.0 )
00175             throw SingularMatrix();
00176 
00177         MxRange mr1( A, bnu::range( k + 1, n ), bnu::range( k, k + 1 ) );
00178         mr1 /= fPivot;
00179         MxRange mr2( A, bnu::range( k + 1, n ), bnu::range( k, k + 1 ) );
00180         MxRange mr3( A, bnu::range( k, k + 1 ), bnu::range( k + 1, n ) );
00181         MxRange mr4( A, bnu::range( k + 1, n ), bnu::range( k + 1, n ) );
00182         mr4 -= prod( mr2, mr3 );
00183     }
00184     
00185     // Transfer elements from A into L and U
00186     bnu::matrix<double> L( I ), U( n, n );
00187     for ( unsigned int i = 0; i < n; ++i )
00188         for ( unsigned int j = 0; j < n; ++j )
00189         {
00190             if ( i > j )
00191                 L( i, j ) = A( i, j );
00192             else
00193                 U( i, j ) = A( i, j );
00194         }
00195 #endif
00196 
00197     size_t n = mxA.size1();
00198     bnu::matrix<double> A( mxA );
00199 
00200     ::std::vector<size_t> cnP;
00201     cnP.reserve( n );
00202     for ( size_t i = 0; i < n; ++i )
00203         cnP.push_back( i );
00204 
00205     // for each column k...
00206     for ( size_t k = 0; k < n - 1; ++k )
00207     {
00208         double fMax = 0.0;
00209         size_t nSwapRowId = k;
00210         for ( size_t nRowId = k; nRowId < n; ++nRowId )
00211         {
00212             double fVal = fabs( A( nRowId, k ) );
00213             if ( fVal > fMax )
00214             {
00215                 fMax = fVal;
00216                 nSwapRowId = nRowId;
00217             }
00218         }
00219 
00220         if ( fMax == 0.0 )
00221             throw SingularMatrix();
00222             
00223         ::std::swap( cnP.at( k ), cnP.at( nSwapRowId ) );
00224         swapRows( A, k, nSwapRowId );
00225         
00226         for ( size_t i = k + 1; i < n; ++i )
00227         {
00228             A( i, k ) /= A( k, k );
00229             for ( size_t j = k + 1; j < n; ++j )
00230                 A( i, j ) -= A( i, k )*A( k, j );
00231         }
00232     }
00233 
00234     // Transfer elements from A into L and U
00235     bnu::identity_matrix<double> I( n, n );
00236     bnu::zero_matrix<double> N( n, n );
00237     bnu::matrix<double> L( I ), U( N ), P( N );
00238 
00239     for ( unsigned int i = 0; i < n; ++i )
00240         for ( unsigned int j = 0; j < n; ++j )
00241         {
00242             if ( i > j )
00243                 L( i, j ) = A( i, j );
00244             else
00245                 U( i, j ) = A( i, j );
00246         }
00247 
00248 #if REWRITE_FOR_SUN_STUDIO_COMPILER
00249     n = cnP.size();
00250     for (size_t i = 0; i < n; ++i)
00251         P(i, cnP[i]) = 1.0;
00252 #else
00253     ::std::vector<size_t>::const_iterator it, itBeg = cnP.begin(), itEnd = cnP.end();
00254     for ( it = itBeg; it != itEnd; ++it )
00255         P( ::std::distance( itBeg, it ), *it ) = 1.0;
00256 #endif
00257 
00258     noalias( mxU ) = U;
00259     noalias( mxL ) = L;
00260     noalias( mxP ) = P;
00261 }
00262 
00263 void inverseU( const bnu::matrix<double>& mxU, bnu::matrix<double>& mxUInv )
00264 {
00265     size_t nSize = mxU.size1();
00266     if ( nSize != mxU.size2() )
00267         throw NonSquareMatrix();
00268 
00269     bnu::matrix<double> Combo( nSize, nSize*2 );
00270     MxRange U( Combo, bnu::range( 0, nSize ), bnu::range( 0, nSize ) );
00271     MxRange UInv( Combo, bnu::range( 0, nSize ), bnu::range( nSize, nSize*2 ) );
00272     bnu::identity_matrix<double> I( nSize );
00273     U = mxU;
00274     UInv = I;
00275     
00276     // back substitution
00277     size_t nRow = nSize;
00278     do
00279     {
00280         // normalize the current row first
00281         --nRow;
00282         double fPivot = U( nRow, nRow );
00283         MxRow mrCur( Combo, nRow );
00284         mrCur /= fPivot;
00285         U( nRow, nRow ) = 1.0; // maybe redundant because it should already be 1.0
00286         
00287         // substitute upward
00288         if ( nRow > 0 )
00289         {
00290             size_t nSubRow = nRow;
00291             do
00292             {
00293                 MxRow mrSub( Combo, --nSubRow );
00294                 mrSub -= mrCur*U( nSubRow, nRow );
00295             }
00296             while ( nSubRow != 0 );
00297         }   
00298     }
00299     while ( nRow != 0 );
00300     
00301     noalias( mxUInv ) = UInv;
00302 }
00303 
00304 void inverseL( const bnu::matrix<double>& mxL, bnu::matrix<double>& mxLInv )
00305 {
00306     size_t nSize = mxL.size1();
00307     if ( nSize != mxL.size2() )
00308         throw NonSquareMatrix();
00309 
00310     bnu::matrix<double> Combo( nSize, nSize*2 );
00311     MxRange L( Combo, bnu::range( 0, nSize ), bnu::range( 0, nSize ) );
00312     MxRange LInv( Combo, bnu::range( 0, nSize ), bnu::range( nSize, nSize*2 ) );
00313     bnu::identity_matrix<double> I( nSize );
00314     L = mxL;
00315     LInv = I;
00316 
00317     // forward substitution
00318     size_t nRow = 0;
00319     do
00320     {
00321         MxRow mrCur( Combo, nRow );
00322         
00323         // substitute downward
00324         if ( nRow < nSize - 1 )
00325         {
00326             size_t nSubRow = nRow + 1;
00327             do
00328             {
00329                 MxRow mrSub( Combo, nSubRow );
00330                 mrSub -= mrCur*L( nSubRow, nRow );
00331             }
00332             while ( ++nSubRow < nSize );
00333         }
00334     }
00335     while ( ++nRow < nSize );
00336     
00337     noalias( mxLInv ) = LInv;
00338 }
00339 
00345 void inverse( const bnu::matrix<double>& mxA, bnu::matrix<double>& mxInv )
00346 {
00347     size_t nRow = mxA.size1(), nCol = mxA.size2();
00348     if ( nRow != nCol )
00349         throw NonSquareMatrix();
00350         
00351     size_t nSize = nRow;
00352         
00353     bnu::matrix<double> mxL( nSize, nSize );
00354     bnu::matrix<double> mxU( nSize, nSize );
00355     bnu::matrix<double> mxP( nSize, nSize );
00356     factorize( mxA, mxL, mxU, mxP );
00357     
00358     bnu::matrix<double> mxUInv( nSize, nSize );
00359     inverseU( mxU, mxUInv );
00360     
00361     bnu::matrix<double> mxLInv( nSize, nSize );
00362     inverseL( mxL, mxLInv );
00363     
00364     bnu::matrix<double> mxTemp = prod( mxUInv, mxLInv );
00365     mxTemp = prod( mxTemp, mxP );
00366     noalias( mxInv ) = mxTemp;
00367 }
00368 
00369 } // end of namespace mxhelper
00370 
00371 //---------------------------------------------------------------------------
00372 
00373 Matrix::Matrix() : 
00374     m_bResizable(true)
00375 {
00376     bnu::matrix<double> m( 0, 0 );
00377     m_aArray = m;
00378 }
00379 
00380 Matrix::Matrix(size_t row, size_t col, bool identity_matrix) :
00381     m_bResizable(true)
00382 {   
00383     bnu::matrix<double> m(row, col);
00384     for ( unsigned int i = 0; i < m.size1(); ++i )
00385     {
00386         for ( unsigned int j = 0; j < m.size2(); ++j )
00387         {
00388             if (identity_matrix && i == j)
00389                 m( i, j ) = 1.0;
00390             else
00391                 m( i, j ) = 0.0;
00392         }
00393     }
00394     m_aArray = m;
00395 }
00396 
00397 Matrix::Matrix( const Matrix& other ) :
00398     m_bResizable( other.m_bResizable ),
00399     m_aArray( other.m_aArray )
00400 {
00401 }
00402 
00403 Matrix::Matrix( const Matrix* p ) :
00404     m_bResizable( p->m_bResizable ),
00405     m_aArray( p->m_aArray )
00406 {
00407 }
00408 
00409 Matrix::Matrix( bnu::matrix<double> m ) : m_bResizable( true )
00410 {
00411     m_aArray = m;
00412 }
00413 
00414 Matrix::~Matrix() throw()
00415 {
00416 }
00417 
00418 void Matrix::setResizable(bool resizable)
00419 { 
00420     m_bResizable = resizable; 
00421 }
00422 
00423 void Matrix::swap( Matrix& other ) throw()
00424 {
00425     m_aArray.swap( other.m_aArray );
00426     std::swap( m_bResizable, other.m_bResizable );
00427 }
00428 
00429 void Matrix::clear()
00430 {
00431     m_aArray.resize( 0, 0 );
00432 }
00433 
00434 void Matrix::copy( const Matrix& other )
00435 {
00436     Matrix tmp( other );
00437     swap( tmp );
00438 }
00439 
00440 Matrix Matrix::clone() const
00441 {
00442     Matrix mxCloned( this );
00443     return mxCloned;
00444 }
00445 
00446 const double Matrix::getValue(size_t row, size_t col) const
00447 {
00448     try
00449     {
00450         return m_aArray(row, col);
00451     }
00452     catch (const ::boost::numeric::ublas::bad_index&)
00453     {
00454         throw BadIndex();
00455     }
00456 }
00457 
00458 double& Matrix::getValue(size_t row, size_t col)
00459 {
00460     try
00461     {
00462         return m_aArray(row, col);
00463     }
00464     catch (const ::boost::numeric::ublas::bad_index&)
00465     {
00466         throw BadIndex();
00467     }
00468 }
00469 
00470 void Matrix::setValue(size_t row, size_t col, double val)
00471 {
00472     maybeExpand(row, col);
00473     m_aArray(row, col) = val;
00474 }
00475 
00476 Matrix Matrix::getColumn(size_t col)
00477 {
00478     size_t nRows = rows();
00479     Matrix m( nRows, 1 );
00480     m.setResizable( false );
00481     for ( size_t i = 0; i < nRows; ++i )
00482         m( i, 0 ) = getValue( i, col );
00483     return m;
00484 }
00485 
00486 Matrix Matrix::getRow(size_t row)
00487 {
00488     size_t nCols = cols();
00489     Matrix mx( 1, nCols );
00490     mx.setResizable( false );
00491     for ( size_t i = 0; i < nCols; ++i )
00492         mx( 0, i ) = getValue( row, i );
00493     return mx;
00494 }
00495 
00496 void Matrix::deleteColumn( size_t nColId )
00497 {
00498     if ( nColId >= m_aArray.size2() )
00499     {
00500         Debug( "deleteColumn" );
00501         throw MatrixSizeMismatch();
00502     }
00503 
00504     bnu::matrix<double> m( m_aArray.size1(), m_aArray.size2()-1 );
00505     for ( size_t i = 0; i < m_aArray.size1(); ++i )
00506         for ( size_t j = 0; j < m_aArray.size2(); ++j )
00507         {
00508             if ( j == nColId )
00509                 continue;
00510             size_t j2 = j > nColId ? j - 1 : j;
00511             m( i, j2 ) = m_aArray( i, j );
00512         }
00513     m_aArray = m;
00514 }
00515 
00516 void Matrix::deleteColumns( const std::vector<size_t>& cnColIds )
00517 {
00518     // reverse sorted set
00519     typedef std::set<size_t,std::greater<size_t> > uIntSet;
00520     
00521     uIntSet aSortedIds;
00522     std::vector<size_t>::const_iterator pos;
00523     for ( pos = cnColIds.begin(); pos != cnColIds.end(); ++pos )
00524         aSortedIds.insert( *pos );
00525 
00526     uIntSet::iterator pos2;
00527     for ( pos2 = aSortedIds.begin(); pos2 != aSortedIds.end(); ++pos2 )
00528         deleteColumn( *pos2 );
00529 }
00530 
00531 void Matrix::deleteRow( size_t nRowId )
00532 {
00533     if ( nRowId >= m_aArray.size1() )
00534     {
00535         Debug( "deleteRow" );
00536         throw MatrixSizeMismatch();
00537     }
00538 
00539     bnu::matrix<double> m( m_aArray.size1()-1, m_aArray.size2() );
00540     for ( size_t i = 0; i < m_aArray.size1(); ++i )
00541         if ( i != nRowId )
00542         {
00543             size_t i2 = i > nRowId ? i - 1 : i;
00544             for ( size_t j = 0; j < m_aArray.size2(); ++j )
00545                 m( i2, j ) = m_aArray( i, j );
00546         }
00547     m_aArray = m;
00548 }
00549 
00550 void Matrix::deleteRows( const std::vector<size_t>& cnRowIds )
00551 {
00552     std::vector<size_t> cnRowIds2( cnRowIds.begin(), cnRowIds.end() );
00553     std::sort( cnRowIds2.begin(), cnRowIds2.end() );
00554 
00555     std::vector<size_t>::reverse_iterator it,
00556         itBeg = cnRowIds2.rbegin(), itEnd = cnRowIds2.rend();
00557     for ( it = itBeg; it != itEnd; ++it )
00558         deleteRow( *it );
00559 }
00560 
00561 const Matrix Matrix::adj() const
00562 {
00563     throwIfEmpty();
00564 
00565     Matrix adj( cols(), rows() ); // transposed
00566 
00567     for ( size_t i = 0; i < adj.rows(); ++i )
00568         for ( size_t j = 0; j < adj.cols(); ++j )
00569             adj.setValue( i, j, cofactor( j, i ) );
00570 
00571     return adj;
00572 }
00573 
00574 double Matrix::cofactor( size_t i, size_t j ) const
00575 {
00576     throwIfEmpty();
00577 
00578     double fVal = minors( i, j );
00579     if ( (i+j)%2 )
00580         fVal *= -1;
00581 
00582     return fVal;
00583 }
00584 
00585 double Matrix::det() const
00586 {
00587     throwIfEmpty();
00588     
00589     if ( !isSquare() )
00590     {
00591         Debug( "is not square" );
00592         throw NonSquareMatrix();
00593     }
00594 
00595     if ( cols() == 1 )
00596         return getValue( 0, 0 );
00597     else if ( cols() == 2 )
00598         return getValue( 0, 0 )*getValue( 1, 1 ) - getValue( 0, 1 )*getValue( 1, 0 );
00599     else if ( cols() == 3 )
00600         return getValue( 0, 0 )*getValue( 1, 1 )*getValue( 2, 2 ) - 
00601             getValue( 0, 0 )*getValue( 1, 2 )*getValue( 2, 1 ) - 
00602             getValue( 1, 0 )*getValue( 0, 1 )*getValue( 2, 2 ) +
00603             getValue( 1, 0 )*getValue( 0, 2 )*getValue( 2, 1 ) +
00604             getValue( 2, 0 )*getValue( 0, 1 )*getValue( 1, 2 ) -
00605             getValue( 2, 0 )*getValue( 0, 2 )*getValue( 1, 1 );
00606 
00607     double fSum = 0.0;
00608     
00609     for ( size_t j = 0; j < cols(); ++j )
00610     {
00611         double fHead = getValue( 0, j );
00612         if ( fHead )
00613         {
00614             if ( j%2 )
00615                 fHead *= -1.0;
00616             fHead *= minors( 0, j );
00617             fSum += fHead;
00618         }
00619     }
00620     return fSum;
00621 }
00622 
00623 const Matrix Matrix::inverse() const
00624 {
00625     throwIfEmpty();
00626     if ( !isSquare() )
00627     {
00628         cout << "matrix size = ( " << rows() << ", " << cols() << " )" << endl;
00629         Debug( "inversion requires a square matrix" );
00630         throw MatrixSizeMismatch();
00631     }
00632 
00633     bnu::matrix<double> mxAInv( m_aArray.size1(), m_aArray.size2() );
00634     mxhelper::inverse( m_aArray, mxAInv );
00635     Matrix mxInv( mxAInv );
00636     mxInv.setResizable( m_bResizable );
00637 
00638     return mxInv;
00639 }
00640 
00641 const Matrix Matrix::trans() const
00642 {
00643     throwIfEmpty();
00644     Matrix m( ::boost::numeric::ublas::trans( m_aArray ) );
00645     m.m_bResizable = m_bResizable;
00646     return m;
00647 }
00648 
00649 double Matrix::minors( size_t iSkip, size_t jSkip ) const
00650 {
00651     throwIfEmpty();
00652     Matrix m( rows() - 1, cols() - 1 );
00653     m.setResizable( false );
00654     for ( size_t i = 0; i < m.cols(); ++i )
00655     {
00656         size_t iOffset = i >= iSkip ? 1 : 0;
00657         for ( size_t j = 0; j < m.rows(); ++j )
00658         {
00659             size_t jOffset = j >= jSkip ? 1 : 0;
00660             double fVal = getValue( i + iOffset, j + jOffset );
00661             m.setValue( i, j, fVal );
00662         }
00663     }
00664     m.setResizable( true );
00665     return m.det();
00666 }
00667 
00668 void Matrix::resize(size_t row, size_t col)
00669 {
00670     
00671 #if 0
00672     // boost 1.30.2 has a bug in resize().  Works in 1.32.0.
00673     m_aArray.resize( row, col, true );
00674 #else
00675     bnu::matrix<double, bnu::row_major, std::vector<double> > aArray(row, col);
00676 
00677     size_t nRowSize = m_aArray.size1() < row ? m_aArray.size1() : row;
00678     size_t nColSize = m_aArray.size2() < col ? m_aArray.size2() : col;
00679     for ( size_t nRowId = 0; nRowId < nRowSize; ++nRowId )
00680         for ( size_t nColId = 0; nColId < nColSize; ++nColId )
00681             aArray( nRowId, nColId ) = m_aArray( nRowId, nColId );
00682     
00683     m_aArray.swap( aArray );
00684 #endif
00685 }
00686 
00687 size_t Matrix::rows() const 
00688 { 
00689     return m_aArray.size1(); 
00690 }
00691 
00692 size_t Matrix::cols() const
00693 {
00694     return m_aArray.size2();
00695 }
00696 
00697 bool Matrix::empty() const
00698 {
00699     return ( rows() == 0 && cols() == 0 );
00700 }
00701 
00702 bool Matrix::isRowEmpty( size_t nRow ) const
00703 {
00704     return mxhelper::isRowEmpty( m_aArray, nRow );
00705 }
00706 
00707 bool Matrix::isColumnEmpty( size_t nCol ) const
00708 {
00709     return mxhelper::isColumnEmpty( m_aArray, nCol );
00710 }
00711 
00712 bool Matrix::isSameSize( const Matrix& r ) const
00713 {
00714     return !( rows() != r.rows() || cols() != r.cols() );
00715 }
00716 
00717 bool Matrix::isSquare() const
00718 {
00719     return rows() == cols();
00720 }
00721 
00722 //----------------------------------------------------------------------------
00723 // Overloaded Operators
00724 
00725 Matrix& Matrix::operator=( const Matrix& r )
00726 {
00727     // check for assignment to self
00728     if ( this == &r )
00729         return *this;
00730 
00731     Matrix temp( r );
00732     swap( temp );
00733     return *this;
00734 }
00735 
00736 const Matrix Matrix::operator+( const Matrix& r ) const
00737 {
00738     Matrix m( this );
00739     if ( !m.isSameSize( r ) )
00740     {
00741         Debug( "addition of mis-matched matrices" );
00742         throw MatrixSizeMismatch();
00743     }
00744     
00745     for ( size_t i = 0; i < m.rows(); ++i )
00746         for ( size_t j = 0; j < m.cols(); ++j )
00747             m.setValue( i, j, m.getValue( i, j ) + r.getValue( i, j ) );
00748     return m;
00749 }
00750 
00751 const Matrix Matrix::operator-( const Matrix& r ) const
00752 {
00753     Matrix m( this );
00754     if ( !m.isSameSize( r ) )
00755     {
00756         Debug( "subtraction of mis-matched matrices" );
00757         throw MatrixSizeMismatch();
00758     }
00759     
00760     for ( size_t i = 0; i < m.rows(); ++i )
00761         for ( size_t j = 0; j < m.cols(); ++j )
00762             m.setValue( i, j, m.getValue( i, j ) - r.getValue( i, j ) );
00763     return m;
00764 }
00765 
00766 const Matrix Matrix::operator*( double fMul ) const
00767 {
00768     Matrix m( this );
00769     for ( size_t i = 0; i < m.rows(); ++i )
00770         for ( size_t j = 0; j < m.cols(); ++j )
00771             m.setValue( i, j, m.getValue( i, j )*fMul );
00772     return m;
00773 }
00774 
00775 const Matrix Matrix::operator*( const Matrix& r ) const
00776 {
00777     if ( cols() != r.rows() )
00778     {
00779         Debug( "illegal multiplication" );
00780         throw MatrixSizeMismatch();
00781     }
00782     
00783     Matrix m( prod( m_aArray, r.m_aArray ) );
00784     return m;
00785 }
00786 
00787 const Matrix Matrix::operator/( double fDiv ) const
00788 {
00789     Matrix m( this );
00790     for ( size_t i = 0; i < m.rows(); ++i )
00791         for ( size_t j = 0; j < m.cols(); ++j )
00792             m.setValue( i, j, m.getValue( i, j )/fDiv );
00793     return m;
00794 }
00795 
00796 Matrix& Matrix::operator+=( const Matrix& r )
00797 {
00798     *this = *this + r;
00799     return *this;
00800 }
00801 
00802 Matrix& Matrix::operator+=( double f )
00803 {
00804     Matrix mx( this );
00805     for ( size_t i = 0; i < mx.rows(); ++i )
00806         for ( size_t j = 0; j < mx.cols(); ++j )
00807             mx.setValue( i, j, mx.getValue( i, j ) + f );
00808     swap( mx );
00809     return *this;
00810 }
00811 
00812 Matrix& Matrix::operator-=( const Matrix& r )
00813 {
00814     *this = *this - r;
00815     return *this;
00816 }
00817 
00818 Matrix& Matrix::operator*=( double f )
00819 {
00820     *this = *this * f;
00821     return *this;
00822 }
00823 
00824 Matrix& Matrix::operator/=( double f )
00825 {
00826     *this = *this / f;
00827     return *this;
00828 }
00829 
00830 const double Matrix::operator()(size_t row, size_t col) const
00831 {
00832     return getValue(row, col);
00833 }
00834 
00835 double& Matrix::operator()(size_t row, size_t col)
00836 {
00837     maybeExpand(row, col);
00838     return getValue(row, col);
00839 }
00840 
00841 bool Matrix::operator==( const Matrix& other ) const
00842 {
00843     return !operator!=( other );
00844 }
00845 
00846 bool Matrix::operator!=( const Matrix& other ) const
00847 {
00848     if ( cols() != other.cols() || rows() != other.rows() )
00849         return true;
00850 
00851     for ( size_t i = 0; i < rows(); ++i )
00852         for ( size_t j = 0; j < cols(); ++j )
00853             if ( getValue( i, j ) != other( i, j ) )
00854                 return true;
00855     return false;
00856 }
00857 
00858 void Matrix::maybeExpand(size_t row, size_t col)
00859 {
00860     if ( m_bResizable )
00861     {
00862         size_t nRowSize = m_aArray.size1();
00863         size_t nColSize = m_aArray.size2();
00864         if ( row >= nRowSize || col >= nColSize )
00865         {
00866             size_t nNewRowSize = row + 1 > nRowSize ? row + 1 : nRowSize;
00867             size_t nNewColSize = col + 1 > nColSize ? col + 1 : nColSize;
00868             resize( nNewRowSize, nNewColSize );
00869         }
00870     }
00871 }
00872 
00873 void Matrix::throwIfEmpty() const
00874 {
00875     if ( empty() )
00876         throw OperationOnEmptyMatrix();
00877 }
00878 
00879 Matrix::StringMatrixType Matrix::getDisplayElements( 
00880         int prec, size_t nColSpace, bool bFormula) const
00881 {
00882     using std::string;
00883     using std::ostringstream;
00884 
00885     // Set all column widths to 0.
00886     std::vector<unsigned int> aColLen;
00887     for ( unsigned int j = 0; j < m_aArray.size2(); ++j )
00888         aColLen.push_back( 0 );
00889     
00890     // Get string matrix.
00891     StringMatrixType mxElements( m_aArray.size1(), m_aArray.size2() );
00892     for ( unsigned int i = 0; i < m_aArray.size1(); ++i )
00893         for ( unsigned int j = 0; j < m_aArray.size2(); ++j )
00894         {
00895             ::std::ostringstream osElem;
00896             double fVal = m_aArray( i, j );
00897             for ( unsigned int k = 0; k < nColSpace; ++k )
00898                 osElem << " ";
00899             if ( prec > 0 )
00900                 osElem << std::showpoint;
00901             osElem << std::fixed << std::setprecision( prec ) << fVal;
00902             mxElements( i, j ) = osElem.str();
00903             if ( aColLen.at( j ) < osElem.str().size() )
00904                 aColLen[j] = osElem.str().size();
00905         }
00906 
00907     // Adjust column widths
00908     for ( unsigned int i = 0; i < mxElements.size1(); ++i )
00909         for ( unsigned int j = 0; j < mxElements.size2(); ++j )
00910         {
00911             unsigned int nLen = mxElements( i, j ).size();
00912             if ( aColLen.at( j ) > nLen )
00913             {
00914                 std::string sSpace;
00915                 for ( unsigned int k = 0; k < (aColLen.at( j ) - nLen); ++k )
00916                     sSpace += " ";
00917                 mxElements( i, j ) = sSpace + mxElements( i, j );
00918             }
00919         }
00920     
00921     if ( !bFormula )
00922         return mxElements;
00923     
00924     // Process elements for constraint formula display.
00925     for ( unsigned int i = 0; i < mxElements.size1(); ++i )
00926     {
00927         for ( unsigned int j = 0; j < mxElements.size2(); ++j )
00928         {
00929             double fVal = m_aArray( i, j );
00930             string sElem = mxElements( i, j );
00931             if ( fVal == 1.0 )
00932             {
00933                 string::size_type nPos = sElem.find_first_of( "1" );
00934                 if ( nPos != string::npos )
00935                 {
00936                     sElem[nPos] = ' ';
00937                     mxElements( i, j ) = sElem;
00938                 }
00939             }
00940             else if ( fVal == -1.0 )
00941             {
00942                 // find "-1"
00943                 string::size_type nPos = sElem.find_first_of( "-" );
00944                 string::size_type nPos2 = nPos + 1;
00945                 if ( nPos != string::npos && nPos2 != string::npos && sElem[nPos2] == '1' )
00946                 {
00947                     sElem[nPos]  = ' ';
00948                     sElem[nPos2] = '-';
00949                     mxElements( i, j ) = sElem;
00950                 }
00951             }
00952                 
00953             if ( j != 0 )
00954             {
00955                 string sElem = mxElements( i, j );
00956                 ostringstream os;
00957                 os << repeatString( " ", nColSpace );
00958                 if ( fVal >= 0 )
00959                     os << "+" << sElem.substr(1);
00960                 else
00961                 {
00962                     string::size_type nPos = sElem.find_first_of( "-", 0 );
00963                     if ( nPos != string::npos )
00964                         sElem[nPos] = ' ';
00965                     os << "-" << sElem.substr(1);
00966                 }
00967                 mxElements( i, j ) = os.str();
00968             }
00969         }
00970     }
00971     return mxElements;
00972 }
00973 
00974 void Matrix::print(size_t prec, size_t colspace) const
00975 {
00976     using std::string;
00977     using std::ostringstream;
00978 
00979     // Print to stdout
00980     ostringstream os;
00981     const bnu::matrix< string > mElements = getDisplayElements(prec, colspace, false);
00982     for ( unsigned int i = 0; i < mElements.size1(); ++i )
00983     {
00984         os << "|";
00985         for ( unsigned int j = 0; j < mElements.size2(); ++j )
00986         {
00987             std::string s = mElements( i, j );
00988             os << s;
00989         }
00990         os << repeatString( " ", colspace ) << "|" << endl;
00991     }
00992     cout << os.str();
00993 }
00994 
00995 // ----------------------------------------------------------------------------
00996 // Non-member functions
00997 
00998 const Matrix operator+(const Matrix& mx, double scalar)
00999 {
01000     return mx + scalar;
01001 }
01002 
01003 const Matrix operator+(double scalar, const Matrix& mx)
01004 {
01005     return mx + scalar;
01006 }
01007 
01008 const Matrix operator*(double scalar, const Matrix& mx)
01009 {
01010     return mx * scalar;
01011 }
01012 
01013 }}
01014 

Generated on Mon Jul 28 09:13:20 2008 for scsolver by  doxygen 1.5.3