source/numeric/lpmodel.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/lpmodel.hxx"
00030 #include "numeric/lpbase.hxx"
00031 #include "numeric/matrix.hxx"
00032 #include "tool/global.hxx"
00033 
00034 #include <iostream>
00035 #include <sstream>
00036 #include <algorithm>
00037 #include <vector>
00038 #include <map>
00039 
00040 using ::std::vector;
00041 using ::std::string;
00042 using ::std::map;
00043 using ::std::cout;
00044 using ::std::endl;
00045 using ::std::ostringstream;
00046 using ::scsolver::numeric::Matrix;
00047 using ::std::distance;
00048 using ::std::find;
00049 
00050 namespace scsolver { namespace numeric { namespace lp {
00051 
00052 class NonBoundingException : public ::std::exception
00053 {
00054 public:
00055         virtual const char* what() const throw()
00056         {
00057                 return "Non bounding exception";
00058         }
00059 };
00060 
00061 struct AttrBound
00062 {
00063         bool Enabled;
00064         double Value;
00065 };
00066 
00067 struct VarBounds
00068 {
00069         AttrBound Upper;
00070         AttrBound Lower;
00071 };
00072 
00073 typedef map<size_t,VarBounds> VarBoundMap;
00074 
00075 class ModelImpl
00076 {
00077 public:
00078         ModelImpl();
00079         ModelImpl( const ModelImpl& );
00080         ~ModelImpl() throw();
00081         void swap( ModelImpl& ) throw();
00082         void print() const;
00083 
00084         size_t getDecisionVarSize() const { return m_mxCost.cols(); }
00085         size_t getConstraintCount() const { return m_mxConstraint.rows(); }
00086 
00087         double getCost( size_t rowid ) const { return m_mxCost( 0, rowid ); }
00088         Matrix getCostVector() const { return m_mxCost; }
00089         void setCostVectorElement( size_t, double );
00090         void setCostVector( const std::vector<double>& );
00091         void deleteCostVectorElements( const std::vector<size_t>& );
00092 
00093         AttrBound getVarBoundAttribute( size_t, BoundType ) const;
00094         double    getVarBound( size_t, BoundType ) const;
00095         void      setVarBound( size_t, BoundType, double );
00096         bool  isVarBounded( size_t, BoundType ) const;
00097         void deleteVarRanges( const std::vector<size_t>& );
00098 
00099         void deleteVariables( const std::vector<size_t>& );
00100 
00101         GoalType getGoal() const { return m_eGoal; }
00102         void setGoal( GoalType e ) { m_eGoal = e; }
00103         
00104         double getObjectiveFuncConstant() const { return m_fObjFuncConstant; }
00105         void setObjectiveFuncConstant( double f ) { m_fObjFuncConstant = f; }
00106 
00107         unsigned long getPrecision() const { return m_nPrecision; }
00108         void       setPrecision( unsigned long n ) { m_nPrecision = n; }
00109 
00110         bool getVarPositive() const { return m_bVarPositive; }
00111         void setVarPositive( bool b ) { m_bVarPositive = b; }
00112 
00113         bool getVarInteger() const
00114         {
00115                 return m_bVarInteger;
00116         }
00117 
00118         void setVarInteger( bool b )
00119         {
00120                 m_bVarInteger =  b;
00121         }
00122 
00123         bool getVerbose() const { return m_bVerbose; }
00124         void setVerbose( bool b ) { m_bVerbose = b; }
00125 
00126         double getConstraint( size_t, size_t ) const;
00127         Matrix getConstraintMatrix() const { return m_mxConstraint; }
00128         Matrix getRhsVector() const { return m_mxRHS; }
00129         double getRhsValue( size_t ) const;
00130         void setRhsValue( size_t, double );
00131         vector<EqualityType> getEqualityVector() const { return m_eEqualities; }
00132         EqualityType getEqualityByRowId( size_t i ) const { return m_eEqualities.at( i ); }
00133         void addConstraint( const std::vector<double>&, EqualityType, double );
00134         void setStandardConstraintMatrix( const Matrix&, const Matrix& );
00135         void deleteConstraintMatrixColumns( const std::vector<size_t>& );
00136         
00137 private:
00138         Matrix m_mxCost;        // row vector
00139         Matrix m_mxConstraint;
00140         Matrix m_mxRHS;         // column vector
00141 
00142         vector<VarBounds> m_cnVarRanges;
00143         vector<EqualityType> m_eEqualities;
00144 
00145         GoalType m_eGoal;
00146         unsigned long m_nPrecision;
00147         bool m_bVarPositive;
00148         bool m_bVarInteger;
00149 
00150         bool m_bVerbose;
00151         double m_fObjFuncConstant;
00152 };
00153 
00154 
00155 ModelImpl::ModelImpl() : 
00156         m_mxCost( 0, 0 ), m_mxConstraint( 0, 0 ), m_mxRHS( 0, 0 ),
00157         m_nPrecision( 2 ), m_bVarPositive( true ), m_bVerbose( false ),
00158         m_fObjFuncConstant( 0.0 )
00159 {
00160 }
00161 
00162 ModelImpl::ModelImpl( const ModelImpl& other ) :
00163         m_mxCost( other.m_mxCost ), 
00164         m_mxConstraint( other.m_mxConstraint ), 
00165         m_mxRHS( other.m_mxRHS ),
00166         m_cnVarRanges( other.m_cnVarRanges ),
00167         m_eEqualities( other.m_eEqualities ), 
00168         m_eGoal( other.m_eGoal ), 
00169         m_nPrecision( other.m_nPrecision ), 
00170         m_bVarPositive( other.m_bVarPositive ), 
00171         m_bVerbose( other.m_bVerbose )
00172 {
00173 }
00174 
00175 ModelImpl::~ModelImpl() throw()
00176 {
00177 }
00178 
00179 void ModelImpl::swap( ModelImpl& other ) throw()
00180 {
00181         m_mxCost.swap( other.m_mxCost );
00182         m_mxConstraint.swap( other.m_mxConstraint );
00183         m_mxRHS.swap( other.m_mxRHS );
00184         std::swap( m_cnVarRanges, other.m_cnVarRanges );
00185         std::swap( m_eEqualities, other.m_eEqualities );
00186         std::swap( m_eGoal, other.m_eGoal );
00187         std::swap( m_nPrecision, other.m_nPrecision );
00188         std::swap( m_bVarPositive, other.m_bVarPositive );
00189         std::swap( m_bVarInteger, other.m_bVarInteger );
00190         std::swap( m_bVerbose, other.m_bVerbose );
00191 }
00192 
00193 void ModelImpl::setCostVectorElement( size_t nId, double fVal )
00194 {
00195         // Cost vector must be a row vector because the X vector is a column.
00196         m_mxCost( 0, nId ) = fVal;
00197 }
00198 
00199 void ModelImpl::setCostVector( const std::vector<double>& cn )
00200 {
00201         std::vector<double>::const_iterator it, 
00202                 itBeg = cn.begin(), itEnd = cn.end();
00203         for ( it = itBeg; it != itEnd; ++it )
00204         {
00205                 size_t nDist = std::distance( itBeg, it );
00206                 setCostVectorElement( nDist, *it );
00207         }
00208 }
00209 
00210 void ModelImpl::deleteCostVectorElements( const std::vector<size_t>& cn )
00211 {
00212         m_mxCost.deleteColumns( cn );
00213 }
00214 
00215 AttrBound ModelImpl::getVarBoundAttribute( size_t i, BoundType e ) const
00216 {
00217         AttrBound ab;
00218         if ( i >= m_cnVarRanges.size() )
00219         {
00220                 // requested variable index is out of bound.
00221                 ab.Enabled = false;
00222                 ab.Value = 0.0;
00223         }
00224         else
00225         {
00226                 VarBounds vb = m_cnVarRanges[i];
00227                 switch ( e )
00228                 {
00229                 case BOUND_LOWER:
00230                         ab = vb.Lower;
00231                         break;
00232                 case BOUND_UPPER:
00233                         ab = vb.Upper;
00234                         break;
00235                 default:
00236                         OSL_ASSERT( !"unknown boundary" );
00237                 }
00238         }
00239 
00240         return ab;
00241 }
00242 
00243 double ModelImpl::getVarBound( size_t i, BoundType e ) const
00244 {
00245         AttrBound ab = getVarBoundAttribute( i, e );
00246         if ( ab.Enabled )
00247                 return ab.Value;
00248         else
00249                 throw NonBoundingException();
00250 }
00251 
00252 void ModelImpl::setVarBound( size_t nVarId, BoundType e, double fBound )
00253 {
00254         size_t nSize = m_cnVarRanges.size();
00255         cout << "size is " << nSize << " and request is " << nVarId << endl;
00256         if ( nVarId >= nSize )
00257         {
00258                 // Fill the container as necessary
00259                 for ( size_t i = 0; i < nVarId + 1 - nSize; ++i )
00260                 {
00261                         cout << "inserting new VarBounds at " << i << endl;
00262                         VarBounds vb;
00263                         vb.Lower.Enabled = false;
00264                         vb.Lower.Value = 0.0;
00265                         vb.Upper.Enabled = false;
00266                         vb.Upper.Value = 0.0;
00267                         m_cnVarRanges.push_back( vb );
00268                 }
00269         }
00270 
00271         switch ( e )
00272         {
00273         case BOUND_LOWER:
00274 
00275                 m_cnVarRanges[nVarId].Lower.Enabled = true;
00276                 m_cnVarRanges[nVarId].Lower.Value = fBound;
00277                 break;
00278         case BOUND_UPPER:
00279                 m_cnVarRanges[nVarId].Upper.Enabled = true;
00280                 m_cnVarRanges[nVarId].Upper.Value = fBound;
00281                 break;
00282         default:
00283                 OSL_ASSERT( !"unknown boundary" );
00284         }
00285 }
00286 
00287 bool ModelImpl::isVarBounded( size_t i, BoundType e ) const
00288 {
00289         AttrBound ab = getVarBoundAttribute( i, e );
00290         return ab.Enabled;
00291 }
00292 
00293 void ModelImpl::deleteVarRanges( const std::vector<size_t>& cnVarIds )
00294 {
00295         vector<size_t> Ids( cnVarIds );
00296         ::std::sort( Ids.begin(), Ids.end() );
00297     vector<VarBounds>::iterator itr, 
00298                 itrBeg = m_cnVarRanges.begin(), itrEnd = m_cnVarRanges.end();
00299 
00300         vector<VarBounds> cnVarRanges( m_cnVarRanges.size() );
00301         for ( itr = itrBeg; itr != itrEnd; ++itr )
00302         {
00303                 size_t nCurId = distance( itrBeg, itr );
00304                 if ( find( cnVarIds.begin(), cnVarIds.end(), nCurId ) == cnVarIds.end() )
00305                         // ID not in delete list
00306                         cnVarRanges.push_back( *itr );
00307         }
00308         m_cnVarRanges.swap( cnVarRanges );
00309 }
00310 
00311 void ModelImpl::deleteVariables( const std::vector<size_t>& cnVarIds )
00312 {
00313         Debug( "deleteVariables" );
00314         deleteCostVectorElements( cnVarIds );
00315         deleteConstraintMatrixColumns( cnVarIds );
00316         deleteVarRanges( cnVarIds );
00317 }
00318 
00319 double ModelImpl::getConstraint( size_t nRow, size_t nCol ) const
00320 {
00321         return m_mxConstraint( nRow, nCol );
00322 }
00323 
00324 double ModelImpl::getRhsValue( size_t nId ) const
00325 {
00326         return m_mxRHS( nId, 0 );
00327 }
00328 
00329 void ModelImpl::setRhsValue( size_t nId, double fVal )
00330 {
00331         m_mxRHS( nId, 0 ) = fVal;
00332 }
00333 
00334 void ModelImpl::addConstraint( const std::vector<double>& aConst, EqualityType eEqual, double fRHS )
00335 {
00336         size_t nRowId = m_mxConstraint.rows();
00337         vector<double>::const_iterator pos;
00338         for ( pos = aConst.begin(); pos != aConst.end(); ++pos )
00339         {
00340                 size_t nColId = distance( aConst.begin(), pos );
00341                 m_mxConstraint( nRowId, nColId ) = *pos;
00342         }
00343         m_eEqualities.push_back( eEqual );
00344         
00345         // RHS vector must be a column.
00346         m_mxRHS( m_mxRHS.rows(), 0 ) = fRHS;
00347 }
00348 
00349 void ModelImpl::setStandardConstraintMatrix( const Matrix& A, const Matrix& B )
00350 {
00351         if ( A.rows() != B.rows() )
00352                 throw MatrixSizeMismatch();
00353         
00354         for ( size_t i = 0; i < A.rows(); ++i )
00355         {
00356                 vector<double> aConst;
00357                 for ( size_t j = 0; j < A.cols(); ++j )
00358                         aConst.push_back( A( i, j ) );
00359                 addConstraint( aConst, EQUAL, B( i, 0 ) );
00360         }
00361 }
00362 
00363 void ModelImpl::deleteConstraintMatrixColumns( const std::vector<size_t>& cn )
00364 {
00365         m_mxConstraint.deleteColumns( cn );
00366 }
00367 
00368 void ModelImpl::print() const
00369 {
00370         using namespace ::boost::numeric::ublas;
00371         size_t nColSpace = 2;
00372         string sX = "x_";
00373         cout << endl << repeatString( "-", 70 ) << endl;
00374         string sGoal;
00375         if ( m_eGoal == GOAL_MAXIMIZE )
00376                 sGoal = "max";
00377         else if ( m_eGoal == GOAL_MINIMIZE )
00378                 sGoal = "min";
00379         else
00380                 //OSL_ASSERT( !"wrong goal" );
00381                 sGoal = "unknown";
00382 
00383         ostringstream osLine;
00384         osLine << "Objective: ";
00385         bool bFirst = true;
00386         for ( size_t j = 0; j < m_mxCost.cols(); ++j )
00387         {
00388                 double fVal = m_mxCost( 0, j );
00389                 if ( fVal != 0.0 )
00390                 {
00391                         if ( bFirst )
00392                         {
00393                                 bFirst = false;
00394                                 osLine << fVal << sX << j;
00395                         }
00396                         else
00397                         {
00398                                 if ( fVal > 0.0 )
00399                                         osLine << " + " << fVal << sX << j;
00400                                 else
00401                                         osLine << " - " << abs(fVal) << sX << j;
00402                         }
00403                 }
00404         }
00405         osLine << "  (" << sGoal << ")";
00406         cout << osLine.str() << endl << repeatString( "-", 70 ) << endl;
00407         cout << "Subject to Constraints:" << endl << endl;
00408         matrix< string > mElements = m_mxConstraint.getDisplayElements( 0, nColSpace, true );
00409         matrix< string > mRHS = m_mxRHS.getDisplayElements( 0, nColSpace, false );
00410         
00411         // Print constraints
00412         for ( size_t i = 0; i < m_mxConstraint.rows(); ++i )
00413         {
00414                 osLine.str( "" );
00415                 for ( size_t j = 0; j < m_mxConstraint.cols(); ++j )
00416                 {
00417                         string s = mElements( i, j );
00418                         double f = m_mxConstraint( i, j );
00419                         ostringstream osVar;
00420                         osVar << s << sX << j;
00421                         if ( f == 0.0 )
00422                                 osLine << repeatString( " ", osVar.str().length() );
00423                         else
00424                                 osLine << osVar.str();
00425                 }
00426                 
00427                 osLine << repeatString( " ", nColSpace );
00428                 
00429                 switch ( m_eEqualities.at( i ) )
00430                 {
00431                         case GREATER_EQUAL:
00432                                 osLine << ">=";
00433                                 break;
00434                         case EQUAL:
00435                                 osLine << " =";
00436                                 break;
00437                         case LESS_EQUAL:
00438                                 osLine << "<=";
00439                                 break;
00440                         default:
00441                                 OSL_ASSERT( !"wrong case" );
00442                 }
00443                 
00444                 osLine << repeatString( " ", nColSpace ) << m_mxRHS( i, 0 );
00445                 cout << osLine.str() << endl;
00446         }
00447         cout << repeatString( "-", 70 ) << endl;
00448         
00449         if ( m_bVarPositive )
00450         {
00451                 cout << "All decision variables are assumed positive" << endl;
00452                 cout << repeatString( "-", 70 ) << endl;
00453         }
00454         
00455         // Display variable boundaries.
00456         Matrix mxCost = getCostVector(); // row vector
00457         osLine.str( "" );
00458         for ( size_t i = 0; i < mxCost.cols(); ++i )
00459         {
00460                 osLine << "x_" << i << ": ";
00461                 bool bLower = isVarBounded( i, BOUND_LOWER );
00462                 bool bUpper = isVarBounded( i, BOUND_UPPER );
00463                 if ( bLower || bUpper )
00464                 {
00465                         if ( bLower )
00466                         {
00467                                 double fBound = getVarBound( i, BOUND_LOWER );
00468                                 osLine << fBound;
00469                         }
00470                         else
00471                                 osLine << "[none]";
00472 
00473                         osLine << " - ";
00474                         
00475                         if ( bUpper )
00476                         {
00477                                 double fBound = getVarBound( i, BOUND_UPPER );
00478                                 osLine << fBound;
00479                         }
00480                         else
00481                                 osLine << "[none]";
00482                 }
00483                 else
00484                         osLine << "[unbounded]";
00485                 osLine << endl;
00486         }
00487         cout << osLine.str();
00488         cout << repeatString( "-", 70 ) << endl;
00489 }
00490 
00491 
00492 //---------------------------------------------------------------------------
00493 // Model
00494 
00495 Model::Model() : m_pImpl( new ModelImpl() )
00496 {
00497 }
00498 
00499 Model::Model( const Model& other ) : m_pImpl( new ModelImpl( *other.m_pImpl.get() ) )
00500 {
00501 }
00502 
00503 Model::~Model()
00504 {
00505 }
00506 
00507 void Model::print() const
00508 {
00509         m_pImpl->print();
00510 }
00511 
00512 size_t Model::getDecisionVarSize() const
00513 {
00514         return m_pImpl->getDecisionVarSize();
00515 }
00516 
00517 size_t Model::getConstraintCount() const
00518 {
00519         return m_pImpl->getConstraintCount();
00520 }
00521 
00522 double Model::getCost( size_t rowid ) const
00523 {
00524         return m_pImpl->getCost( rowid );
00525 }
00526 
00532 Matrix Model::getCostVector() const
00533 {
00534         return m_pImpl->getCostVector();
00535 }
00536 
00537 void Model::setCostVectorElement( size_t i, double fVal )
00538 {
00539         m_pImpl->setCostVectorElement( i, fVal );
00540 }
00541 
00542 void Model::setCostVector( const std::vector<double>& cn )
00543 {
00544         m_pImpl->setCostVector( cn );
00545 }
00546 
00547 
00551 double Model::getVarBound( size_t i, BoundType e ) const
00552 {
00553         return m_pImpl->getVarBound( i, e );
00554 }
00555 
00556 void Model::setVarBound( size_t i, BoundType e, double fValue )
00557 {
00558         m_pImpl->setVarBound( i, e, fValue );
00559 }
00560 
00561 bool Model::isVarBounded( size_t i, BoundType e ) const
00562 {
00563         return m_pImpl->isVarBounded( i, e );
00564 }
00565 
00566 void Model::deleteVariables( const std::vector<size_t>& cnVarIds )
00567 {
00568         m_pImpl->deleteVariables( cnVarIds );
00569 }
00570 
00571 GoalType Model::getGoal() const
00572 {
00573         return m_pImpl->getGoal();
00574 }
00575 
00576 void Model::setGoal( GoalType e )
00577 {
00578         m_pImpl->setGoal( e );
00579 }
00580 
00581 double Model::getObjectiveFuncConstant() const
00582 {
00583         return m_pImpl->getObjectiveFuncConstant();
00584 }
00585 
00586 void Model::setObjectiveFuncConstant( double f )
00587 {
00588         m_pImpl->setObjectiveFuncConstant( f );
00589 }
00590 
00591 unsigned long Model::getPrecision() const
00592 {
00593         return m_pImpl->getPrecision();
00594 }
00595 
00596 void Model::setPrecision( unsigned long i )
00597 {
00598         m_pImpl->setPrecision( i );
00599 }
00600 
00601 bool Model::getVarPositive() const
00602 {
00603         return m_pImpl->getVarPositive();
00604 }
00605 
00606 void Model::setVarPositive( bool b )
00607 {
00608         m_pImpl->setVarPositive( b );
00609 }
00610 
00611 bool Model::getVarInteger() const
00612 {
00613         return m_pImpl->getVarInteger();
00614 }
00615 
00616 void Model::setVarInteger( bool b )
00617 {
00618         m_pImpl->setVarInteger( b );
00619 }
00620 
00621 bool Model::getVerbose() const
00622 {
00623         return m_pImpl->getVerbose();
00624 }
00625 
00626 void Model::setVerbose( bool b )
00627 {
00628         m_pImpl->setVerbose( b );
00629 }
00630 
00631 double Model::getConstraint( size_t nRow, size_t nCol ) const
00632 {
00633         return m_pImpl->getConstraint( nRow, nCol );
00634 }
00635 
00636 Matrix Model::getConstraintMatrix() const
00637 {
00638         return m_pImpl->getConstraintMatrix();
00639 }
00640 
00641 Matrix Model::getRhsVector() const
00642 {
00643         return m_pImpl->getRhsVector();
00644 }
00645 
00646 double Model::getRhsValue( size_t nId ) const
00647 {
00648         return m_pImpl->getRhsValue( nId );
00649 }
00650 
00651 void Model::setRhsValue( size_t nId, double fVal )
00652 {
00653         m_pImpl->setRhsValue( nId, fVal );
00654 }
00655 
00656 std::vector<EqualityType> Model::getEqualityVector() const
00657 {
00658         return m_pImpl->getEqualityVector();
00659 }
00660 
00661 EqualityType Model::getEquality( size_t i ) const
00662 {
00663         return m_pImpl->getEqualityByRowId( i );
00664 }
00665 
00666 void Model::addConstraint( const std::vector< double >& v, EqualityType e, double fRhs )
00667 {
00668         m_pImpl->addConstraint( v, e, fRhs );
00669 }
00670 
00671 void Model::setStandardConstraintMatrix( const Matrix& mxConst, const Matrix& mxRhs )
00672 {
00673         m_pImpl->setStandardConstraintMatrix( mxConst, mxRhs );
00674 }
00675 
00676 
00677 }}}
00678 
00679 
00680 

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