source/ui/lpbuilder.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 <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 // Local entities
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 // ConstraintAddress
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                 // LHS is not a number.  Compare the cell addresses.
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                 // RHS is not a number.  Compare the cell addresses.
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 // LpModelBuilderImpl
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         // Objective Formula
00236         CellAddress getObjectiveFormulaAddress() const;
00237         void setObjectiveFormulaAddress( const table::CellAddress& );
00238 
00239         // Constraints  
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         // Objective Formula & Decision Variables
00267         table::CellAddress m_aObjFormulaAddr;
00268         std::vector< DecisionVar > m_cnDecisionVars;
00269         std::vector< ConstraintAddress > m_cnConstraintAddress;
00270 
00271         // Constraint Matrix
00272         Matrix m_mxConstraint;
00273         Matrix m_mxRHS;
00274 
00275         // Temporary Cell Formula Container used for recovery of cell values 
00276         // after modifying the cell.
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         //stripZeroCostDecisionVar();
00295         //stripConstConstraint();
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         // Constraint matrix, equality, and RHS
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         // First, get the column ID of this coefficient from the address of a 
00364         // decision variable (aCellAddr).
00365         sal_uInt32 nColId = getDecisionVarId( aCellAddr );
00366         
00367         // Next, get this coefficient's row ID from ConstraintAddress.
00368         sal_uInt32 nRowId = getConstraintId( aConstAddr );
00369         
00370 //      cout << "(" << nRowId << ", " << nColId << ") = " << fCoef << "  RHS = " << fRHS << endl;
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         // This should NOT be reached!
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         // Scan the constraint matrix to find empty rows.
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 // LpModelBuilder
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 

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