# HG changeset patch # User deba # Date 1207670488 0 # Node ID 852361980706707839751e069d33fb01221c5056 # Parent e4ec01f1a4cd4cde826a68411c4a2f32061bfc6a Bug fixes in LP solvers - the copyLp is clarified - newLp and copyLp gives back pointers - cplex gives back empty string for variables without name - cplex row and column retrieval - added macro for soplex diff -r e4ec01f1a4cd -r 852361980706 lemon/config.h.in --- a/lemon/config.h.in Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/config.h.in Tue Apr 08 16:01:28 2008 +0000 @@ -3,3 +3,6 @@ /* Define to 1 if you have GLPK. */ #undef HAVE_GLPK + +/* Define to 1 if you have SOPLEX. */ +#undef HAVE_SOPLEX diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_base.h --- a/lemon/lp_base.h Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_base.h Tue Apr 08 16:01:28 2008 +0000 @@ -371,25 +371,6 @@ return *this; } - //std::ostream & - void prettyPrint(std::ostream &os) { - //std::fmtflags os.flags(); - //os.setf(std::ios::showpos); - Base::iterator j=Base::begin(); - if (j!=Base::end()) - os<second<<"*x["<first)<<"]"; - ++j; - for (; j!=Base::end(); ++j){ - if (j->second>=0) - os<<"+"; - os<second<<"*x["<first)<<"]"; - } - //Nem valami korrekt, de nem talaltam meg, hogy kell - //os.unsetf(std::ios::showpos); - - //return os; - } - }; ///Linear constraint @@ -481,19 +462,6 @@ return isFinite(_ub); } - void prettyPrint(std::ostream &os) { - if (_lb==-LpSolverBase::INF||isNaN(_lb)) - os<<"-infty<="; - else - os<<_lb<<"<="; - _expr.prettyPrint(os); - if (_ub==LpSolverBase::INF) - os<<"<=infty"; - else - os<<"<="<<_ub; - //return os; - } - }; ///Linear expression of rows @@ -735,15 +703,33 @@ typedef MappedOutputIterator ColIterator; //Abstract virtual functions - virtual LpSolverBase &_newLp() = 0; - virtual LpSolverBase &_copyLp(){ - ///\todo This should be implemented here, too, when we have - ///problem retrieving routines. It can be overriden. + virtual LpSolverBase* _newLp() = 0; + virtual LpSolverBase* _copyLp(){ + LpSolverBase* newlp = _newLp(); - //Starting: - LpSolverBase & newlp(_newLp()); + std::map ref; + for (LpSolverBase::ColIt it(*this); it != INVALID; ++it) { + Col ccol = newlp->addCol(); + ref[it] = ccol; + newlp->colName(ccol, colName(it)); + newlp->colLowerBound(ccol, colLowerBound(it)); + newlp->colUpperBound(ccol, colUpperBound(it)); + } + + for (LpSolverBase::RowIt it(*this); it != INVALID; ++it) { + Expr e = row(it), ce; + for (Expr::iterator jt = e.begin(); jt != e.end(); ++jt) { + ce[ref[jt->first]] = jt->second; + } + ce += e.constComp(); + Row r = newlp->addRow(ce); + + double lower, upper; + getRowBounds(it, lower, upper); + newlp->rowBounds(r, lower, upper); + } + return newlp; - //return *(LpSolverBase*)0; }; virtual int _addCol() = 0; @@ -804,9 +790,9 @@ virtual ~LpSolverBase() {} ///Creates a new LP problem - LpSolverBase &newLp() {return _newLp();} + LpSolverBase* newLp() {return _newLp();} ///Makes a copy of the LP problem - LpSolverBase ©Lp() {return _copyLp();} + LpSolverBase* copyLp() {return _copyLp();} ///\name Build up and modify the LP diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_cplex.cc --- a/lemon/lp_cplex.cc Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_cplex.cc Tue Apr 08 16:01:28 2008 +0000 @@ -17,47 +17,47 @@ */ #include +#include #include ///\file ///\brief Implementation of the LEMON-CPLEX lp solver interface. namespace lemon { - LpCplex::LpCplex() : LpSolverBase() { + LpCplex::LpCplex() { // env = CPXopenCPLEXdevelop(&status); env = CPXopenCPLEX(&status); lp = CPXcreateprob(env, &status, "LP problem"); } + + LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() { + env = CPXopenCPLEX(&status); + lp = CPXcloneprob(env, cplex.lp, &status); + rows = cplex.rows; + cols = cplex.cols; + } LpCplex::~LpCplex() { - CPXfreeprob(env,&lp); - CPXcloseCPLEX(&env); + CPXfreeprob(env,&lp); + CPXcloseCPLEX(&env); } - LpSolverBase &LpCplex::_newLp() + LpSolverBase* LpCplex::_newLp() { //The first approach opens a new environment - LpCplex* newlp=new LpCplex(); - return *newlp; + return new LpCplex(); } - LpSolverBase &LpCplex::_copyLp() { - ///\bug FixID data is not copied! - //The first approach opens a new environment - LpCplex* newlp=new LpCplex(); - //The routine CPXcloneprob can be used to create a new CPLEX problem - //object and copy all the problem data from an existing problem - //object to it. Solution and starting information is not copied. - newlp->lp = CPXcloneprob(env, lp, &status); - return *newlp; + LpSolverBase* LpCplex::_copyLp() { + return new LpCplex(*this); } int LpCplex::_addCol() { int i = CPXgetnumcols(env, lp); Value lb[1],ub[1]; - lb[0]=-INF;//-CPX_INFBOUND; - ub[0]=INF;//CPX_INFBOUND; + lb[0]=-INF; + ub[0]=INF; status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL); return i; } @@ -89,7 +89,11 @@ ///\bug Untested int storespace; CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); - + if (storespace == 0) { + name.clear(); + return; + } + storespace *= -1; std::vector buf(storespace); char *names[1]; @@ -136,6 +140,21 @@ } void LpCplex::_getRowCoeffs(int i, RowIterator b) const { + int tmp1, tmp2, tmp3, length; + CPXgetrows(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); + + length = -length; + std::vector indices(length); + std::vector values(length); + + CPXgetrows(env, lp, &tmp1, &tmp2, &indices[0], &values[0], + length, &tmp3, i, i); + + for (int i = 0; i < length; ++i) { + *b = std::make_pair(indices[i], values[i]); + ++b; + } + /// \todo implement } @@ -156,7 +175,22 @@ } void LpCplex::_getColCoeffs(int i, ColIterator b) const { - /// \todo implement + + int tmp1, tmp2, tmp3, length; + CPXgetcols(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); + + length = -length; + std::vector indices(length); + std::vector values(length); + + CPXgetcols(env, lp, &tmp1, &tmp2, &indices[0], &values[0], + length, &tmp3, i, i); + + for (int i = 0; i < length; ++i) { + *b = std::make_pair(indices[i], values[i]); + ++b; + } + } void LpCplex::_setCoeff(int row, int col, Value value) @@ -187,6 +221,7 @@ { LpCplex::Value x; CPXgetlb (env, lp, &x, i, i); + if (x <= -CPX_INFBOUND) x = -INF; return x; } @@ -205,6 +240,7 @@ { LpCplex::Value x; CPXgetub (env, lp, &x, i, i); + if (x >= CPX_INFBOUND) x = INF; return x; } @@ -469,8 +505,8 @@ // Default: 0 // Description: Method for linear optimization. // Determines which algorithm is used when CPXlpopt() (or "optimize" in the Interactive Optimizer) is called. Currently the behavior of the "Automatic" setting is that CPLEX simply invokes the dual simplex method, but this capability may be expanded in the future so that CPLEX chooses the method based on problem characteristics +#if CPX_VERSION < 900 void statusSwitch(CPXENVptr env,int& stat){ -#if CPX_VERSION < 900 int lpmethod; CPXgetintparam (env,CPX_PARAM_LPMETHOD,&lpmethod); if (lpmethod==2){ @@ -482,8 +518,10 @@ stat=CPX_UNBOUNDED; } } + } +#else + void statusSwitch(CPXENVptr,int&){} #endif - } LpCplex::SolutionStatus LpCplex::_getPrimalStatus() const { diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_cplex.h --- a/lemon/lp_cplex.h Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_cplex.h Tue Apr 08 16:01:28 2008 +0000 @@ -49,11 +49,13 @@ /// \e LpCplex(); /// \e + LpCplex(const LpCplex&); + /// \e ~LpCplex(); protected: - virtual LpSolverBase &_newLp(); - virtual LpSolverBase &_copyLp(); + virtual LpSolverBase* _newLp(); + virtual LpSolverBase* _copyLp(); virtual int _addCol(); @@ -100,6 +102,11 @@ virtual bool _isMax() const; + public: + + CPXENVptr cplexEnv() { return env; } + CPXLPptr cplexLp() { return lp; } + }; } //END OF NAMESPACE LEMON diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_glpk.cc --- a/lemon/lp_glpk.cc Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_glpk.cc Tue Apr 08 16:01:28 2008 +0000 @@ -89,6 +89,8 @@ LEMON_glp(get_col_lb)(glp.lp,i), LEMON_glp(get_col_ub)(glp.lp,i)); } + rows = glp.rows; + cols = glp.cols; } LpGlpk::~LpGlpk() { @@ -105,18 +107,18 @@ ///\e - LpSolverBase &LpGlpk::_newLp() + LpSolverBase* LpGlpk::_newLp() { - LpGlpk* newlp=new LpGlpk; - return *newlp; + LpGlpk* newlp = new LpGlpk; + return newlp; } ///\e - LpSolverBase &LpGlpk::_copyLp() + LpSolverBase* LpGlpk::_copyLp() { - LpGlpk* newlp=new LpGlpk(*this); - return *newlp; + LpGlpk *newlp = new LpGlpk(*this); + return newlp; } int LpGlpk::_addRow() { diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_glpk.h --- a/lemon/lp_glpk.h Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_glpk.h Tue Apr 08 16:01:28 2008 +0000 @@ -49,8 +49,8 @@ ~LpGlpk(); protected: - virtual LpSolverBase &_newLp(); - virtual LpSolverBase &_copyLp(); + virtual LpSolverBase* _newLp(); + virtual LpSolverBase* _copyLp(); virtual int _addCol(); virtual int _addRow(); @@ -120,6 +120,12 @@ ///Pointer to the underlying GLPK data structure. LPX *lpx() {return lp;} + + ///Returns the constraint identifier understood by GLPK. + int lpxRow(Row r) { return _lpId(r); } + + ///Returns the variable identifier understood by GLPK. + int lpxCol(Col c) { return _lpId(c); } }; } //END OF NAMESPACE LEMON diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_skeleton.cc --- a/lemon/lp_skeleton.cc Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_skeleton.cc Tue Apr 08 16:01:28 2008 +0000 @@ -22,16 +22,16 @@ ///\brief A skeleton file to implement LP solver interfaces namespace lemon { - LpSolverBase &LpSkeleton::_newLp() + LpSolverBase* LpSkeleton::_newLp() { LpSolverBase *tmp=0; - return *tmp; + return tmp; } - LpSolverBase &LpSkeleton::_copyLp() + LpSolverBase* LpSkeleton::_copyLp() { LpSolverBase *tmp=0; - return *tmp; + return tmp; } int LpSkeleton::_addCol() diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_skeleton.h --- a/lemon/lp_skeleton.h Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_skeleton.h Tue Apr 08 16:01:28 2008 +0000 @@ -32,9 +32,9 @@ protected: ///\e - virtual LpSolverBase &_newLp(); + virtual LpSolverBase* _newLp(); ///\e - virtual LpSolverBase &_copyLp(); + virtual LpSolverBase* _copyLp(); /// \e virtual int _addCol(); /// \e diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_soplex.cc --- a/lemon/lp_soplex.cc Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_soplex.cc Tue Apr 08 16:01:28 2008 +0000 @@ -36,16 +36,33 @@ LpSoplex::~LpSoplex() { delete soplex; } + + LpSoplex::LpSoplex(const LpSoplex& lp) : LpSolverBase() { + rows = lp.rows; + rows.setIdHandler(relocateIdHandler); + + cols = lp.cols; + cols.setIdHandler(relocateIdHandler); + + soplex = new soplex::SoPlex; + (*static_cast(soplex)) = *(lp.soplex); + + colNames = lp.colNames; + invColNames = lp.invColNames; + + primal_value = lp.primal_value; + dual_value = lp.dual_value; + + } - LpSolverBase &LpSoplex::_newLp() { + LpSolverBase* LpSoplex::_newLp() { LpSoplex* newlp = new LpSoplex(); - return *newlp; + return newlp; } - LpSolverBase &LpSoplex::_copyLp() { - LpSoplex* newlp = new LpSoplex(); - (*static_cast(newlp->soplex)) = *soplex; - return *newlp; + LpSolverBase* LpSoplex::_copyLp() { + LpSoplex* newlp = new LpSoplex(*this); + return newlp; } int LpSoplex::_addCol() { diff -r e4ec01f1a4cd -r 852361980706 lemon/lp_soplex.h --- a/lemon/lp_soplex.h Tue Apr 08 15:16:16 2008 +0000 +++ b/lemon/lp_soplex.h Tue Apr 08 16:01:28 2008 +0000 @@ -66,12 +66,14 @@ /// \e LpSoplex(); /// \e + LpSoplex(const LpSoplex&); + /// \e ~LpSoplex(); protected: - virtual LpSolverBase &_newLp(); - virtual LpSolverBase &_copyLp(); + virtual LpSolverBase* _newLp(); + virtual LpSolverBase* _copyLp(); virtual int _addCol(); virtual int _addRow(); diff -r e4ec01f1a4cd -r 852361980706 test/lp_test.cc --- a/test/lp_test.cc Tue Apr 08 15:16:16 2008 +0000 +++ b/test/lp_test.cc Tue Apr 08 16:01:28 2008 +0000 @@ -20,6 +20,7 @@ #include #include "test_tools.h" #include +#include #ifdef HAVE_CONFIG_H #include @@ -216,7 +217,8 @@ { LP::DualExpr e,f,g; - LP::Row p1,p2,p3,p4,p5; + LP::Row p1 = INVALID, p2 = INVALID, p3 = INVALID, + p4 = INVALID, p5 = INVALID; e[p1]=2; e[p1]+=2; @@ -295,7 +297,6 @@ lp.max(); - //Testing the problem retrieving routines check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!"); check(lp.isMax(),"This is a maximization!"); @@ -307,7 +308,39 @@ lp.getRowBounds(upright,lb,ub); check( lb==-LpSolverBase::INF,"The lower bound for the first row should be -infty."); check( ub==1,"The upper bound for the first row should be 1."); + LpSolverBase::Expr e = lp.row(upright); + check( e.size() == 2, "The row retrieval gives back wrong expression."); + check( e[x1] == 1, "The first coefficient should 1."); + check( e[x2] == 1, "The second coefficient should 1."); + LpSolverBase::DualExpr de = lp.col(x1); + check( de.size() == 4, "The col retrieval gives back wrong expression."); + check( de[upright] == 1, "The first coefficient should 1."); + + LpSolverBase* clp = lp.copyLp(); + + //Testing the problem retrieving routines + check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!"); + check(clp->isMax(),"This is a maximization!"); + check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!"); + // std::cout<colLowerBound(x1)==0,"The lower bound for variable x1 should be 0."); + std::cerr << clp->colUpperBound(x1) << std::endl; + check( clp->colUpperBound(x1)==LpSolverBase::INF,"The upper bound for variable x1 should be infty."); + + clp->getRowBounds(upright,lb,ub); + check( lb==-LpSolverBase::INF,"The lower bound for the first row should be -infty."); + check( ub==1,"The upper bound for the first row should be 1."); + e = clp->row(upright); + check( e.size() == 2, "The row retrieval gives back wrong expression."); + check( e[x1] == 1, "The first coefficient should 1."); + check( e[x2] == 1, "The second coefficient should 1."); + + de = clp->col(x1); + check( de.size() == 4, "The col retrieval gives back wrong expression."); + check( de[upright] == 1, "The first coefficient should 1."); + + delete clp; //Maximization of x1+x2 //over the triangle with vertices (0,0) (0,1) (1,0) @@ -338,6 +371,7 @@ lp.min(); check(lp.primalStatus()==LpSolverBase::UNDEFINED,"Primalstatus should be UNDEFINED"); + // lp.solve(); // if (lp.primalStatus()==LpSolverBase::OPTIMAL){ // std::cout<< "Z = "<