source/numeric/lpsimplex.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 #include <osl/diagnose.h>
00029 
00030 #include "numeric/lpsimplex.hxx"
00031 #include "numeric/lpmodel.hxx"
00032 #include "tool/global.hxx"
00033 
00034 #include <memory>
00035 #include <iostream>
00036 #include <sstream>
00037 #include <algorithm>
00038 #include <vector>
00039 #include <map>
00040 #include <list>
00041 
00042 using ::std::vector;
00043 using ::std::string;
00044 using ::std::cout;
00045 using ::std::endl;
00046         
00047 namespace scsolver { namespace numeric { namespace lp {
00048 
00049 typedef vector<size_t>                          uInt32Container;
00050 typedef uInt32Container::iterator               uInt32Iter;
00051 typedef uInt32Container::const_iterator uInt32CIter;
00052 
00053 typedef vector<BoundType>                                       BoundContainer;
00054 typedef BoundContainer::iterator                BoundIter;
00055 typedef BoundContainer::const_iterator  BoundCIter;
00056 
00057 class IllegalTwoPhaseSearch : public ::std::exception
00058 {
00059         virtual const char *what() const throw()
00060         {
00061                 return "Illegal nested two phase search detected";
00062         }
00063 };
00064 
00065 //---------------------------------------------------------------------------
00066 // RevisedSimplexImpl
00067 
00068 class RevisedSimplexImpl
00069 {
00070 public:
00071         RevisedSimplexImpl( RevisedSimplex* );
00072         ~RevisedSimplexImpl();
00073 
00074         void solve();
00075         void setEnableTwoPhaseSearch( bool b ) { m_bTwoPhaseAllowed = b; }
00076         bool isTwoPhaseSearchEnabled() { return m_bTwoPhaseAllowed; }
00077 
00078 private:
00079         RevisedSimplex* m_pSelf;
00080 
00081         bool m_bTwoPhaseAllowed;        // is two-phase initial search allowed ?
00082 
00083         Matrix m_aBasicInv;
00084         Matrix m_aUpdateMatrix;
00085         Matrix m_aPriceVector;
00086         Matrix m_aX;
00087         size_t m_nIter;
00088 
00089         Model m_Model;
00090         Matrix m_A, m_B, m_C;
00091         std::vector<bool> m_aBasicVar;
00092         std::vector<size_t> m_aBasicVarId;
00093 
00095         std::list<size_t> m_cnPermVarIndex;
00096 
00097         struct ConstDecVar
00098         {
00099                 size_t Id;
00100                 double Value;
00101         };
00102         std::list<ConstDecVar> m_cnConstDecVarList;
00103 
00104         //-----------------------------------------------------------------------
00105         // Private methods
00106 
00107         Model* getModel() const { return m_pSelf->getModel(); }
00108 
00109         void convertVarRange( Model& );
00110         void runNormalInitSearch();
00111         void runTwoPhaseInitSearch( const std::vector<size_t>& );
00112         void printIterateHeader() const;
00113         bool iterate();
00114 
00115         Matrix solvePriceVector( std::vector<size_t>, const Matrix&, const Matrix& );
00116         void getLambda( const Matrix&, const Matrix&, double&, size_t& ) const;
00117 };
00118 
00119 
00120 RevisedSimplexImpl::RevisedSimplexImpl( RevisedSimplex* p ) : m_pSelf( p ),
00121         m_bTwoPhaseAllowed( true ),
00122         m_aBasicInv( 0, 0 ), m_aUpdateMatrix( 0, 0 ), m_aPriceVector( 0, 0 ),
00123         m_aX( 0, 0 ), m_nIter( 0 )
00124 {
00125 }
00126 
00127 RevisedSimplexImpl::~RevisedSimplexImpl()
00128 {
00129 }
00130 
00139 void RevisedSimplexImpl::convertVarRange( Model& aModel )
00140 {
00141         size_t nColSize = aModel.getCostVector().cols();
00142 
00143         for ( size_t i = 0; i < nColSize; ++i )
00144         {
00145                 if ( aModel.isVarBounded( i, BOUND_LOWER ) )
00146                 {
00147                         double fLBound = aModel.getVarBound( i, BOUND_LOWER );
00148                         cout << i << " lower bound: " << fLBound << endl;
00149 
00150                         vector<double> v( nColSize );
00151                         v.at( i ) = 1.0;
00152                         aModel.addConstraint( v, GREATER_EQUAL, fLBound );
00153                 }
00154 
00155                 if ( aModel.isVarBounded( i, BOUND_UPPER ) )
00156                 {
00157                         double fUBound = aModel.getVarBound( i, BOUND_UPPER );
00158                         cout << i << " upper bound: " << fUBound << endl;
00159 
00160                         vector<double> v( nColSize );
00161                         v.at( i ) = 1.0;
00162                         aModel.addConstraint( v, LESS_EQUAL, fUBound );
00163                 }
00164         }
00165 }
00166 
00167 void RevisedSimplexImpl::solve()
00168 {
00169         // Normalize the objective with use of slack variable(s), and store in 
00170         // the following variables such that:
00171         //
00172         //     A = expanded constraint matrix
00173         //     B = right hand side vector
00174         //     C = expanded cost vector
00175 
00176         Model aModel( *m_pSelf->getCanonicalModel() );
00177         convertVarRange( aModel );
00178         aModel.print();
00179         Matrix A( aModel.getConstraintMatrix() );
00180         Matrix B( aModel.getRhsVector() );
00181         Matrix C( aModel.getCostVector() );
00182 
00183         for ( size_t i = 0; i < A.rows(); ++i )
00184         {
00185                 EqualityType eEq = aModel.getEquality( i );
00186                 switch( eEq )
00187                 {
00188                 case LESS_EQUAL:
00189                         A( i, A.cols() ) = 1;
00190                         break;
00191                 case GREATER_EQUAL:
00192                         A( i, A.cols() ) = -1;
00193                         break;
00194                 default:
00195                         OSL_ASSERT( eEq == EQUAL );
00196                 }
00197                 if ( eEq != EQUAL )
00198                         C( 0, C.cols() ) = 0;
00199         }
00200 
00201         if ( !aModel.getVarPositive() )
00202         {
00203                 if ( aModel.getVerbose() )
00204                         cout << "non-positive variables are not yet supported" << endl;
00205                 throw ModelInfeasible();
00206         }
00207 
00208         // Search for an initial solution.
00209         vector<size_t> aSatRows;    // collection of satisfied rows
00210         vector<size_t> aNonSatRows; // collection of non-satisfied rows
00211         for ( size_t i = 0; i < A.rows(); ++i )
00212                 aNonSatRows.push_back( i );
00213 
00214         // Determine initial basic variables.
00215         vector<bool> aBasicVar; 
00216         for ( size_t j = 0; j < A.cols(); ++j )
00217         {
00218                 bool bNonZeroFound = false;
00219                 long nUniqueRowSigned = -1;
00220                 aBasicVar.push_back( false );
00221                 
00222                 // Check all the coefficients in that column and store the row ID of
00223                 // a non-zero coefficient if and only if that non-zero coefficient is
00224                 // the only non-zero coefficient in that particular column.
00225                 
00226                 for ( size_t i = 0; i < A.rows(); ++i )
00227                         if ( A( i, j ) != 0.0 )
00228                                 if ( bNonZeroFound )
00229                                 {
00230                                         // a second non-zero coefficient encountered (not good)
00231                                         nUniqueRowSigned = -1;
00232                                         break;
00233                                 }
00234                                 else
00235                                 {
00236                                         bNonZeroFound = true;
00237                                         nUniqueRowSigned = i;
00238                                 }
00239                 
00240                 if ( nUniqueRowSigned >= 0 )
00241                 {
00242                         // Such non-zero coefficient exists (see above).
00243 
00244                         size_t nUniqueRow = nUniqueRowSigned;
00245                         double fVal = A( nUniqueRow, j );
00246                         double fRHS = B( nUniqueRow, 0 );
00247                         
00248                         if ( ( fVal >= 0.0 && fRHS >= 0.0 ) || ( fVal < 0.0 && fRHS < 0.0 ) )
00249                         {
00250                                 // The signs match
00251                                 bool bDupMatch = false;
00252                                 vector<size_t>::iterator pos;                           
00253                                 pos = find( aSatRows.begin(), aSatRows.end(), nUniqueRow );
00254                                 if ( pos == aSatRows.end() )
00255                                         aSatRows.push_back( nUniqueRow );
00256                                 else
00257                                         bDupMatch = true;
00258                                 
00259                                 pos = remove( aNonSatRows.begin(), aNonSatRows.end(), nUniqueRow );
00260                                 if ( pos != aNonSatRows.end() )
00261                                         aNonSatRows.erase( pos, aNonSatRows.end() );
00262                                 if ( !bDupMatch )
00263                                         aBasicVar[j] = true;
00264                         }
00265                 }
00266         }
00267 
00268         if ( aModel.getVerbose() )
00269         {
00270                 cout << "A:" << endl;
00271                 A.print( 0 );
00272                 cout << "B:" << endl;
00273                 B.print( 0 );
00274                 cout << "C:" << endl;
00275                 C.print( 0 );
00276                 
00277                 cout << "aSatRows: ";
00278                 printElements( aSatRows, " " );
00279                 cout << "\t" << "aNonSatRows: ";
00280                 printElements( aNonSatRows, " " );
00281                 cout << "\t" << "aBasicVar: ";
00282                 printElements( aBasicVar, " " );
00283                 cout << endl;
00284         }
00285         
00286         m_aBasicVar = aBasicVar;
00287 
00288         m_Model = aModel;
00289         m_A = A;
00290         m_B = B;
00291         m_C = C;
00292 
00293         if ( aNonSatRows.size() > 0 )
00294                 runTwoPhaseInitSearch( aNonSatRows );
00295         else
00296                 runNormalInitSearch();
00297         
00298         // Store all necessary variables before iterations start
00299 
00300         m_aUpdateMatrix.clear();
00301         m_aBasicVarId.clear();
00302         vector<bool>::iterator pos;
00303         for ( pos = m_aBasicVar.begin(); pos != m_aBasicVar.end(); ++pos )
00304                 if ( *pos )
00305                         m_aBasicVarId.push_back( distance( m_aBasicVar.begin(), pos ) );
00306 
00307         m_aPriceVector = solvePriceVector( m_aBasicVarId, m_aBasicInv, C );
00308 
00309         // Start iterations
00310         m_nIter = 0;
00311         while ( !iterate() );
00312 
00313         m_pSelf->setCanonicalSolution( m_aX );
00314         if ( m_Model.getVerbose() )
00315         {
00316                 cout << "x = ";
00317                 m_pSelf->getSolution().trans().print(); 
00318         }
00319 }
00320 
00326 void RevisedSimplexImpl::runNormalInitSearch()
00327 {
00328         // Two phase method NOT necessary
00329         if ( m_Model.getVerbose() )
00330                 Debug( "two phase method NOT necessary" );
00331         
00332         Matrix ABasic( m_A );
00333         vector<size_t> aNonBasicVarId;
00334         vector<bool>::iterator pos;
00335         for ( pos = m_aBasicVar.begin(); pos != m_aBasicVar.end(); ++pos )
00336                 if ( !*pos )
00337                         aNonBasicVarId.push_back( distance( m_aBasicVar.begin(), pos ) );
00338         
00339         if ( m_Model.getVerbose() )
00340         {
00341                 cout << "aNonBasicVarId: ";
00342                 printElements( aNonBasicVarId );
00343                 cout << endl;
00344         }
00345                 
00346         ABasic.deleteColumns( aNonBasicVarId );
00347         Matrix aBasicInv( ABasic.inverse() );
00348         Matrix XBasic = aBasicInv * m_B;
00349                 
00350         size_t nRow = 0;
00351         Matrix X( 0, 0 );
00352         for ( size_t j = 0; j < m_A.cols(); ++j )
00353         {
00354                 // Remember that the X is a single-column matrix
00355                 if ( m_aBasicVar.at(j) )
00356                         X( j, 0 ) = XBasic( nRow++, 0 );
00357                 else
00358                         X( j, 0 ) = 0.0;
00359         }
00360         
00361         // Update member variables.
00362         
00363         m_aX = X;
00364         m_aBasicInv = aBasicInv;
00365 }
00366 
00373 void RevisedSimplexImpl::runTwoPhaseInitSearch( const vector<size_t>& aNonSatRows )
00374 {
00375         if ( !m_bTwoPhaseAllowed )
00376                 throw IllegalTwoPhaseSearch();
00377                 
00378         static const bool bDebugTwoPhase = false;
00379 
00380         if ( m_Model.getVerbose() )
00381                 Debug( "Entering a two-phase search for initial solution" );
00382 
00383         Matrix A2( m_A );
00384         
00385         cout << "initial number of column(s): " << A2.cols() << endl;
00386         vector<size_t>::const_iterator nIter, end = aNonSatRows.end();
00387         for ( nIter = aNonSatRows.begin(); nIter != end; ++nIter )
00388         {
00389                 size_t nRowId = *nIter;
00390                 if ( m_B( nRowId, 0 ) >= 0 )
00391                         A2( nRowId, A2.cols() ) = 1;
00392                 else
00393                         A2( nRowId, A2.cols() ) = -1;
00394         }
00395         
00396         cout << A2.cols() - m_A.cols() << " column(s) added" << endl;
00397 
00398         auto_ptr<Model> model( new Model );
00399         model->setGoal( GOAL_MINIMIZE );
00400         model->setStandardConstraintMatrix( A2, m_B );
00401         model->setVarPositive( true );
00402         for ( size_t i = 0; i < A2.cols(); ++i )
00403                 if ( i < m_A.cols() )
00404                         model->setCostVectorElement( i, 0 );
00405                 else
00406                         model->setCostVectorElement( i, 1 );
00407 
00408         if ( bDebugTwoPhase )
00409                 model->print();
00410 
00411         model->setVerbose( bDebugTwoPhase );
00412         auto_ptr<BaseAlgorithm> algorithm( new RevisedSimplex );
00413 
00414         // This looks ugly, but necessary to prevent nested two-phase search during 
00415         // two phase search. (TODO: find a better approach)
00416         static_cast<RevisedSimplex*>(algorithm.get())->setEnableTwoPhaseSearch( false );
00417 
00418         algorithm->setModel( model.get() );
00419         algorithm->solve();
00420         Matrix Xtmp( algorithm->getSolution() );
00421 
00422         size_t nANumRow = m_A.rows(), nANumCol = m_A.cols(), nA2NumCol = A2.cols();
00423         for ( size_t i = nANumCol; i < nA2NumCol; ++i )
00424         {
00425                 double f = Xtmp( i, 0 ); // Do I need to round this to precision ?
00426                 cout << "f = " << f << endl;
00427                 if ( f != 0.0 )
00428                         throw ModelInfeasible();
00429         }
00430 
00431         Matrix X( 0, 0 );
00432         vector<size_t> aNonBasicVarId;
00433         vector<bool> aBasicVar( m_aBasicVar );
00434 
00435         size_t i = nANumCol;
00436         do
00437         {
00438                 double f = Xtmp( --i, 0 );
00439                 X( i, 0 ) = f;
00440                 if ( aNonBasicVarId.size() < nANumCol - nANumRow && f == 0.0 )
00441                 {
00442                         aBasicVar[i] = false;
00443                         aNonBasicVarId.push_back( i );
00444                 }
00445                 else
00446                         aBasicVar[i] = true;
00447         }
00448         while ( i != 0 );
00449 
00450         sort( aNonBasicVarId.begin(), aNonBasicVarId.end() );
00451         cout << "aNonBasicVarId = ";
00452         printElements( aNonBasicVarId, " " );
00453 
00454         Matrix ABasic( m_A );
00455         ABasic.print( 0 );
00456 
00457         cout << "(" << ABasic.rows() << "," << ABasic.cols() << ")" << endl;
00458 
00459         ABasic.deleteColumns( aNonBasicVarId );
00460         ABasic.print( 0 );
00461 
00462         cout << "(" << ABasic.rows() << "," << ABasic.cols() << ")" << endl;
00463 
00464         Matrix aBasicInv( ABasic.inverse() );
00465         cout << "inverse" << endl;
00466         aBasicInv.print();
00467 
00468         // Update member variables.
00469         
00470         m_aBasicVar = aBasicVar;
00471         m_aX = X;
00472         m_aBasicInv = aBasicInv;
00473         
00474         if ( m_Model.getVerbose() )
00475                 Debug( "Two-phase search found an initial solution" );
00476 }
00477 
00478 void RevisedSimplexImpl::printIterateHeader() const
00479 {
00480         cout << endl;
00481         string line = repeatString( "-", 70 );
00482 
00483         cout << line << endl;
00484         cout << "Iteration " << m_nIter << endl;
00485         cout << line << endl;
00486         
00487         cout << "Basic Variable: ";
00488         printElements( m_aBasicVar );
00489         cout << endl;
00490         
00491         cout << "x(" << m_nIter << ") = ";
00492         m_aX.trans().print( m_Model.getPrecision() );
00493         cout << "cx = " << (m_C*m_aX).operator()( 0, 0 ) << endl;
00494         cout << line << endl;
00495         
00496         cout << "Basic Variable ID: ";
00497         printElements( m_aBasicVarId, " " );
00498         cout << endl << endl;;
00499         
00500         cout << "A^(-1)" << endl;
00501         m_aBasicInv.print();
00502         
00503         cout << endl << "v = ";
00504         m_aPriceVector.print();
00505 }
00506 
00507 bool RevisedSimplexImpl::iterate()
00508 {
00509         bool bVerbose = m_Model.getVerbose();
00510         if ( bVerbose )
00511                 printIterateHeader();
00512 
00513         // m_aBasicVar, m_aBasicVarId, m_aBasicInv, m_aPriceVector
00514         // m_aX, m_A, m_B, m_C
00515 
00516         // Determine IDs of non-basic variables
00517         vector<size_t> aNonBasicVarId;
00518         vector<bool>::iterator bIter;
00519         for ( bIter = m_aBasicVar.begin(); bIter != m_aBasicVar.end(); ++bIter )
00520                 if ( !*bIter )
00521                         aNonBasicVarId.push_back( distance( m_aBasicVar.begin(), bIter ) );
00522 
00523         // Determine entering non-basic variable        
00524         vector<size_t>::iterator nIter, nBegin = aNonBasicVarId.begin(), nEnd = aNonBasicVarId.end();
00525         map<size_t,double> fEnterBasicVars;
00526         double fMin, fMax;
00527         size_t nMin, nMax;
00528         for ( nIter = nBegin; nIter != nEnd; ++nIter )
00529         {
00530                 size_t nId = *nIter;
00531                 double fPrice = m_C( 0, nId ) - 
00532                         ( m_aPriceVector*m_A.getColumn( nId ) ).operator()( 0, 0 );
00533 
00534                 if ( bVerbose )
00535                         cout << "c(" << nId << ") = " << fPrice << endl;
00536 
00537                 fEnterBasicVars.insert( make_pair( nId, fPrice ) );
00538                 if ( nIter == nBegin )
00539                 {
00540                         fMin = fMax = fPrice;
00541                         nMin = nMax = nId;
00542                 }
00543                 else
00544                 {
00545                         if ( fPrice > fMax )
00546                         {
00547                                 fMax = fPrice;
00548                                 nMax = nId;
00549                         }
00550                         if ( fPrice < fMin )
00551                         {
00552                                 fMin = fPrice;
00553                                 nMin = nId;
00554                         }
00555                 }                       
00556         }
00557         
00558         GoalType eGoal = m_Model.getGoal();
00559         if ( ( eGoal == GOAL_MAXIMIZE && fMax <= 0.0 ) ||
00560                  ( eGoal == GOAL_MINIMIZE && fMin >= 0.0 ) )
00561         {
00562                 if ( bVerbose )
00563                         cout << "Optimum solution reached" << endl;
00564                 return true;
00565         }
00566         
00567         size_t nEnterVarId = 0;
00568         if ( eGoal == GOAL_MAXIMIZE )
00569                 nEnterVarId = nMax;
00570         else if ( eGoal == GOAL_MINIMIZE )
00571                 nEnterVarId = nMin;
00572         else
00573                 throw;
00574 
00575         // Calculate dX (delta-X)
00576         Matrix dXBasic = m_aBasicInv * m_A.getColumn( nEnterVarId ) * (-1);
00577         Matrix dX( 0, 0 );
00578         
00579         OSL_ASSERT( dXBasic.rows() == m_aBasicVarId.size() );
00580         
00581         for ( size_t i = 0; i < dXBasic.rows(); ++i )
00582                 dX( m_aBasicVarId.at( i ), 0 ) = dXBasic( i, 0 );
00583         
00584         nEnd = aNonBasicVarId.end();
00585         for ( nIter = aNonBasicVarId.begin(); nIter != nEnd; ++nIter )
00586         {
00587                 size_t nId = *nIter;
00588                 dX( nId, 0 ) = nId == nEnterVarId ? 1.0 : 0.0;
00589         }
00590         if ( bVerbose )
00591         {
00592                 cout << "dX[" << nEnterVarId << "] = ";
00593                 dX.trans().print( m_Model.getPrecision() );
00594         }
00595 
00596         // Check all components of dX to make sure there is at least one negative 
00597         // component.
00598         bool bNegativeFound = false;
00599         for ( size_t i = 0; i < dX.rows(); ++i )
00600                 if ( dX( i, 0 ) < 0.0 )
00601                 {
00602                         bNegativeFound = true;
00603                         break;
00604                 }
00605                 
00606         if ( !bNegativeFound )
00607         {
00608                 if ( bVerbose )
00609                         cout << "Unbounded model with no solution" << endl;
00610                 throw ModelInfeasible();
00611         }
00612 
00613         // Calculate lambda value
00614         double fLambda;
00615         size_t nLeaveVarId;
00616         getLambda( m_aX, dX, fLambda, nLeaveVarId );
00617         
00618         if ( bVerbose )
00619                 cout << "lambda = " << fLambda << "  x" << nEnterVarId << " enters and "
00620                          << "x" << nLeaveVarId << " leaves" << endl;
00621 
00622         m_aX += dX*fLambda;
00623         m_aBasicVar[nEnterVarId].flip();
00624         m_aBasicVar[nLeaveVarId].flip();
00625         size_t nIndexLeaveVar;
00626         for ( nIter = m_aBasicVarId.begin(); nIter < m_aBasicVarId.end(); ++nIter )
00627                 if ( *nIter == nLeaveVarId )
00628                 {
00629                         nIndexLeaveVar = distance( m_aBasicVarId.begin(), nIter );
00630                         *nIter = nEnterVarId;
00631                         break;
00632                 }
00633 
00634         Matrix E( m_aBasicInv.rows(), m_aBasicInv.cols(), true );
00635         double fLeaveVar = dX( nLeaveVarId, 0 );
00636         for ( size_t i = 0; i < E.rows(); ++i )
00637         {
00638                 int nId = m_aBasicVarId.at( i );
00639                 double fdXVal = dX( nId, 0 );
00640                 if ( i == nIndexLeaveVar )
00641                         E( i, i ) = 1.0/fLeaveVar*(-1.0);
00642                 else
00643                         E( i, nIndexLeaveVar ) = fdXVal / fLeaveVar * (-1.0);
00644         }
00645         
00646         // Update invert matrix and price vector.
00647         m_aBasicInv = E*m_aBasicInv;
00648         m_aPriceVector = solvePriceVector( m_aBasicVarId, m_aBasicInv, m_C );
00649         ++m_nIter;
00650         
00651         return false;
00652 }
00653 
00654 Matrix RevisedSimplexImpl::solvePriceVector( std::vector<size_t> aBasicVarId,
00655                 const Matrix& AInv, const Matrix& C )
00656 {
00657         Matrix c;
00658         std::vector<size_t>::iterator pos;
00659         for ( pos = aBasicVarId.begin(); pos != aBasicVarId.end(); ++pos )
00660         {
00661                 size_t i = distance( aBasicVarId.begin(), pos );
00662                 double f = C( 0, aBasicVarId.at( i ) );
00663                 c( 0, i ) = f;
00664         }
00665         return c*AInv;
00666 }
00667 
00668 void RevisedSimplexImpl::getLambda( const Matrix& X, const Matrix& dX, 
00669                 double& rLambda, size_t& rLeaveVarId ) const
00670 {
00671         OSL_ASSERT( X.rows() == dX.rows() );
00672 
00673         double fLambda = 0.0;
00674         size_t nId = 0;
00675         bool bFirst = true;
00676         for ( size_t i = 0; i < X.rows(); ++i )
00677         {
00678                 double fXVal = X( i, 0 );
00679                 double fdXVal = dX( i, 0 );
00680                 if ( fdXVal < 0 )
00681                 {
00682                         double fVal = fXVal / fdXVal * (-1.0);
00683                         if ( bFirst )
00684                         {
00685                                 fLambda = fVal;
00686                                 nId = i;
00687                                 bFirst = false;
00688                         }
00689                         else
00690                         {
00691                                 if ( fVal < fLambda )
00692                                 {
00693                                         fLambda = fVal;
00694                                         nId = i;
00695                                 }
00696                         }
00697                 }
00698         }
00699         
00700         rLambda = fLambda;
00701         rLeaveVarId = nId;
00702 }
00703 
00704 
00705 //---------------------------------------------------------------------------
00706 // RevisedSimplex
00707 
00708 RevisedSimplex::RevisedSimplex() : BaseAlgorithm(),
00709         m_pImpl( new RevisedSimplexImpl( this ) )
00710 {
00711 }
00712 
00713 RevisedSimplex::~RevisedSimplex() throw()
00714 {
00715 }
00716 
00717 void RevisedSimplex::solve()
00718 {
00719         m_pImpl->solve();
00720 }
00721 
00722 void RevisedSimplex::setEnableTwoPhaseSearch( bool b )
00723 {
00724         m_pImpl->setEnableTwoPhaseSearch( b );
00725 }
00726 
00727 //---------------------------------------------------------------------------
00728 // BoundedRevisedSimplexImpl
00729 
00730 typedef std::list<size_t> SizeTypeContainer;
00731 
00732 class BoundedRevisedSimplexImpl
00733 {
00734 public:
00735         BoundedRevisedSimplexImpl( BoundedRevisedSimplex* );
00736         ~BoundedRevisedSimplexImpl();
00737         
00738         void solve();
00739         
00740 private:
00741 
00747         struct VarBoundary
00748         {
00749                 size_t Id;
00750                 double Value;
00751                 BoundType BoundData;
00752         };
00753         
00754         struct EnterBasicVar
00755         {
00756                 size_t Id;
00757                 double Price;
00758                 BoundType BoundData;
00759         };
00760 
00761         BoundedRevisedSimplex* m_pSelf;
00762         
00763         Matrix m_mxBasicInv;
00764         Matrix m_mxUpdateMatrix;
00765         Matrix m_mxPriceVector;
00766         Matrix m_mxX;
00767         size_t m_nIter;
00768 
00769         Matrix m_mxA, m_mxB, m_mxC;
00770         std::vector<bool> m_aBasicVar;
00771         SizeTypeContainer m_aBasicVarId;
00772         SizeTypeContainer m_aNonBasicVarId;
00773         std::vector<size_t> m_aSkipBasicVarId;
00774         std::vector<BoundType> m_aNonBasicVarBoundType;
00775         
00776         std::auto_ptr<Model> m_pModel; // A copy of original model
00777 
00778         Model* getModel() const { return m_pSelf->getModel(); }
00779         
00780         bool findInitialSolution();
00781         bool buildInitialVars( vector<VarBoundary>& );
00782         void initialize();
00783         bool iterateVarBoundary( size_t, size_t, vector<VarBoundary>& );
00784         bool isSolutionFeasible( const Matrix& ) const;
00785         const Matrix solvePriceVector( const SizeTypeContainer&, const Matrix&, const Matrix& ) const;
00786         
00787         bool iterate();
00788         bool queryEnteringNBVar( EnterBasicVar& );
00789         void calculateNewX( const EnterBasicVar&, size_t&, Matrix& );
00790         void updateNBVars( const EnterBasicVar&, size_t );
00791         void updateInverseBasicMatrix( const EnterBasicVar&, size_t, const Matrix& );
00792         void printIterateHeader() const;
00793         bool isPriceBoundEligible( const EnterBasicVar& ) const;
00794         void getLambda( const Matrix&, const Matrix&, double&, size_t& ) const;
00795 
00796 };
00797 
00798 BoundedRevisedSimplexImpl::BoundedRevisedSimplexImpl( BoundedRevisedSimplex* p ) :
00799         m_pSelf( p ), m_mxBasicInv( 0, 0 ), m_mxUpdateMatrix( 0, 0 ), m_mxPriceVector( 0, 0 ),
00800         m_mxX( 0, 0 ), m_nIter( 0 ), m_mxA( 0, 0 ), m_mxB( 0, 0 ), m_mxC( 0, 0 )
00801 {
00802 }
00803 
00804 BoundedRevisedSimplexImpl::~BoundedRevisedSimplexImpl()
00805 {
00806 }
00807 
00808 void BoundedRevisedSimplexImpl::solve()
00809 {
00810         initialize();
00811 
00812         if ( !findInitialSolution() )
00813         {
00814                 if ( m_pModel->getVerbose() )
00815                         cout << "Initial solution not found" << endl;
00816                 throw ModelInfeasible();
00817         }
00818         
00819         if ( m_pModel->getVerbose() )
00820                 cout << "Initial solution found" << endl;
00821 
00822         m_mxPriceVector = solvePriceVector( m_aBasicVarId, m_mxBasicInv, m_mxC );
00823 
00824         m_nIter = 0;
00825         m_aSkipBasicVarId.clear();
00826         
00827         while ( !iterate() );
00828         
00829         Matrix mxSolution;
00830         for ( size_t i = 0; i < m_pModel->getCostVector().cols(); ++i )
00831                 mxSolution( i, 0 ) = m_mxX( i, 0 );
00832 
00833         if ( m_pModel->getVerbose() )
00834         {
00835                 cout << "x = ";
00836                 mxSolution.trans().print();     
00837         }
00838 
00839 #ifdef DEBUG
00840         if ( isSolutionFeasible( mxSolution ) )
00841                 Debug( "Double-checked to make sure the solution is feasible" );
00842         else
00843                 Debug( "Solution not feasible!?" );
00844 #endif
00845 
00846         m_pSelf->setCanonicalSolution( mxSolution );
00847 }
00848 
00849 void BoundedRevisedSimplexImpl::initialize()
00850 {
00851         // Normalize the objective with use of slack variable(s), and 
00852         // store in the following variables such that:
00853         //
00854         //  A = expanded constraint matrix
00855         //  B = right hand side vector
00856         //  C = expanded cost vector
00857 
00858         m_mxBasicInv.clear();
00859         m_mxUpdateMatrix.clear();
00860 
00861         auto_ptr<Model> ptr( new Model( *m_pSelf->getCanonicalModel() ) );
00862         m_pModel = ptr; // Note: transfer of ownership
00863 
00864         m_mxA = m_pModel->getConstraintMatrix();
00865         m_mxB = m_pModel->getRhsVector();
00866         m_mxC = m_pModel->getCostVector();
00867 
00868         // Expand constraint matrix in case the cost vector is wider 
00869         // (the cost vector and the constraint matrix is supposed to 
00870         // have the same column width).
00871         if ( m_mxA.cols() < m_mxC.cols() )
00872         {
00873                 size_t nNewCol = m_mxA.cols();
00874                 nNewCol += m_mxC.cols() - m_mxA.cols();
00875                 m_mxA.resize( m_mxA.rows(), nNewCol );
00876         }
00877 
00878         const size_t nRowSizeA = m_mxA.rows();
00879         for ( size_t i = 0; i < nRowSizeA; ++i )
00880         {
00881                 EqualityType eEq = m_pModel->getEquality( i );
00882                 switch( eEq )
00883                 {
00884                 case LESS_EQUAL:
00885                         m_mxA( i, m_mxA.cols() ) = 1;
00886                         break;
00887                 case GREATER_EQUAL:
00888                         m_mxA( i, m_mxA.cols() ) = -1;
00889                         break;
00890                 default:
00891                         OSL_ASSERT( eEq == EQUAL );
00892                 }
00893                 if ( eEq != EQUAL )
00894                 {
00895                         size_t nCol = m_mxC.cols();
00896                         m_pModel->setCostVectorElement( nCol, 0 );
00897                         m_pModel->setVarBound( nCol, BOUND_LOWER, 0 );
00898                         m_mxC( 0, nCol ) = 0;
00899                 }
00900         }
00901 
00902         if ( m_pModel->getVerbose() )
00903         {
00904                 m_pModel->print();
00905                 cout << "A:" << endl;
00906                 m_mxA.print();
00907                 cout << "B:" << endl;
00908                 m_mxB.print();
00909                 cout << "C:" << endl;
00910                 m_mxC.print();
00911         }
00912 }
00913 
00914 void BoundedRevisedSimplexImpl::printIterateHeader() const
00915 {
00916         cout << endl;
00917         string line = repeatString( "-", 70 );
00918 
00919         cout << line << endl;
00920         cout << "Iteration " << m_nIter << endl;
00921         cout << line << endl;
00922         
00923         cout << "x(" << m_nIter << ") = ";
00924         m_mxX.trans().print( getModel()->getPrecision() );
00925         cout << "cx = " << (m_mxC*m_mxX).operator()( 0, 0 ) << endl;
00926         cout << line << endl;
00927         
00928         cout << "Basic Variable ID: ";
00929         printElements( m_aBasicVarId );
00930         cout << endl << endl;;
00931         
00932         SizeTypeContainer::const_iterator itr, 
00933                 itrBeg = m_aNonBasicVarId.begin(),
00934                 itrEnd = m_aNonBasicVarId.end();
00935         for ( itr = itrBeg; itr != itrEnd; ++itr )
00936         {
00937                 cout << *itr << ": ";
00938                 int idx = distance( itrBeg, itr );
00939                 switch ( m_aNonBasicVarBoundType.at( idx ) )
00940                 {
00941                 case BOUND_LOWER:
00942                         cout << "L" << endl;
00943                         break;
00944                 case BOUND_UPPER:
00945                         cout << "U" << endl;
00946                         break;
00947                 default:
00948                         OSL_ASSERT( !"wrong bound type" );
00949                 }
00950         }
00951         cout << endl;
00952         
00953         cout << "A^(-1) (shortcut calculation)" << endl;
00954         m_mxBasicInv.print();
00955         
00956         cout << endl << "v = ";
00957         m_mxPriceVector.print();
00958 }
00959 
00960 bool BoundedRevisedSimplexImpl::isPriceBoundEligible( const EnterBasicVar& aVar ) const
00961 {
00962         bool b;
00963 
00964         switch ( m_pModel->getGoal() )
00965         {
00966         case GOAL_MAXIMIZE:
00967                 // A maximizing model requires either a lower-bounded non-basic with a 
00968                 // positive price or a upper-bounded non-basic with a negative price.
00969 
00970                 b = ( aVar.Price > 0.0 && aVar.BoundData == BOUND_LOWER ) ||
00971                         ( aVar.Price < 0.0 && aVar.BoundData == BOUND_UPPER );
00972                 break;
00973 
00974         case GOAL_MINIMIZE:
00975                 // A minimizing model requires a lower-bounded non-basic with a negative 
00976                 // price or an upper-bounded non-basic with a positive price.
00977 
00978                 b = ( aVar.Price < 0.0 && aVar.BoundData == BOUND_LOWER ) ||
00979                         ( aVar.Price > 0.0 && aVar.BoundData == BOUND_UPPER );
00980                 break;
00981         default:
00982                 OSL_ASSERT( !"wrong goal" );
00983         }
00984 
00985         return b;
00986 }
00987 
00988 void BoundedRevisedSimplexImpl::getLambda( const Matrix& X, const Matrix& dX, 
00989                 double& rLambda, size_t& rLeaveVarId ) const
00990 {
00991         OSL_ASSERT( X.rows() == dX.rows() );
00992         double fLmdPos = 0.0, fLmdNeg = 0.0, fLmd = 0.0;
00993         size_t nId;
00994         
00995         for ( size_t i = 0; i < X.rows(); ++i )
00996         {
00997                 double fXVal  = X( i, 0 );
00998                 double fdXVal = dX( i, 0 );
00999                 if ( fdXVal > 0.0 && m_pModel->isVarBounded( i, BOUND_UPPER ) )
01000                 {
01001                         // dX positive
01002                         double fUpper = m_pModel->getVarBound( i, BOUND_UPPER );
01003                         double fTmp = ( fUpper - fXVal ) / fdXVal;
01004                         if ( ( fLmdPos != 0.0 && fLmdPos > fTmp ) || fLmdPos == 0.0 )
01005                         {
01006                                 cout << "pos: " << fTmp << " " << i << endl;
01007                                 fLmdPos = fTmp;
01008                         }
01009                 }
01010                 else if ( fdXVal < 0.0 && m_pModel->isVarBounded( i, BOUND_LOWER ) )
01011                 {
01012                         // dX negative
01013                         double fLower = m_pModel->getVarBound( i, BOUND_LOWER );
01014                         double fTmp = ( fXVal - fLower ) / ( fdXVal*(-1) );
01015                         if ( ( fLmdNeg != 0.0 && fLmdNeg > fTmp ) || fLmdNeg == 0.0 )
01016                         {
01017                                 cout << "neg: " << fTmp << " " << i << endl;
01018                                 fLmdNeg = fTmp;
01019                         }
01020                 }
01021                 
01022                 double fLmdTmp;
01023                 if ( fLmdPos != 0.0 && fLmdNeg != 0.0 )
01024                         fLmdTmp = min( fLmdPos, fLmdNeg );
01025                 else if ( fLmdPos != 0.0 )
01026                         fLmdTmp = fLmdPos;
01027                 else if ( fLmdNeg != 0.0 )
01028                         fLmdTmp = fLmdNeg;
01029                 else
01030                         fLmdTmp = 0.0;
01031                         
01032                 if ( ( fLmdTmp != 0.0 && fLmdTmp < fLmd ) || fLmd == 0.0 )
01033                 {
01034                         fLmd = fLmdTmp;
01035                         nId = i;
01036                 }
01037         }
01038         std::swap( fLmd, rLambda );
01039         std::swap( nId, rLeaveVarId );
01040 }
01041 
01042 bool BoundedRevisedSimplexImpl::iterate()
01043 {
01044         if ( getModel()->getVerbose() )
01045                 printIterateHeader();
01046 
01047         EnterBasicVar aEnterVar; // Entering basic variable (ID, Price and BoundType)
01048         if ( queryEnteringNBVar( aEnterVar ) )
01049                 return true;
01050 
01051         size_t nLeaveVarId;     // Leaving basic variable ID
01052         Matrix mxDX;
01053         calculateNewX( aEnterVar, nLeaveVarId, mxDX );
01054         updateNBVars( aEnterVar, nLeaveVarId );
01055         updateInverseBasicMatrix( aEnterVar, nLeaveVarId, mxDX );
01056 
01057         ++m_nIter;
01058         return false;
01059 }
01060 
01066 bool BoundedRevisedSimplexImpl::queryEnteringNBVar( EnterBasicVar& rEnterVar )
01067 {
01068         SizeTypeContainer   aEnterBasicVarId;
01069         vector<EnterBasicVar> aEnterBasicVars;
01070 
01071         SizeTypeContainer::const_iterator itr,
01072                         itrBeg = m_aNonBasicVarId.begin(),
01073                         itrEnd = m_aNonBasicVarId.end();
01074 
01075         // Go though all existing non-basic variables and build a list
01076         // of them with bound type information.
01077         for ( itr = itrBeg; itr != itrEnd; ++itr )
01078         {
01079                 size_t nId = *itr;      // non-basic variable ID
01080 
01081                 // Make sure the variable is not constant equilavent.
01082                 if ( m_pModel->isVarBounded( nId, BOUND_LOWER ) )
01083                 {
01084                         double fBoundVal = m_pModel->getVarBound( nId, BOUND_LOWER );
01085                         if ( m_pModel->isVarBounded( nId, BOUND_UPPER ) && 
01086                                  fBoundVal == m_pModel->getVarBound( nId, BOUND_UPPER ) )
01087                         {
01088                                 Debug( "queryEnteringNBVar: Constant equivalent variable found" );
01089                                 continue;
01090                         }
01091                 }
01092 
01093                 EnterBasicVar aVar;
01094                 aEnterBasicVarId.push_back( nId );
01095                 aVar.Id = nId;
01096 
01097                 aVar.BoundData = m_aNonBasicVarBoundType.at( 
01098                                 distance( itrBeg, itr ) );
01099                 
01100                 // Evaluate pricing
01101                 aVar.Price = m_mxC( 0, nId ) - 
01102                                 ( m_mxPriceVector*m_mxA.getColumn( nId ) ).operator()( 0, 0 );
01103 
01104                 if ( getModel()->getVerbose() )
01105                         cout << "c(" << aVar.Id << ") = " << aVar.Price << endl;
01106                 aEnterBasicVars.push_back( aVar );
01107         }
01108 
01109         bool bFirstEnterVarFound = false;               
01110         itrBeg = aEnterBasicVarId.begin();
01111         itrEnd = aEnterBasicVarId.end();
01112         for ( itr = itrBeg; itr != itrEnd; ++itr )
01113         {
01114                 size_t i = distance( itrBeg, itr );
01115                 EnterBasicVar aVar = aEnterBasicVars.at( i );
01116                 OSL_ASSERT( aVar.Id == *itr );
01117                 
01118                 if ( isPriceBoundEligible( aVar ) )
01119                 {
01120                         if ( !bFirstEnterVarFound )
01121                         {
01122                                 bFirstEnterVarFound = true;
01123                                 rEnterVar = aVar;
01124                         }
01125                         else if ( abs( rEnterVar.Price ) < abs( aVar.Price ) )
01126                                 rEnterVar = aVar;
01127                 }
01128         }
01129         
01130         if ( !bFirstEnterVarFound )
01131         {
01132                 if ( getModel()->getVerbose() )
01133                         cout << "Optimum solution reached" << endl;
01134                 return true;
01135         }
01136         return false;
01137 }
01138 
01144 void BoundedRevisedSimplexImpl::calculateNewX( const EnterBasicVar& aEnterVar,
01145                 size_t& nLeaveVarId, Matrix& mxDX )
01146 {
01147         Matrix mxB = m_mxA.getColumn( aEnterVar.Id );
01148         if ( aEnterVar.BoundData == BOUND_LOWER )
01149                 mxB *= (-1);
01150 
01151         Matrix dXBasic( m_mxBasicInv*mxB );
01152 
01153         Matrix dX;
01154         SizeTypeContainer::const_iterator itr, 
01155                 itrBeg = m_aBasicVarId.begin(), itrEnd = m_aBasicVarId.end();
01156         for ( itr = itrBeg; itr != itrEnd; ++itr )
01157                 dX( *itr, 0 ) = dXBasic( distance( itrBeg, itr ), 0 );
01158 
01159         itrBeg = m_aNonBasicVarId.begin(), itrEnd = m_aNonBasicVarId.end();
01160         
01161         for ( itr = itrBeg; itr != itrEnd; ++itr )
01162         {
01163                 size_t nId = *itr;
01164                 if ( nId == aEnterVar.Id )
01165                 {
01166                         switch ( aEnterVar.BoundData )
01167                         {
01168                         case BOUND_LOWER:
01169                                 dX( nId, 0 ) = 1.0;
01170                                 break;
01171                         case BOUND_UPPER:
01172                                 dX( nId, 0 ) = -1.0;
01173                                 break;
01174                         default:
01175                                 OSL_ASSERT( !"wrong bound type" );
01176                         }
01177                 }
01178                 else
01179                         dX( nId, 0 ) = 0.0;
01180         }
01181         
01182         if ( getModel()->getVerbose() )
01183         {
01184                 cout << "dX[" << aEnterVar.Id << "] = ";
01185                 dX.trans().print( getModel()->getPrecision() );
01186         }
01187 
01188         double fLambda;
01189         getLambda( m_mxX, dX, fLambda, nLeaveVarId );
01190 
01191         if ( fLambda == 0.0 )
01192         {
01193                 if ( m_pModel->getVerbose() )
01194                         cout << "Unbounded model with no solution";
01195                 throw ModelInfeasible();
01196         }
01197         
01198         if ( m_pModel->getVerbose() )
01199                 cout << "lambda = " << fLambda << "  x_" << nLeaveVarId << " leaves and x_"
01200                          << aEnterVar.Id << " enters" << endl;
01201 
01202         m_mxX += dX*fLambda;
01203         mxDX = dX;
01204 }
01205 
01209 void BoundedRevisedSimplexImpl::updateNBVars( const EnterBasicVar& aEnterVar, size_t nLeaveVarId )
01210 {
01211         //-------------------------------------------------------------------------
01212         // Update non-basic variable information
01213         
01214         SizeTypeContainer::iterator itr, 
01215                 itrBeg = m_aNonBasicVarId.begin(), 
01216                 itrEnd = m_aNonBasicVarId.end();
01217 
01218         BoundIter itr2, 
01219                 itr2Beg = m_aNonBasicVarBoundType.begin(), 
01220                 itr2End = m_aNonBasicVarBoundType.end();
01221         
01222         for ( itr = itrBeg, itr2 = itr2Beg ; itr != itrEnd; ++itr, ++itr2 )
01223                 if ( *itr == aEnterVar.Id )
01224                 {
01225                         OSL_ASSERT( *itr2 == aEnterVar.BoundData );
01226                         m_aNonBasicVarId.erase( itr );
01227                         m_aNonBasicVarBoundType.erase( itr2 );
01228                         break;
01229                 }
01230         OSL_ASSERT ( itr != itrEnd && itr2 != itr2End );
01231         
01232         // Since the variable with the index of nLeaveVar is now non-basic, it must be
01233         // bounded at either end.
01234 
01235         if ( m_pModel->isVarBounded( nLeaveVarId, BOUND_LOWER ) &&
01236                  m_mxX( nLeaveVarId, 0 ) == m_pModel->getVarBound( nLeaveVarId, BOUND_LOWER ) )
01237         {
01238                 m_aNonBasicVarId.push_back( nLeaveVarId );
01239                 m_aNonBasicVarBoundType.push_back( BOUND_LOWER );
01240         }
01241         else if ( m_pModel->isVarBounded( nLeaveVarId, BOUND_UPPER ) &&
01242                           m_mxX( nLeaveVarId, 0 ) == m_pModel->getVarBound( nLeaveVarId, BOUND_UPPER ) )
01243         {
01244                 m_aNonBasicVarId.push_back( nLeaveVarId );
01245                 m_aNonBasicVarBoundType.push_back( BOUND_UPPER );
01246         }
01247         
01248         OSL_ASSERT( m_pModel->isVarBounded( nLeaveVarId, BOUND_LOWER ) || 
01249                         m_pModel->isVarBounded( nLeaveVarId, BOUND_UPPER ) );
01250 }
01251 
01252 void BoundedRevisedSimplexImpl::updateInverseBasicMatrix( const EnterBasicVar& aEnterVar, size_t nLeaveVarId, const Matrix& mxDX )
01253 {
01254         //-------------------------------------------------------------------------
01255         // Update the inverse matrix if the leaving variable is basic
01256         
01257         SizeTypeContainer::iterator itrBeg = m_aBasicVarId.begin(), itrEnd = m_aBasicVarId.end();
01258         SizeTypeContainer::iterator itr = find( itrBeg, itrEnd, nLeaveVarId );
01259         if ( itr != itrEnd )
01260         {
01261                 *itr = aEnterVar.Id;
01262                 size_t nIndexLeaveVar = distance( itrBeg, itr );
01263                 OSL_ASSERT( m_mxBasicInv.isSquare() );
01264                 Matrix mxE( m_mxBasicInv.rows(), m_mxBasicInv.cols(), true );
01265                 double fLeaveVar = mxDX( nLeaveVarId, 0 );
01266 
01267                 for ( SizeTypeContainer::iterator itr2 = itrBeg; 
01268                           itr2 != itrEnd; ++itr2 )
01269                 {
01270                         size_t nBVarId = *itr2, nRowId = distance( itrBeg, itr2 );
01271                         double fDXVal = mxDX( nBVarId, 0 );
01272                         if ( nRowId == nIndexLeaveVar )
01273                                 if ( aEnterVar.BoundData == BOUND_LOWER )
01274                                         mxE( nRowId, nRowId ) = -1.0 / fLeaveVar;
01275                                 else
01276                                         mxE( nRowId, nRowId ) =  1.0 / fLeaveVar; //??
01277                         else
01278                                 mxE( nRowId, nIndexLeaveVar ) = fDXVal / fLeaveVar * (-1.0);
01279                 }
01280                 
01281                 if ( m_pModel->getVerbose() )
01282                 {
01283                         cout << "E:";
01284                         mxE.print( m_pModel->getPrecision() );
01285                 }
01286                 
01287                 m_mxBasicInv = mxE * m_mxBasicInv;
01288                 m_mxPriceVector = solvePriceVector( m_aBasicVarId, m_mxBasicInv, m_mxC );
01289         }
01290 }
01291 
01299 bool BoundedRevisedSimplexImpl::findInitialSolution()
01300 {
01301         m_pModel->print();
01302         size_t nNumInitNonBasic = m_mxA.cols() - m_mxB.rows();
01303         if ( m_pModel->getVerbose() )
01304         {
01305                 const string line = repeatString( "-", 70 );
01306                 cout << endl << line << endl;
01307                 cout << "Initial solution search" << endl << line << endl;
01308                 cout << "nNumInitNonBasic = " << nNumInitNonBasic << endl;
01309         }
01310 
01311         vector<VarBoundary> aArray;
01312         return iterateVarBoundary( 0, nNumInitNonBasic, aArray );
01313 }
01314 
01335 bool BoundedRevisedSimplexImpl::buildInitialVars( vector<VarBoundary>& cnNonBasic )
01336 {
01337         Debug( "buildInitialVars" );
01338         Debug( "mxA" );
01339         m_mxA.print();
01340         Debug( "mxB" );
01341         m_mxB.print();
01342         Debug( "mxC" );
01343         m_mxC.print();
01344 
01345         size_t nCostSize = m_mxC.cols();
01346 
01347         std::list<size_t> cnBasicId; // permutation of basic variable IDs
01348         for ( size_t i = 0; i < nCostSize; ++i )
01349                 cnBasicId.push_back( i );
01350 
01351         Matrix mxInitX( nCostSize, 1 );
01352 
01353         Debug( "All IDs: " );
01354         printElements( cnBasicId );
01355 
01356         Matrix mxLHSSum( m_mxA.rows(), 1 ); // matrix to keep track of left-hand-side sums
01357         SizeTypeContainer cnNBColId;        // non-basic variable IDs
01358         std::vector<BoundType> cnNBBoundType;   // non-basic bound type
01359         cout << "NonBasicID: ";
01360 
01361         std::vector<VarBoundary>::const_iterator itr, 
01362                 itrBeg = cnNonBasic.begin(), itrEnd = cnNonBasic.end();
01363         for ( itr = itrBeg; itr != itrEnd; ++itr )
01364         {
01365                 double fNBVal = itr->Value;
01366                 size_t nColId = itr->Id;
01367                 cout << nColId << " ";
01368                 mxInitX( nColId, 0 ) = fNBVal;
01369                 cnNBBoundType.push_back( itr->BoundData );
01370                 cnNBColId.push_back( nColId );
01371                 cnBasicId.remove( nColId );
01372                 for ( size_t nRowId = 0; nRowId < m_mxA.rows(); ++nRowId )
01373                         mxLHSSum( nRowId, 0 ) += m_mxA( nRowId, nColId ) * fNBVal;
01374         }
01375         cout << endl;
01376 
01377         Debug( "Basic IDs: " );
01378         printElements( cnBasicId );
01379 
01380         Matrix mxBasic( m_mxA );
01381         mxBasic.deleteColumns( toVector<SizeTypeContainer, size_t>(cnNBColId) );
01382 
01383         // Now solve for initial basic variables (mxX).
01384         Matrix mxBasicInv = mxBasic.inverse();
01385         Matrix mxNewRHS = m_mxB - mxLHSSum;
01386         Matrix mxBaseX = mxBasicInv*mxNewRHS;
01387 
01388         mxBasic.print();
01389         mxLHSSum.print();
01390         Debug( "initial basic variable:" );
01391         mxBaseX.print();
01392 
01393         // Transfer basic variables into initial X vector.  For each variable,
01394         // make sure that the value satisfies its boundary condition if it's
01395         // bounded.
01396 
01397         // TODO: Find a way to back-track if an initial basic variable does not
01398         // satisfy its boundary condition.
01399 
01400         std::list<size_t>::const_iterator itrLt, 
01401                 itrLtBeg = cnBasicId.begin(), itrLtEnd = cnBasicId.end();
01402         for ( itrLt = itrLtBeg; itrLt != itrLtEnd; ++itrLt )
01403         {
01404                 size_t nVarId = *itrLt;
01405                 double fBaseVal = mxBaseX( distance( itrLtBeg, itrLt ), 0 );
01406 
01407                 // check lower boundary condition
01408                 if ( m_pModel->isVarBounded( nVarId, BOUND_LOWER ) )
01409                 {
01410                         double fBound = m_pModel->getVarBound( nVarId, BOUND_LOWER );
01411                         if ( fBaseVal < fBound )
01412                         {
01413                                 cout << nVarId << " basic variable (" << fBaseVal << ") < lower bound (" 
01414                                          << fBound << ")" << endl;
01415                                 return false;
01416                         }
01417                 }
01418 
01419                 // check upper boundary condition
01420                 if ( m_pModel->isVarBounded( nVarId, BOUND_UPPER ) )
01421                 {
01422                         double fBound = m_pModel->getVarBound( nVarId, BOUND_UPPER );
01423                         if ( fBaseVal > fBound )
01424                         {
01425                                 cout << nVarId << " basic variable (" << fBaseVal << ") > upper bound (" 
01426                                          << fBound << ")" << endl;
01427                                 return false;
01428                         }
01429                 }
01430                 mxInitX( nVarId, 0 ) = fBaseVal;
01431         }
01432 
01433         Debug( "initial X:" );
01434         mxInitX.trans().print();
01435 
01436         m_mxX.swap( mxInitX );
01437         m_mxBasicInv.swap( mxBasicInv );
01438         swap( m_aBasicVarId, cnBasicId );
01439         swap( m_aNonBasicVarId, cnNBColId );
01440         swap( m_aNonBasicVarBoundType, cnNBBoundType );
01441 
01442         return true;
01443 }
01444 
01457 bool BoundedRevisedSimplexImpl::iterateVarBoundary( size_t nIdx, size_t nUpper, 
01458                 vector<VarBoundary>& aArray )
01459 {       
01460         if ( aArray.size() == nUpper )
01461         {
01462                 cout << "array size maxed: " << aArray.size() << endl;
01463                 return buildInitialVars( aArray );
01464         }
01465 
01466         if ( nIdx > m_mxC.cols() )
01467                 // Not enough non-basic variables found
01468                 return false;
01469 
01470         // Check both boundaries of a variable at the current ID, and if either 
01471         // one is bounded, then get that value and its side and store it into 
01472         // the array.
01473         BoundType e[2] = { BOUND_LOWER, BOUND_UPPER };
01474         for ( size_t i = 0; i < 2; ++i )
01475                 if ( m_pModel->isVarBounded( nIdx, e[i] ) )
01476                 {
01477                         cout << "index: a" << nIdx << "a\tarray size: " << aArray.size() << "\t";
01478                         if ( i == 0 )
01479                                 cout << "lower" << endl;
01480                         else
01481                                 cout << "upper" << endl;
01482                         VarBoundary temp;
01483                         temp.Id = nIdx;
01484                         temp.Value = m_pModel->getVarBound( nIdx, e[i] );
01485                         temp.BoundData = e[i];
01486                         aArray.push_back( temp );
01487                         if ( m_pModel->getVerbose() )
01488                         {
01489                                 cout << nIdx << " bounded at ";
01490                                 if ( e[i] == BOUND_LOWER )
01491                                         cout << "lower end";
01492                                 else
01493                                         cout << "upper end";
01494                                 cout << " (" << temp.Value << ")" << endl;
01495                         }
01496                         break;
01497 #if 0
01498                         if ( iterateVarBoundary( nIdx+1, nUpper, aArray ) )
01499                                 return true;
01500                         aArray.pop_back();
01501 #endif
01502                 }
01503                 
01504         return iterateVarBoundary( nIdx+1, nUpper, aArray );
01505 #if 0
01506         return false;
01507 #endif
01508 }
01509 
01510 bool BoundedRevisedSimplexImpl::isSolutionFeasible( const Matrix& mxX ) const
01511 {
01512         OSL_ASSERT( m_mxC.cols() == mxX.rows() );
01513         
01514         for ( size_t i = 0; i < mxX.rows(); ++i )
01515         {
01516                 double fVal = mxX( i, 0 );
01517                 if ( ( m_pModel->isVarBounded( i, BOUND_LOWER ) && 
01518                            fVal < m_pModel->getVarBound( i, BOUND_LOWER ) ) ||
01519                          ( m_pModel->isVarBounded( i, BOUND_UPPER ) &&
01520                            fVal > m_pModel->getVarBound( i, BOUND_UPPER ) ) )
01521                         return false;
01522         }
01523 
01524         if ( m_mxA*mxX != m_mxB )
01525                 return false;
01526 
01527         return true;
01528 }
01529 
01530 const Matrix BoundedRevisedSimplexImpl::solvePriceVector( 
01531                 const SizeTypeContainer& aBasicVarId,
01532                 const Matrix& mxAInv, const Matrix& mxC ) const
01533 {
01534         Matrix c;
01535         SizeTypeContainer::const_iterator itr;
01536         SizeTypeContainer::const_iterator itrBeg = aBasicVarId.begin();
01537         SizeTypeContainer::const_iterator itrEnd = aBasicVarId.end();
01538         for ( itr = itrBeg; itr != itrEnd; ++itr )
01539         {
01540                 int idx = distance( itrBeg, itr );
01541                 c( 0, idx ) = mxC( 0, *itr );
01542         }
01543         return c*mxAInv;
01544 }
01545 
01546 
01547 //---------------------------------------------------------------------------
01548 // BoundedRevisedSimplex
01549 
01550 BoundedRevisedSimplex::BoundedRevisedSimplex() : BaseAlgorithm(),
01551         m_pImpl( new BoundedRevisedSimplexImpl( this ) )
01552 {
01553 }
01554 
01555 BoundedRevisedSimplex::~BoundedRevisedSimplex() throw()
01556 {
01557 }
01558 
01559 void BoundedRevisedSimplex::solve()
01560 {
01561         m_pImpl->solve();
01562 }
01563 
01564 
01565 }}}}

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