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 <algorithm>
00030 #include <exception>
00031
00032 #include "lpbuilder.hxx"
00033 #include "tool/global.hxx"
00034 #include "unoglobal.hxx"
00035 #include "type.hxx"
00036 #include "numeric/type.hxx"
00037 #include "numeric/lpmodel.hxx"
00038 #include "numeric/matrix.hxx"
00039
00040 using namespace ::com::sun::star;
00041 using com::sun::star::table::CellAddress;
00042 using scsolver::numeric::Matrix;
00043 using ::std::vector;
00044 using ::std::cout;
00045 using ::std::endl;
00046 using ::std::distance;
00047
00048 namespace scsolver {
00049
00050 class NoMatchingElementsFound : public ::std::exception {};
00051 class LogicError : public ::std::exception
00052 {
00053 public:
00054 virtual const char* what() const throw()
00055 {
00056 return "Logic Error";
00057 }
00058 };
00059
00060
00061
00062
00063 bool operator==( const CellAddress& lhs, const CellAddress& rhs )
00064 {
00065 if ( lhs.Sheet != rhs.Sheet || lhs.Column != rhs.Column || lhs.Row != rhs.Row )
00066 return false;
00067 return true;
00068 }
00069
00070 bool operator!=( const CellAddress& lhs, const CellAddress& rhs )
00071 {
00072 return !( lhs == rhs );
00073 }
00074
00075 struct DecisionVar
00076 {
00077 CellAddress Address;
00078 double Cost;
00079 };
00080
00083 struct CellAttr
00084 {
00085 CellAddress Address;
00086 rtl::OUString Formula;
00087 };
00088
00089
00090
00091
00092
00093 ConstraintAddress::ConstraintAddress() :
00094 m_bIsLHSNumber(false),
00095 m_bIsRHSNumber(false),
00096 m_fLHSValue(0.0),
00097 m_fRHSValue(0.0)
00098 {
00099 }
00100
00101 ConstraintAddress::ConstraintAddress( const ConstraintAddress& aOther ) :
00102 Left( aOther.Left ), Right( aOther.Right ), Equal( aOther.Equal ),
00103 m_bIsLHSNumber( aOther.m_bIsLHSNumber ), m_bIsRHSNumber( aOther.m_bIsRHSNumber ),
00104 m_fLHSValue( aOther.m_fLHSValue ), m_fRHSValue( aOther.m_fRHSValue )
00105 {
00106 }
00107
00108 ConstraintAddress::~ConstraintAddress() throw()
00109 {
00110 }
00111
00112 bool ConstraintAddress::equals( const ConstraintAddress& aOther ) const
00113 {
00114 if (m_bIsLHSNumber)
00115 {
00116 if (!aOther.m_bIsLHSNumber || aOther.m_fLHSValue != m_fLHSValue)
00117 return false;
00118 }
00119 else
00120 {
00121
00122 if (aOther.m_bIsLHSNumber || aOther.Left.Sheet != Left.Sheet ||
00123 aOther.Left.Column != Left.Column || aOther.Left.Row != Left.Row)
00124 return false;
00125 }
00126
00127 if (m_bIsRHSNumber)
00128 {
00129 if (!aOther.m_bIsRHSNumber || aOther.m_fRHSValue != m_fRHSValue)
00130 return false;
00131 }
00132 else
00133 {
00134
00135 if (aOther.m_bIsRHSNumber || aOther.Right.Sheet != Right.Sheet ||
00136 aOther.Right.Column != Right.Column || aOther.Right.Row != Right.Row)
00137 return false;
00138 }
00139 return true;
00140 }
00141
00142 bool ConstraintAddress::operator==( const ConstraintAddress& aOther ) const
00143 {
00144 return equals( aOther );
00145 }
00146
00147 table::CellAddress ConstraintAddress::getLeftCellAddr() const
00148 {
00149 return Left;
00150 }
00151
00152 void ConstraintAddress::setLeftCellAddr( const table::CellAddress& addr )
00153 {
00154 Left = addr;
00155 m_bIsLHSNumber = false;
00156 }
00157
00158 table::CellAddress ConstraintAddress::getRightCellAddr() const
00159 {
00160 return Right;
00161 }
00162
00163 void ConstraintAddress::setRightCellAddr( const table::CellAddress& addr )
00164 {
00165 Right = addr;
00166 m_bIsRHSNumber = false;
00167 }
00168
00169 double ConstraintAddress::getLeftCellValue() const
00170 {
00171 return m_fLHSValue;
00172 }
00173
00174 double ConstraintAddress::getRightCellValue() const
00175 {
00176 return m_fRHSValue;
00177 }
00178
00179 void ConstraintAddress::setLeftCellValue( double value )
00180 {
00181 m_fLHSValue = value;
00182 m_bIsLHSNumber = true;
00183 }
00184
00185 void ConstraintAddress::setRightCellValue( double value )
00186 {
00187 m_fRHSValue = value;
00188 m_bIsRHSNumber = true;
00189 }
00190
00191 bool ConstraintAddress::isLeftCellNumeric() const
00192 {
00193 return m_bIsLHSNumber;
00194 }
00195
00196 bool ConstraintAddress::isRightCellNumeric() const
00197 {
00198 return m_bIsRHSNumber;
00199 }
00200
00201 numeric::EqualityType ConstraintAddress::getEquality() const
00202 {
00203 return Equal;
00204 }
00205
00206 void ConstraintAddress::setEquality( numeric::EqualityType eq )
00207 {
00208 Equal = eq;
00209 }
00210
00211
00212
00213
00214
00224 class LpModelBuilderImpl
00225 {
00226 public:
00227 LpModelBuilderImpl();
00228 ~LpModelBuilderImpl() throw();
00229
00230 numeric::lp::Model getModel();
00231
00232 numeric::GoalType getGoal() const;
00233 void setGoal( numeric::GoalType );
00234
00235
00236 CellAddress getObjectiveFormulaAddress() const;
00237 void setObjectiveFormulaAddress( const table::CellAddress& );
00238
00239
00240 sal_uInt32 getConstraintId( const ConstraintAddress& );
00241 void setConstraintAddress( const ConstraintAddress& );
00242 std::vector< ConstraintAddress > getAllConstraintAddresses() const { return m_cnConstraintAddress; }
00243 void setConstraintMatrixSize( size_t, size_t );
00244 void setConstraintCoefficient( const CellAddress&, const ConstraintAddress&, double, double );
00245 void clearConstraintAddresses() { m_cnConstraintAddress.clear(); }
00246 numeric::EqualityType getConstraintEquality( sal_uInt32 ) const;
00247
00248 sal_uInt32 getDecisionVarId( const CellAddress& );
00249 void setDecisionVarAddress( const CellAddress& );
00250 vector< CellAddress > getAllDecisionVarAddresses() const;
00251 void clearDecisionVarAddresses() { m_cnDecisionVars.clear(); }
00252
00253 double getCostVector( const CellAddress& );
00254 void setCostVector( const CellAddress&, double );
00255
00256 const rtl::OUString getTempCellFormula( const CellAddress& ) const;
00257 void setTempCellFormula( const table::CellAddress&, const rtl::OUString& );
00258
00259 void stripConstConstraint();
00260 void stripZeroCostDecisionVar();
00261
00262 private:
00263
00264 numeric::GoalType m_eGoal;
00265
00266
00267 table::CellAddress m_aObjFormulaAddr;
00268 std::vector< DecisionVar > m_cnDecisionVars;
00269 std::vector< ConstraintAddress > m_cnConstraintAddress;
00270
00271
00272 Matrix m_mxConstraint;
00273 Matrix m_mxRHS;
00274
00275
00276
00277 std::vector< CellAttr > m_cnCellAttrs;
00278 };
00279
00280 LpModelBuilderImpl::LpModelBuilderImpl() :
00281 m_eGoal( numeric::GOAL_UNKNOWN ), m_mxConstraint( 0, 0 ), m_mxRHS( 0, 0 )
00282 {
00283 }
00284
00285 LpModelBuilderImpl::~LpModelBuilderImpl() throw()
00286 {
00287 }
00288
00292 numeric::lp::Model LpModelBuilderImpl::getModel()
00293 {
00294
00295
00296
00297 numeric::lp::Model aModel;
00298
00299 vector< DecisionVar >::const_iterator it,
00300 itBeg = m_cnDecisionVars.begin(), itEnd = m_cnDecisionVars.end();
00301 for ( it = itBeg; it != itEnd; ++it )
00302 aModel.setCostVectorElement( distance( itBeg, it ), (*it).Cost );
00303
00304
00305 for ( sal_uInt32 i = 0; i < m_mxConstraint.rows(); ++i )
00306 {
00307 vector<double> aConst;
00308 for ( sal_uInt32 j = 0; j < m_mxConstraint.cols(); ++j )
00309 aConst.push_back( m_mxConstraint( i, j ) );
00310
00311 numeric::EqualityType e = getConstraintEquality( i );
00312 aModel.addConstraint( aConst, e, m_mxRHS( i, 0 ) );
00313 }
00314
00315 aModel.setGoal( getGoal() );
00316 return aModel;
00317 }
00318
00319 numeric::GoalType LpModelBuilderImpl::getGoal() const
00320 {
00321 return m_eGoal;
00322 }
00323
00324 void LpModelBuilderImpl::setGoal( numeric::GoalType e )
00325 {
00326 m_eGoal = e;
00327 }
00328
00329 CellAddress LpModelBuilderImpl::getObjectiveFormulaAddress() const
00330 {
00331 return m_aObjFormulaAddr;
00332 }
00333
00334 void LpModelBuilderImpl::setObjectiveFormulaAddress( const table::CellAddress& aAddr )
00335 {
00336 m_aObjFormulaAddr = aAddr;
00337 }
00338
00339 sal_uInt32 LpModelBuilderImpl::getConstraintId( const ConstraintAddress& aConstAddr )
00340 {
00341 vector< ConstraintAddress >::iterator pos;
00342 for ( pos = m_cnConstraintAddress.begin(); pos != m_cnConstraintAddress.end(); ++pos )
00343 if ( pos->equals( aConstAddr ) )
00344 return distance( m_cnConstraintAddress.begin(), pos );
00345
00346 throw NoMatchingElementsFound();
00347 }
00348
00349 void LpModelBuilderImpl::setConstraintAddress( const ConstraintAddress& aItem )
00350 {
00351 m_cnConstraintAddress.push_back( aItem );
00352 }
00353
00354 void LpModelBuilderImpl::setConstraintMatrixSize( size_t nRow, size_t nCol )
00355 {
00356 m_mxConstraint.resize( nRow, nCol );
00357 }
00358
00359 void LpModelBuilderImpl::setConstraintCoefficient(
00360 const table::CellAddress& aCellAddr, const ConstraintAddress& aConstAddr,
00361 double fCoef, double fRHS )
00362 {
00363
00364
00365 sal_uInt32 nColId = getDecisionVarId( aCellAddr );
00366
00367
00368 sal_uInt32 nRowId = getConstraintId( aConstAddr );
00369
00370
00371 try
00372 {
00373 m_mxConstraint( nRowId, nColId ) = fCoef;
00374 m_mxRHS( nRowId, 0 ) = fRHS;
00375 }
00376 catch (const numeric::BadIndex& )
00377 {
00378 throw RuntimeError(ascii("Error assigning value to a matrix"));
00379 }
00380 }
00381
00385 numeric::EqualityType LpModelBuilderImpl::getConstraintEquality( sal_uInt32 i ) const
00386 {
00387 if ( m_cnConstraintAddress.size() > i )
00388 return m_cnConstraintAddress.at(i).getEquality();
00389 return numeric::EQUAL;
00390 }
00391
00392 sal_uInt32 LpModelBuilderImpl::getDecisionVarId( const table::CellAddress& aAddr )
00393 {
00394 vector< DecisionVar >::const_iterator it,
00395 itBeg = m_cnDecisionVars.begin(), itEnd = m_cnDecisionVars.end();
00396 for ( it = itBeg; it != itEnd; ++it )
00397 {
00398 CellAddress aAddrTmp = it->Address;
00399 if ( aAddrTmp == aAddr )
00400 return distance( itBeg, it );
00401 }
00402
00403 throw NoMatchingElementsFound();
00404 }
00405
00409 void LpModelBuilderImpl::setDecisionVarAddress( const table::CellAddress& aAddr )
00410 {
00411 DecisionVar aVar;
00412 aVar.Address = aAddr;
00413 aVar.Cost = 0.0;
00414 m_cnDecisionVars.push_back( aVar );
00415 }
00416
00417 vector< CellAddress > LpModelBuilderImpl::getAllDecisionVarAddresses() const
00418 {
00419 vector< CellAddress > cnAddrs;
00420 vector< DecisionVar >::const_iterator it,
00421 itBeg = m_cnDecisionVars.begin(), itEnd = m_cnDecisionVars.end();
00422 for ( it = itBeg; it != itEnd; ++it )
00423 cnAddrs.push_back( it->Address );
00424
00425 return cnAddrs;
00426 }
00427
00430 double LpModelBuilderImpl::getCostVector( const table::CellAddress& aAddr )
00431 {
00432 vector< DecisionVar >::const_iterator it,
00433 itBeg = m_cnDecisionVars.begin(), itEnd = m_cnDecisionVars.end();
00434 for ( it = itBeg; it != itEnd; ++it )
00435 {
00436 DecisionVar aVar = *it;
00437 if ( aVar.Address == aAddr )
00438 return aVar.Cost;
00439 }
00440
00441
00442 throw NoMatchingElementsFound();
00443 }
00444
00445 void LpModelBuilderImpl::setCostVector( const table::CellAddress& aAddr, double fCost )
00446 {
00447 vector< DecisionVar >::iterator it,
00448 itBeg = m_cnDecisionVars.begin(), itEnd = m_cnDecisionVars.end();
00449 for ( it = itBeg; it != itEnd; ++it )
00450 {
00451 if ( it->Address == aAddr )
00452 {
00453 it->Cost = fCost;
00454 return;
00455 }
00456 }
00457 OSL_ASSERT( !"LogicError: no matching address found" );
00458 }
00459
00460 const rtl::OUString LpModelBuilderImpl::getTempCellFormula( const table::CellAddress& aAddr ) const
00461 {
00462 vector< CellAttr >::const_iterator it,
00463 itBeg = m_cnCellAttrs.begin(), itEnd = m_cnCellAttrs.end();
00464
00465 for ( it = itBeg; it != itEnd; ++it )
00466 if( it->Address == aAddr )
00467 return it->Formula;
00468
00469 rtl::OUString sEmpty;
00470 return sEmpty;
00471 }
00472
00473 void LpModelBuilderImpl::setTempCellFormula( const table::CellAddress& aAddr, const rtl::OUString& sStr )
00474 {
00475 CellAttr aCellAttr;
00476 aCellAttr.Address = aAddr;
00477 aCellAttr.Formula = sStr;
00478 m_cnCellAttrs.push_back( aCellAttr );
00479 }
00480
00483 void LpModelBuilderImpl::stripConstConstraint()
00484 {
00485 using namespace numeric;
00486
00487 Debug( "stripConstConstraint" );
00488
00489 Matrix mxConstraint( m_mxConstraint ), mxRHS( m_mxRHS );
00490 OSL_ASSERT( mxConstraint.rows() == mxRHS.rows() );
00491 size_t nRowSize = mxConstraint.rows();
00492
00493 vector<size_t> cnRowsToRemove;
00494
00495
00496 for ( size_t i = 0; i < nRowSize; ++i )
00497 if ( mxConstraint.isRowEmpty( i ) )
00498 {
00499 double fRHS = mxRHS( i, 0 );
00500 EqualityType eEq = getConstraintEquality( i );
00501 if ( ( fRHS <= 0 && eEq == GREATER_EQUAL ) ||
00502 ( fRHS >= 0 && eEq == LESS_EQUAL ) ||
00503 ( fRHS == 0.0 && eEq == EQUAL ) )
00504 cnRowsToRemove.push_back( i );
00505 }
00506
00507 cout << "rows to remove: ";
00508 printElements( cnRowsToRemove );
00509
00510 mxConstraint.deleteRows( cnRowsToRemove );
00511 mxRHS.deleteRows( cnRowsToRemove );
00512
00513 m_mxConstraint.swap( mxConstraint );
00514 m_mxRHS.swap( mxRHS );
00515 }
00516
00520 void LpModelBuilderImpl::stripZeroCostDecisionVar()
00521 {
00522 Debug( "stripZeroCostDecisionVar" );
00523
00524 vector< DecisionVar > cnNewVars;
00525 Matrix mxConstraint( m_mxConstraint );
00526 cnNewVars.reserve( m_cnDecisionVars.size() );
00527 vector< size_t > cnColsToRemove;
00528
00529 vector< DecisionVar >::iterator it,
00530 itBeg = m_cnDecisionVars.begin(), itEnd = m_cnDecisionVars.end();
00531 cout << m_cnDecisionVars.size() << endl;
00532 size_t nLastRow = mxConstraint.rows();
00533 for ( it = itBeg; it != itEnd; ++it )
00534 {
00535 if ( it->Cost )
00536 cnNewVars.push_back( *it );
00537 else
00538 {
00539 size_t nCol = distance( itBeg, it );
00540 if ( mxConstraint.isColumnEmpty( nCol ) )
00541 cnColsToRemove.push_back( nCol );
00542 else
00543 cnNewVars.push_back( *it );
00544 }
00545 }
00546
00547 printElements( cnColsToRemove );
00548 cout << "mxConstraint:" << endl;
00549 mxConstraint.print( 0 );
00550
00551 cout << "(" << nLastRow << ", " << mxConstraint.cols() << ")" << endl;
00552
00553 mxConstraint.deleteColumns( cnColsToRemove );
00554 mxConstraint.print( 0 );
00555 swap( cnNewVars, m_cnDecisionVars );
00556 m_mxConstraint.swap( mxConstraint );
00557 }
00558
00559
00560
00561
00562 LpModelBuilder::LpModelBuilder() : m_pImpl( new LpModelBuilderImpl() )
00563 {
00564 }
00565
00566 LpModelBuilder::~LpModelBuilder()
00567 {
00568 }
00569
00570 numeric::lp::Model LpModelBuilder::getModel()
00571 {
00572 return m_pImpl->getModel();
00573 }
00574
00575 numeric::GoalType LpModelBuilder::getGoal() const
00576 {
00577 return m_pImpl->getGoal();
00578 }
00579
00580 void LpModelBuilder::setGoal( numeric::GoalType e )
00581 {
00582 m_pImpl->setGoal( e );
00583 }
00584
00585 const CellAddress LpModelBuilder::getObjectiveFormulaAddress() const
00586 {
00587 return m_pImpl->getObjectiveFormulaAddress();
00588 }
00589
00590 void LpModelBuilder::setObjectiveFormulaAddress( const table::CellAddress& aAddr )
00591 {
00592 m_pImpl->setObjectiveFormulaAddress( aAddr );
00593 }
00594
00595 double LpModelBuilder::getCostVector( const table::CellAddress& aAddr )
00596 {
00597 return m_pImpl->getCostVector( aAddr );
00598 }
00599
00600 void LpModelBuilder::setCostVector( const table::CellAddress& aAddr, double fCost )
00601 {
00602 m_pImpl->setCostVector( aAddr, fCost );
00603 }
00604
00605 void LpModelBuilder::clearConstraintAddresses()
00606 {
00607 m_pImpl->clearConstraintAddresses();
00608 }
00609
00610 void LpModelBuilder::setConstraintAddress( const ConstraintAddress& aItem )
00611 {
00612 m_pImpl->setConstraintAddress( aItem );
00613 }
00614
00615 vector< ConstraintAddress > LpModelBuilder::getAllConstraintAddresses() const
00616 {
00617 return m_pImpl->getAllConstraintAddresses();
00618 }
00619
00620 void LpModelBuilder::setConstraintMatrixSize( size_t nRow, size_t nCol )
00621 {
00622 m_pImpl->setConstraintMatrixSize( nRow, nCol );
00623 }
00624
00625 void LpModelBuilder::setConstraintCoefficient(
00626 const CellAddress& aCellAddr, const ConstraintAddress& aConstAddr,
00627 double fCoef, double fRHS )
00628 {
00629 m_pImpl->setConstraintCoefficient( aCellAddr, aConstAddr, fCoef, fRHS );
00630 }
00631
00632 void LpModelBuilder::setDecisionVarAddress( const table::CellAddress& aAddr )
00633 {
00634 m_pImpl->setDecisionVarAddress( aAddr );
00635 }
00636
00637 vector< CellAddress > LpModelBuilder::getAllDecisionVarAddresses() const
00638 {
00639 return m_pImpl->getAllDecisionVarAddresses();
00640 }
00641
00642 void LpModelBuilder::clearDecisionVarAddresses()
00643 {
00644 return m_pImpl->clearDecisionVarAddresses();
00645 }
00646
00647 const rtl::OUString LpModelBuilder::getTempCellFormula( const table::CellAddress& aAddr ) const
00648 {
00649 return m_pImpl->getTempCellFormula( aAddr );
00650 }
00651
00652 void LpModelBuilder::setTempCellFormula( const table::CellAddress& aAddr, const rtl::OUString& sStr )
00653 {
00654 m_pImpl->setTempCellFormula( aAddr, sStr );
00655 }
00656
00657
00658 }
00659