00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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
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
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
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
00277 size_t nRow = nSize;
00278 do
00279 {
00280
00281 --nRow;
00282 double fPivot = U( nRow, nRow );
00283 MxRow mrCur( Combo, nRow );
00284 mrCur /= fPivot;
00285 U( nRow, nRow ) = 1.0;
00286
00287
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
00318 size_t nRow = 0;
00319 do
00320 {
00321 MxRow mrCur( Combo, nRow );
00322
00323
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 }
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
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() );
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
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
00724
00725 Matrix& Matrix::operator=( const Matrix& r )
00726 {
00727
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
00886 std::vector<unsigned int> aColLen;
00887 for ( unsigned int j = 0; j < m_aArray.size2(); ++j )
00888 aColLen.push_back( 0 );
00889
00890
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
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
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
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
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
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