diff -r d8475431bbbb -r 8e85e6bbefdf lemon/lp_base.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/lp_base.h Mon May 23 04:48:14 2005 +0000 @@ -0,0 +1,907 @@ +/* -*- C++ -*- + * lemon/lp_base.h - Part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_LP_BASE_H +#define LEMON_LP_BASE_H + +#include +#include +#include +#include + +#include +#include +#include + +//#include"lin_expr.h" + +///\file +///\brief The interface of the LP solver interface. +///\ingroup gen_opt_group +namespace lemon { + + ///Internal data structure to convert floating id's to fix one's + + ///\todo This might be implemented to be also usable in other places. + class _FixId + { + std::vector index; + std::vector cross; + int first_free; + public: + _FixId() : first_free(-1) {}; + ///Convert a floating id to a fix one + + ///\param n is a floating id + ///\return the corresponding fix id + int fixId(int n) {return cross[n];} + ///Convert a fix id to a floating one + + ///\param n is a fix id + ///\return the corresponding floating id + int floatingId(int n) { return index[n];} + ///Add a new floating id. + + ///\param n is a floating id + ///\return the fix id of the new value + ///\todo Multiple additions should also be handled. + int insert(int n) + { + if(n>=int(cross.size())) { + cross.resize(n+1); + if(first_free==-1) { + cross[n]=index.size(); + index.push_back(n); + } + else { + cross[n]=first_free; + int next=index[first_free]; + index[first_free]=n; + first_free=next; + } + return cross[n]; + } + ///\todo Create an own exception type. + else throw LogicError(); //floatingId-s must form a continuous range; + } + ///Remove a fix id. + + ///\param n is a fix id + /// + void erase(int n) + { + int fl=index[n]; + index[n]=first_free; + first_free=n; + for(int i=fl+1;i, so for expamle + ///if \c e is an Expr and \c v and \c w are of type \ref Col, then you can + ///read and modify the coefficients like + ///these. + ///\code + ///e[v]=5; + ///e[v]+=12; + ///e.erase(v); + ///\endcode + ///or you can also iterate through its elements. + ///\code + ///double s=0; + ///for(LpSolverBase::Expr::iterator i=e.begin();i!=e.end();++i) + /// s+=i->second; + ///\endcode + ///(This code computes the sum of all coefficients). + ///- Numbers (double's) + ///and variables (\ref Col "Col"s) directly convert to an + ///\ref Expr and the usual linear operations are defined so + ///\code + ///v+w + ///2*v-3.12*(v-w/2)+2 + ///v*2.1+(3*v+(v*12+w+6)*3)/2 + ///\endcode + ///are valid \ref Expr "Expr"essions. + ///The usual assignment operations are also defined. + ///\code + ///e=v+w; + ///e+=2*v-3.12*(v-w/2)+2; + ///e*=3.4; + ///e/=5; + ///\endcode + ///- The constant member can be set and read by \ref constComp() + ///\code + ///e.constComp()=12; + ///double c=e.constComp(); + ///\endcode + /// + ///\note \ref clear() not only sets all coefficients to 0 but also + ///clears the constant components. + /// + ///\sa Constr + /// + class Expr : public std::map + { + public: + typedef LpSolverBase::Col Key; + typedef LpSolverBase::Value Value; + + protected: + typedef std::map Base; + + Value const_comp; + public: + typedef True IsLinExpression; + ///\e + Expr() : Base(), const_comp(0) { } + ///\e + Expr(const Key &v) : const_comp(0) { + Base::insert(std::make_pair(v, 1)); + } + ///\e + Expr(const Value &v) : const_comp(v) {} + ///\e + void set(const Key &v,const Value &c) { + Base::insert(std::make_pair(v, c)); + } + ///\e + Value &constComp() { return const_comp; } + ///\e + const Value &constComp() const { return const_comp; } + + ///Removes the components with zero coefficient. + void simplify() { + for (Base::iterator i=Base::begin(); i!=Base::end();) { + Base::iterator j=i; + ++j; + if ((*i).second==0) Base::erase(i); + j=i; + } + } + + ///Sets all coefficients and the constant component to 0. + void clear() { + Base::clear(); + const_comp=0; + } + + ///\e + Expr &operator+=(const Expr &e) { + for (Base::const_iterator j=e.begin(); j!=e.end(); ++j) + (*this)[j->first]+=j->second; + ///\todo it might be speeded up using "hints" + const_comp+=e.const_comp; + return *this; + } + ///\e + Expr &operator-=(const Expr &e) { + for (Base::const_iterator j=e.begin(); j!=e.end(); ++j) + (*this)[j->first]-=j->second; + const_comp-=e.const_comp; + return *this; + } + ///\e + Expr &operator*=(const Value &c) { + for (Base::iterator j=Base::begin(); j!=Base::end(); ++j) + j->second*=c; + const_comp*=c; + return *this; + } + ///\e + Expr &operator/=(const Value &c) { + for (Base::iterator j=Base::begin(); j!=Base::end(); ++j) + j->second/=c; + const_comp/=c; + return *this; + } + }; + + ///Linear constraint + + ///This data stucture represents a linear constraint in the LP. + ///Basically it is a linear expression with a lower or an upper bound + ///(or both). These parts of the constraint can be obtained by the member + ///functions \ref expr(), \ref lowerBound() and \ref upperBound(), + ///respectively. + ///There are two ways to construct a constraint. + ///- You can set the linear expression and the bounds directly + /// by the functions above. + ///- The operators \<=, == and \>= + /// are defined between expressions, or even between constraints whenever + /// it makes sense. Therefore if \c e and \c f are linear expressions and + /// \c s and \c t are numbers, then the followings are valid expressions + /// and thus they can be used directly e.g. in \ref addRow() whenever + /// it makes sense. + /// \code + /// e<=s + /// e<=f + /// s<=e<=t + /// e>=t + /// \endcode + ///\warning The validity of a constraint is checked only at run time, so + ///e.g. \ref addRow(x[1]\<=x[2]<=5) will compile, but will throw a + ///\ref LogicError exception. + class Constr + { + public: + typedef LpSolverBase::Expr Expr; + typedef Expr::Key Key; + typedef Expr::Value Value; + +// static const Value INF; +// static const Value NaN; + + protected: + Expr _expr; + Value _lb,_ub; + public: + ///\e + Constr() : _expr(), _lb(NaN), _ub(NaN) {} + ///\e + Constr(Value lb,const Expr &e,Value ub) : + _expr(e), _lb(lb), _ub(ub) {} + ///\e + Constr(const Expr &e,Value ub) : + _expr(e), _lb(NaN), _ub(ub) {} + ///\e + Constr(Value lb,const Expr &e) : + _expr(e), _lb(lb), _ub(NaN) {} + ///\e + Constr(const Expr &e) : + _expr(e), _lb(NaN), _ub(NaN) {} + ///\e + void clear() + { + _expr.clear(); + _lb=_ub=NaN; + } + + ///Reference to the linear expression + Expr &expr() { return _expr; } + ///Cont reference to the linear expression + const Expr &expr() const { return _expr; } + ///Reference to the lower bound. + + ///\return + ///- -\ref INF: the constraint is lower unbounded. + ///- -\ref NaN: lower bound has not been set. + ///- finite number: the lower bound + Value &lowerBound() { return _lb; } + ///The const version of \ref lowerBound() + const Value &lowerBound() const { return _lb; } + ///Reference to the upper bound. + + ///\return + ///- -\ref INF: the constraint is upper unbounded. + ///- -\ref NaN: upper bound has not been set. + ///- finite number: the upper bound + Value &upperBound() { return _ub; } + ///The const version of \ref upperBound() + const Value &upperBound() const { return _ub; } + ///Is the constraint lower bounded? + bool lowerBounded() const { + using namespace std; + return finite(_lb); + } + ///Is the constraint upper bounded? + bool upperBounded() const { + using namespace std; + return finite(_ub); + } + }; + + + protected: + _FixId rows; + _FixId cols; + + //Abstract virtual functions + virtual LpSolverBase &_newLp() = 0; + virtual LpSolverBase &_copyLp() = 0; + + virtual int _addCol() = 0; + virtual int _addRow() = 0; + virtual void _setRowCoeffs(int i, + int length, + int const * indices, + Value const * values ) = 0; + virtual void _setColCoeffs(int i, + int length, + int const * indices, + Value const * values ) = 0; + virtual void _setCoeff(int row, int col, Value value) = 0; + virtual void _setColLowerBound(int i, Value value) = 0; + virtual void _setColUpperBound(int i, Value value) = 0; +// virtual void _setRowLowerBound(int i, Value value) = 0; +// virtual void _setRowUpperBound(int i, Value value) = 0; + virtual void _setRowBounds(int i, Value lower, Value upper) = 0; + virtual void _setObjCoeff(int i, Value obj_coef) = 0; + virtual void _clearObj()=0; +// virtual void _setObj(int length, +// int const * indices, +// Value const * values ) = 0; + virtual SolveExitStatus _solve() = 0; + virtual Value _getPrimal(int i) = 0; + virtual Value _getPrimalValue() = 0; + virtual SolutionStatus _getPrimalStatus() = 0; + virtual void _setMax() = 0; + virtual void _setMin() = 0; + + //Own protected stuff + + //Constant component of the objective function + Value obj_const_comp; + + + + + public: + + ///\e + LpSolverBase() : obj_const_comp(0) {} + + ///\e + virtual ~LpSolverBase() {} + + ///Creates a new LP problem + LpSolverBase &newLp() {return _newLp();} + ///Makes a copy of the LP problem + LpSolverBase ©Lp() {return _copyLp();} + + ///\name Build up and modify of the LP + + ///@{ + + ///Add a new empty column (i.e a new variable) to the LP + Col addCol() { Col c; c.id=cols.insert(_addCol()); return c;} + + ///\brief Adds several new columns + ///(i.e a variables) at once + /// + ///This magic function takes a container as its argument + ///and fills its elements + ///with new columns (i.e. variables) + ///\param t can be + ///- a standard STL compatible iterable container with + ///\ref Col as its \c values_type + ///like + ///\code + ///std::vector + ///std::list + ///\endcode + ///- a standard STL compatible iterable container with + ///\ref Col as its \c mapped_type + ///like + ///\code + ///std::map + ///\endcode + ///- an iterable lemon \ref concept::WriteMap "write map" like + ///\code + ///ListGraph::NodeMap + ///ListGraph::EdgeMap + ///\endcode + ///\return The number of the created column. +#ifdef DOXYGEN + template + int addColSet(T &t) { return 0;} +#else + template + typename enable_if::type + addColSet(T &t,dummy<0> = 0) { + int s=0; + for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addCol();s++;} + return s; + } + template + typename enable_if::type + addColSet(T &t,dummy<1> = 1) { + int s=0; + for(typename T::iterator i=t.begin();i!=t.end();++i) { + i->second=addCol(); + s++; + } + return s; + } + template + typename enable_if::type + addColSet(T &t,dummy<2> = 2) { + ///\bug return addColSet(t.valueSet()); should also work. + int s=0; + for(typename T::ValueSet::iterator i=t.valueSet().begin(); + i!=t.valueSet().end(); + ++i) + { + *i=addCol(); + s++; + } + return s; + } +#endif + + ///Add a new empty row (i.e a new constaint) to the LP + + ///This function adds a new empty row (i.e a new constaint) to the LP. + ///\return The created row + Row addRow() { Row r; r.id=rows.insert(_addRow()); return r;} + + ///Set a row (i.e a constaint) of the LP + + ///\param r is the row to be modified + ///\param l is lower bound (-\ref INF means no bound) + ///\param e is a linear expression (see \ref Expr) + ///\param u is the upper bound (\ref INF means no bound) + ///\bug This is a temportary function. The interface will change to + ///a better one. + ///\todo Option to control whether a constraint with a single variable is + ///added or not. + void setRow(Row r, Value l,const Expr &e, Value u) { + std::vector indices; + std::vector values; + indices.push_back(0); + values.push_back(0); + for(Expr::const_iterator i=e.begin(); i!=e.end(); ++i) + if((*i).second!=0) { ///\bug EPSILON would be necessary here!!! + indices.push_back(cols.floatingId((*i).first.id)); + values.push_back((*i).second); + } + _setRowCoeffs(rows.floatingId(r.id),indices.size()-1, + &indices[0],&values[0]); +// _setRowLowerBound(rows.floatingId(r.id),l-e.constComp()); +// _setRowUpperBound(rows.floatingId(r.id),u-e.constComp()); + _setRowBounds(rows.floatingId(r.id),l-e.constComp(),u-e.constComp()); + } + + ///Set a row (i.e a constaint) of the LP + + ///\param r is the row to be modified + ///\param c is a linear expression (see \ref Constr) + void setRow(Row r, const Constr &c) { + setRow(r, + c.lowerBounded()?c.lowerBound():-INF, + c.expr(), + c.upperBounded()?c.upperBound():INF); + } + + ///Add a new row (i.e a new constaint) to the LP + + ///\param l is the lower bound (-\ref INF means no bound) + ///\param e is a linear expression (see \ref Expr) + ///\param u is the upper bound (\ref INF means no bound) + ///\return The created row. + ///\bug This is a temportary function. The interface will change to + ///a better one. + Row addRow(Value l,const Expr &e, Value u) { + Row r=addRow(); + setRow(r,l,e,u); + return r; + } + + ///Add a new row (i.e a new constaint) to the LP + + ///\param c is a linear expression (see \ref Constr) + ///\return The created row. + Row addRow(const Constr &c) { + Row r=addRow(); + setRow(r,c); + return r; + } + + /// Set the lower bound of a column (i.e a variable) + + /// The upper bound of a variable (column) has to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or -\ref INF. + void colLowerBound(Col c, Value value) { + _setColLowerBound(cols.floatingId(c.id),value); + } + /// Set the upper bound of a column (i.e a variable) + + /// The upper bound of a variable (column) has to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value or \ref INF. + void colUpperBound(Col c, Value value) { + _setColUpperBound(cols.floatingId(c.id),value); + }; + /// Set the lower and the upper bounds of a column (i.e a variable) + + /// The lower and the upper bounds of + /// a variable (column) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value, -\ref INF or \ref INF. + void colBounds(Col c, Value lower, Value upper) { + _setColLowerBound(cols.floatingId(c.id),lower); + _setColUpperBound(cols.floatingId(c.id),upper); + } + +// /// Set the lower bound of a row (i.e a constraint) + +// /// The lower bound of a linear expression (row) has to be given by an +// /// extended number of type Value, i.e. a finite number of type +// /// Value or -\ref INF. +// void rowLowerBound(Row r, Value value) { +// _setRowLowerBound(rows.floatingId(r.id),value); +// }; +// /// Set the upper bound of a row (i.e a constraint) + +// /// The upper bound of a linear expression (row) has to be given by an +// /// extended number of type Value, i.e. a finite number of type +// /// Value or \ref INF. +// void rowUpperBound(Row r, Value value) { +// _setRowUpperBound(rows.floatingId(r.id),value); +// }; + + /// Set the lower and the upper bounds of a row (i.e a constraint) + + /// The lower and the upper bounds of + /// a constraint (row) have to be given by an + /// extended number of type Value, i.e. a finite number of type + /// Value, -\ref INF or \ref INF. + void rowBounds(Row c, Value lower, Value upper) { + _setRowBounds(rows.floatingId(c.id),lower, upper); + // _setRowUpperBound(rows.floatingId(c.id),upper); + } + + ///Set an element of the objective function + void objCoeff(Col c, Value v) {_setObjCoeff(cols.floatingId(c.id),v); }; + ///Set the objective function + + ///\param e is a linear expression of type \ref Expr. + ///\bug The previous objective function is not cleared! + void setObj(Expr e) { + _clearObj(); + for (Expr::iterator i=e.begin(); i!=e.end(); ++i) + objCoeff((*i).first,(*i).second); + obj_const_comp=e.constComp(); + } + + ///Maximize + void max() { _setMax(); } + ///Minimize + void min() { _setMin(); } + + + ///@} + + + ///\name Solve the LP + + ///@{ + + ///\e + SolveExitStatus solve() { return _solve(); } + + ///@} + + ///\name Obtain the solution + + ///@{ + + ///\e + SolutionStatus primalStatus() { + return _getPrimalStatus(); + } + + ///\e + Value primal(Col c) { return _getPrimal(cols.floatingId(c.id)); } + + ///\e + + ///\return + ///- \ref INF or -\ref INF means either infeasibility or unboundedness + /// of the primal problem, depending on whether we minimize or maximize. + ///- \ref NaN if no primal solution is found. + ///- The (finite) objective value if an optimal solution is found. + Value primalValue() { return _getPrimalValue()+obj_const_comp;} + ///@} + + }; + + ///\e + + ///\relates LpSolverBase::Expr + /// + inline LpSolverBase::Expr operator+(const LpSolverBase::Expr &a, + const LpSolverBase::Expr &b) + { + LpSolverBase::Expr tmp(a); + tmp+=b; ///\todo Doesn't STL have some special 'merge' algorithm? + return tmp; + } + ///\e + + ///\relates LpSolverBase::Expr + /// + inline LpSolverBase::Expr operator-(const LpSolverBase::Expr &a, + const LpSolverBase::Expr &b) + { + LpSolverBase::Expr tmp(a); + tmp-=b; ///\todo Doesn't STL have some special 'merge' algorithm? + return tmp; + } + ///\e + + ///\relates LpSolverBase::Expr + /// + inline LpSolverBase::Expr operator*(const LpSolverBase::Expr &a, + const LpSolverBase::Value &b) + { + LpSolverBase::Expr tmp(a); + tmp*=b; ///\todo Doesn't STL have some special 'merge' algorithm? + return tmp; + } + + ///\e + + ///\relates LpSolverBase::Expr + /// + inline LpSolverBase::Expr operator*(const LpSolverBase::Value &a, + const LpSolverBase::Expr &b) + { + LpSolverBase::Expr tmp(b); + tmp*=a; ///\todo Doesn't STL have some special 'merge' algorithm? + return tmp; + } + ///\e + + ///\relates LpSolverBase::Expr + /// + inline LpSolverBase::Expr operator/(const LpSolverBase::Expr &a, + const LpSolverBase::Value &b) + { + LpSolverBase::Expr tmp(a); + tmp/=b; ///\todo Doesn't STL have some special 'merge' algorithm? + return tmp; + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator<=(const LpSolverBase::Expr &e, + const LpSolverBase::Expr &f) + { + return LpSolverBase::Constr(-LpSolverBase::INF,e-f,0); + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator<=(const LpSolverBase::Value &e, + const LpSolverBase::Expr &f) + { + return LpSolverBase::Constr(e,f); + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator<=(const LpSolverBase::Expr &e, + const LpSolverBase::Value &f) + { + return LpSolverBase::Constr(e,f); + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator>=(const LpSolverBase::Expr &e, + const LpSolverBase::Expr &f) + { + return LpSolverBase::Constr(-LpSolverBase::INF,f-e,0); + } + + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator>=(const LpSolverBase::Value &e, + const LpSolverBase::Expr &f) + { + return LpSolverBase::Constr(f,e); + } + + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator>=(const LpSolverBase::Expr &e, + const LpSolverBase::Value &f) + { + return LpSolverBase::Constr(f,e); + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator==(const LpSolverBase::Expr &e, + const LpSolverBase::Expr &f) + { + return LpSolverBase::Constr(0,e-f,0); + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator<=(const LpSolverBase::Value &n, + const LpSolverBase::Constr&c) + { + LpSolverBase::Constr tmp(c); + ///\todo Create an own exception type. + if(!isnan(tmp.lowerBound())) throw LogicError(); + else tmp.lowerBound()=n; + return tmp; + } + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator<=(const LpSolverBase::Constr& c, + const LpSolverBase::Value &n) + { + LpSolverBase::Constr tmp(c); + ///\todo Create an own exception type. + if(!isnan(tmp.upperBound())) throw LogicError(); + else tmp.upperBound()=n; + return tmp; + } + + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator>=(const LpSolverBase::Value &n, + const LpSolverBase::Constr&c) + { + LpSolverBase::Constr tmp(c); + ///\todo Create an own exception type. + if(!isnan(tmp.upperBound())) throw LogicError(); + else tmp.upperBound()=n; + return tmp; + } + ///\e + + ///\relates LpSolverBase::Constr + /// + inline LpSolverBase::Constr operator>=(const LpSolverBase::Constr& c, + const LpSolverBase::Value &n) + { + LpSolverBase::Constr tmp(c); + ///\todo Create an own exception type. + if(!isnan(tmp.lowerBound())) throw LogicError(); + else tmp.lowerBound()=n; + return tmp; + } + + +} //namespace lemon + +#endif //LEMON_LP_BASE_H