// -*- c++ -*- #ifndef LEMON_LP_SOLVER_WRAPPER_H #define LEMON_LP_SOLVER_WRAPPER_H ///\ingroup misc ///\file ///\brief Dijkstra algorithm. // #include #include #include #include #include // #include //#include extern "C" { #include "glpk.h" } #include #include #include #include #include #include //#include #include #include //#include //#include //#include //#include //#include using std::cout; using std::cin; using std::endl; namespace lemon { /// \addtogroup misc /// @{ /// \brief A partitioned vector with iterable classes. /// /// This class implements a container in which the data is stored in an /// stl vector, the range is partitioned into sets and each set is /// doubly linked in a list. /// That is, each class is iterable by lemon iterators, and any member of /// the vector can bo moved to an other class. template class IterablePartition { protected: struct Node { T data; int prev; //invalid az -1 int next; }; std::vector nodes; struct Tip { int first; int last; }; std::vector tips; public: /// The classes are indexed by integers from \c 0 to \c classNum()-1. int classNum() const { return tips.size(); } /// This lemon style iterator iterates through a class. class ClassIt; /// Constructor. The number of classes is to be given which is fixed /// over the life of the container. /// The partition classes are indexed from 0 to class_num-1. IterablePartition(int class_num) { for (int i=0; i class LPSolverBase { /*! @name Unchategorized functions and types (public members) */ //@{ public: //UNCATEGORIZED /// \e typedef _Value Value; /// \e typedef IterablePartition::ClassIt RowIt; /// \e typedef IterablePartition::ClassIt ColIt; public: /// \e IterablePartition row_iter_map; /// \e IterablePartition col_iter_map; /// \e const int VALID_CLASS; /// \e const int INVALID_CLASS; /// \e static const _Value INF; public: /// \e LPSolverBase() : row_iter_map(2), col_iter_map(2), VALID_CLASS(0), INVALID_CLASS(1) { } /// \e virtual ~LPSolverBase() { } //@} /*! @name Medium level interface (public members) These functions appear in the low level and also in the high level interfaces thus these each of these functions have to be implemented only once in the different interfaces. This means that these functions have to be reimplemented for all of the different lp solvers. These are basic functions, and have the same parameter lists in the low and high level interfaces. */ //@{ public: //UNCATEGORIZED FUNCTIONS /// \e virtual void setMinimize() = 0; /// \e virtual void setMaximize() = 0; //SOLVER FUNCTIONS /// \e virtual void solveSimplex() = 0; /// \e virtual void solvePrimalSimplex() = 0; /// \e virtual void solveDualSimplex() = 0; /// \e //SOLUTION RETRIEVING /// \e virtual _Value getObjVal() = 0; //OTHER FUNCTIONS /// \e virtual int rowNum() const = 0; /// \e virtual int colNum() const = 0; /// \e virtual int warmUp() = 0; /// \e virtual void printWarmUpStatus(int i) = 0; /// \e virtual int getPrimalStatus() = 0; /// \e virtual void printPrimalStatus(int i) = 0; /// \e virtual int getDualStatus() = 0; /// \e virtual void printDualStatus(int i) = 0; /// Returns the status of the slack variable assigned to row \c row_it. virtual int getRowStat(const RowIt& row_it) = 0; /// \e virtual void printRowStatus(int i) = 0; /// Returns the status of the variable assigned to column \c col_it. virtual int getColStat(const ColIt& col_it) = 0; /// \e virtual void printColStatus(int i) = 0; //@} /*! @name Low level interface (protected members) Problem manipulating functions in the low level interface */ //@{ protected: //MATRIX MANIPULATING FUNCTIONS /// \e virtual int _addCol() = 0; /// \e virtual int _addRow() = 0; /// \e virtual void _eraseCol(int i) = 0; /// \e virtual void _eraseRow(int i) = 0; /// \e virtual void _setRowCoeffs(int i, const std::vector >& coeffs) = 0; /// \e virtual void _setColCoeffs(int i, const std::vector >& coeffs) = 0; public: /// \e enum Bound { FREE, LOWER, UPPER, DOUBLE, FIXED }; protected: /// \e /// The lower bound of a variable (column) have to be given by an /// extended number of type _Value, i.e. a finite number of type /// _Value or -INF. virtual void _setColLowerBound(int i, _Value value) = 0; /// \e /// The lower bound of a variable (column) is an /// extended number of type _Value, i.e. a finite number of type /// _Value or -INF. virtual _Value _getColLowerBound(int i) = 0; /// \e /// The upper bound of a variable (column) have to be given by an /// extended number of type _Value, i.e. a finite number of type /// _Value or INF. virtual void _setColUpperBound(int i, _Value value) = 0; /// \e /// The upper bound of a variable (column) is an /// extended number of type _Value, i.e. a finite number of type /// _Value or INF. virtual _Value _getColUpperBound(int i) = 0; /// \e /// The lower bound of a linear expression (row) have to be given by an /// extended number of type _Value, i.e. a finite number of type /// _Value or -INF. virtual void _setRowLowerBound(int i, _Value value) = 0; /// \e /// The lower bound of a linear expression (row) is an /// extended number of type _Value, i.e. a finite number of type /// _Value or -INF. virtual _Value _getRowLowerBound(int i) = 0; /// \e /// The upper bound of a linear expression (row) have to be given by an /// extended number of type _Value, i.e. a finite number of type /// _Value or INF. virtual void _setRowUpperBound(int i, _Value value) = 0; /// \e /// The upper bound of a linear expression (row) is an /// extended number of type _Value, i.e. a finite number of type /// _Value or INF. virtual _Value _getRowUpperBound(int i) = 0; /// \e virtual void _setObjCoef(int i, _Value obj_coef) = 0; /// \e virtual _Value _getObjCoef(int i) = 0; //SOLUTION RETRIEVING /// \e virtual _Value _getPrimal(int i) = 0; //@} /*! @name High level interface (public members) Problem manipulating functions in the high level interface */ //@{ public: //MATRIX MANIPULATING FUNCTIONS /// \e ColIt addCol() { int i=_addCol(); ColIt col_it; col_iter_map.first(col_it, INVALID_CLASS); if (col_iter_map.valid(col_it)) { //van hasznalhato hely col_iter_map.set(col_it, INVALID_CLASS, VALID_CLASS); col_iter_map[col_it]=i; } else { //a cucc vegere kell inzertalni mert nincs szabad hely col_it=col_iter_map.push_back(i, VALID_CLASS); } return col_it; } /// \e RowIt addRow() { int i=_addRow(); RowIt row_it; row_iter_map.first(row_it, INVALID_CLASS); if (row_iter_map.valid(row_it)) { //van hasznalhato hely row_iter_map.set(row_it, INVALID_CLASS, VALID_CLASS); row_iter_map[row_it]=i; } else { //a cucc vegere kell inzertalni mert nincs szabad hely row_it=row_iter_map.push_back(i, VALID_CLASS); } return row_it; } /// \e void eraseCol(const ColIt& col_it) { col_iter_map.set(col_it, VALID_CLASS, INVALID_CLASS); int cols[2]; cols[1]=col_iter_map[col_it]; _eraseCol(cols[1]); col_iter_map[col_it]=0; //glpk specifikus, de kell ez?? ColIt it; for (col_iter_map.first(it, VALID_CLASS); col_iter_map.valid(it); col_iter_map.next(it)) { if (col_iter_map[it]>cols[1]) --col_iter_map[it]; } } /// \e void eraseRow(const RowIt& row_it) { row_iter_map.set(row_it, VALID_CLASS, INVALID_CLASS); int rows[2]; rows[1]=row_iter_map[row_it]; _eraseRow(rows[1]); row_iter_map[row_it]=0; //glpk specifikus, de kell ez?? RowIt it; for (row_iter_map.first(it, VALID_CLASS); row_iter_map.valid(it); row_iter_map.next(it)) { if (row_iter_map[it]>rows[1]) --row_iter_map[it]; } } /// \e template void setRowCoeffs(RowIt row_it, Begin begin, End end) { std::vector > coeffs; for ( ; begin!=end; ++begin) { coeffs.push_back(std:: make_pair(col_iter_map[begin->first], begin->second)); } _setRowCoeffs(row_iter_map[row_it], coeffs); } /// \e template void setColCoeffs(ColIt col_it, Begin begin, End end) { std::vector > coeffs; for ( ; begin!=end; ++begin) { coeffs.push_back(std:: make_pair(row_iter_map[begin->first], begin->second)); } _setColCoeffs(col_iter_map[col_it], coeffs); } /// \e void setColLowerBound(ColIt col_it, _Value lo) { _setColLowerBound(col_iter_map[col_it], lo); } /// \e _Value getColLowerBound(ColIt col_it) { return _getColLowerBound(col_iter_map[col_it]); } /// \e void setColUpperBound(ColIt col_it, _Value up) { _setColUpperBound(col_iter_map[col_it], up); } /// \e _Value getColUpperBound(ColIt col_it) { return _getColUpperBound(col_iter_map[col_it]); } /// \e void setRowLowerBound(RowIt row_it, _Value lo) { _setRowLowerBound(row_iter_map[row_it], lo); } /// \e _Value getRowLowerBound(RowIt row_it) { return _getRowLowerBound(row_iter_map[row_it]); } /// \e void setRowUpperBound(RowIt row_it, _Value up) { _setRowUpperBound(row_iter_map[row_it], up); } /// \e _Value getRowUpperBound(RowIt row_it) { return _getRowUpperBound(row_iter_map[row_it]); } /// \e void setObjCoef(const ColIt& col_it, _Value obj_coef) { _setObjCoef(col_iter_map[col_it], obj_coef); } /// \e _Value getObjCoef(const ColIt& col_it) { return _getObjCoef(col_iter_map[col_it]); } //SOLUTION RETRIEVING FUNCTIONS /// \e _Value getPrimal(const ColIt& col_it) { return _getPrimal(col_iter_map[col_it]); } //@} /*! @name User friend interface Problem manipulating functions in the user friend interface */ //@{ //EXPRESSION TYPES /// \e typedef Expr Expression; /// \e typedef Expr DualExpression; //MATRIX MANIPULATING FUNCTIONS /// \e void setRowCoeffs(RowIt row_it, const Expression& expr) { std::vector > row_coeffs; for(typename Expression::Data::const_iterator i=expr.data.begin(); i!=expr.data.end(); ++i) { row_coeffs.push_back(std::make_pair (col_iter_map[(*i).first], (*i).second)); } _setRowCoeffs(row_iter_map[row_it], row_coeffs); } /// \e void setColCoeffs(ColIt col_it, const DualExpression& expr) { std::vector > col_coeffs; for(typename DualExpression::Data::const_iterator i=expr.data.begin(); i!=expr.data.end(); ++i) { col_coeffs.push_back(std::make_pair (row_iter_map[(*i).first], (*i).second)); } _setColCoeffs(col_iter_map[col_it], col_coeffs); } /// \e void setObjCoeffs(const Expression& expr) { for(typename Expression::Data::const_iterator i=expr.data.begin(); i!=expr.data.end(); ++i) { setObjCoef((*i).first, (*i).second); } } //@} }; template const _Value LPSolverBase<_Value>::INF=std::numeric_limits<_Value>::infinity(); /// \brief Wrapper for GLPK solver /// /// This class implements a lemon wrapper for GLPK. class LPGLPK : public LPSolverBase { public: typedef LPSolverBase Parent; public: /// \e LPX* lp; public: /// \e LPGLPK() : Parent(), lp(lpx_create_prob()) { lpx_set_int_parm(lp, LPX_K_DUAL, 1); } /// \e ~LPGLPK() { lpx_delete_prob(lp); } //MATRIX INDEPEDENT MANIPULATING FUNCTIONS /// \e void setMinimize() { lpx_set_obj_dir(lp, LPX_MIN); } /// \e void setMaximize() { lpx_set_obj_dir(lp, LPX_MAX); } //LOW LEVEL INTERFACE, MATRIX MANIPULATING FUNCTIONS protected: /// \e int _addCol() { int i=lpx_add_cols(lp, 1); _setColLowerBound(i, -INF); _setColUpperBound(i, INF); return i; } /// \e int _addRow() { int i=lpx_add_rows(lp, 1); return i; } /// \e virtual void _setRowCoeffs(int i, const std::vector >& coeffs) { int mem_length=1+colNum(); int* indices = new int[mem_length]; double* doubles = new double[mem_length]; int length=0; for (std::vector >:: const_iterator it=coeffs.begin(); it!=coeffs.end(); ++it) { ++length; indices[length]=it->first; doubles[length]=it->second; // std::cout << " " << indices[length] << " " // << doubles[length] << std::endl; } // std::cout << i << " " << length << std::endl; lpx_set_mat_row(lp, i, length, indices, doubles); delete [] indices; delete [] doubles; } /// \e virtual void _setColCoeffs(int i, const std::vector >& coeffs) { int mem_length=1+rowNum(); int* indices = new int[mem_length]; double* doubles = new double[mem_length]; int length=0; for (std::vector >:: const_iterator it=coeffs.begin(); it!=coeffs.end(); ++it) { ++length; indices[length]=it->first; doubles[length]=it->second; } lpx_set_mat_col(lp, i, length, indices, doubles); delete [] indices; delete [] doubles; } /// \e virtual void _eraseCol(int i) { int cols[2]; cols[1]=i; lpx_del_cols(lp, 1, cols); } virtual void _eraseRow(int i) { int rows[2]; rows[1]=i; lpx_del_rows(lp, 1, rows); } virtual void _setColLowerBound(int i, double lo) { if (lo==INF) { //FIXME error } int b=lpx_get_col_type(lp, i); double up=lpx_get_col_ub(lp, i); if (lo==-INF) { switch (b) { case LPX_FR: case LPX_LO: lpx_set_col_bnds(lp, i, LPX_FR, lo, up); break; case LPX_UP: break; case LPX_DB: case LPX_FX: lpx_set_col_bnds(lp, i, LPX_UP, lo, up); break; default: ; //FIXME error } } else { switch (b) { case LPX_FR: case LPX_LO: lpx_set_col_bnds(lp, i, LPX_LO, lo, up); break; case LPX_UP: case LPX_DB: case LPX_FX: if (lo==up) lpx_set_col_bnds(lp, i, LPX_FX, lo, up); else lpx_set_col_bnds(lp, i, LPX_DB, lo, up); break; default: ; //FIXME error } } } virtual double _getColLowerBound(int i) { int b=lpx_get_col_type(lp, i); switch (b) { case LPX_FR: return -INF; case LPX_LO: return lpx_get_col_lb(lp, i); case LPX_UP: return -INF; case LPX_DB: case LPX_FX: return lpx_get_col_lb(lp, i); default: ; //FIXME error return 0.0; } } virtual void _setColUpperBound(int i, double up) { if (up==-INF) { //FIXME error } int b=lpx_get_col_type(lp, i); double lo=lpx_get_col_lb(lp, i); if (up==INF) { switch (b) { case LPX_FR: case LPX_LO: break; case LPX_UP: lpx_set_col_bnds(lp, i, LPX_FR, lo, up); break; case LPX_DB: case LPX_FX: lpx_set_col_bnds(lp, i, LPX_LO, lo, up); break; default: ; //FIXME error } } else { switch (b) { case LPX_FR: lpx_set_col_bnds(lp, i, LPX_UP, lo, up); case LPX_LO: if (lo==up) lpx_set_col_bnds(lp, i, LPX_FX, lo, up); else lpx_set_col_bnds(lp, i, LPX_DB, lo, up); break; case LPX_UP: lpx_set_col_bnds(lp, i, LPX_UP, lo, up); break; case LPX_DB: case LPX_FX: if (lo==up) lpx_set_col_bnds(lp, i, LPX_FX, lo, up); else lpx_set_col_bnds(lp, i, LPX_DB, lo, up); break; default: ; //FIXME error } } } virtual double _getColUpperBound(int i) { int b=lpx_get_col_type(lp, i); switch (b) { case LPX_FR: case LPX_LO: return INF; case LPX_UP: case LPX_DB: case LPX_FX: return lpx_get_col_ub(lp, i); default: ; //FIXME error return 0.0; } } virtual void _setRowLowerBound(int i, double lo) { if (lo==INF) { //FIXME error } int b=lpx_get_row_type(lp, i); double up=lpx_get_row_ub(lp, i); if (lo==-INF) { switch (b) { case LPX_FR: case LPX_LO: lpx_set_row_bnds(lp, i, LPX_FR, lo, up); break; case LPX_UP: break; case LPX_DB: case LPX_FX: lpx_set_row_bnds(lp, i, LPX_UP, lo, up); break; default: ; //FIXME error } } else { switch (b) { case LPX_FR: case LPX_LO: lpx_set_row_bnds(lp, i, LPX_LO, lo, up); break; case LPX_UP: case LPX_DB: case LPX_FX: if (lo==up) lpx_set_row_bnds(lp, i, LPX_FX, lo, up); else lpx_set_row_bnds(lp, i, LPX_DB, lo, up); break; default: ; //FIXME error } } } virtual double _getRowLowerBound(int i) { int b=lpx_get_row_type(lp, i); switch (b) { case LPX_FR: return -INF; case LPX_LO: return lpx_get_row_lb(lp, i); case LPX_UP: return -INF; case LPX_DB: case LPX_FX: return lpx_get_row_lb(lp, i); default: ; //FIXME error return 0.0; } } virtual void _setRowUpperBound(int i, double up) { if (up==-INF) { //FIXME error } int b=lpx_get_row_type(lp, i); double lo=lpx_get_row_lb(lp, i); if (up==INF) { switch (b) { case LPX_FR: case LPX_LO: break; case LPX_UP: lpx_set_row_bnds(lp, i, LPX_FR, lo, up); break; case LPX_DB: case LPX_FX: lpx_set_row_bnds(lp, i, LPX_LO, lo, up); break; default: ; //FIXME error } } else { switch (b) { case LPX_FR: lpx_set_row_bnds(lp, i, LPX_UP, lo, up); case LPX_LO: if (lo==up) lpx_set_row_bnds(lp, i, LPX_FX, lo, up); else lpx_set_row_bnds(lp, i, LPX_DB, lo, up); break; case LPX_UP: lpx_set_row_bnds(lp, i, LPX_UP, lo, up); break; case LPX_DB: case LPX_FX: if (lo==up) lpx_set_row_bnds(lp, i, LPX_FX, lo, up); else lpx_set_row_bnds(lp, i, LPX_DB, lo, up); break; default: ; //FIXME error } } } virtual double _getRowUpperBound(int i) { int b=lpx_get_row_type(lp, i); switch (b) { case LPX_FR: case LPX_LO: return INF; case LPX_UP: case LPX_DB: case LPX_FX: return lpx_get_row_ub(lp, i); default: ; //FIXME error return 0.0; } } /// \e virtual double _getObjCoef(int i) { return lpx_get_obj_coef(lp, i); } /// \e virtual void _setObjCoef(int i, double obj_coef) { lpx_set_obj_coef(lp, i, obj_coef); } public: /// \e void solveSimplex() { lpx_simplex(lp); } /// \e void solvePrimalSimplex() { lpx_simplex(lp); } /// \e void solveDualSimplex() { lpx_simplex(lp); } /// \e protected: virtual double _getPrimal(int i) { return lpx_get_col_prim(lp, i); } public: /// \e double getObjVal() { return lpx_get_obj_val(lp); } /// \e int rowNum() const { return lpx_get_num_rows(lp); } /// \e int colNum() const { return lpx_get_num_cols(lp); } /// \e int warmUp() { return lpx_warm_up(lp); } /// \e void printWarmUpStatus(int i) { switch (i) { case LPX_E_OK: cout << "LPX_E_OK" << endl; break; case LPX_E_EMPTY: cout << "LPX_E_EMPTY" << endl; break; case LPX_E_BADB: cout << "LPX_E_BADB" << endl; break; case LPX_E_SING: cout << "LPX_E_SING" << endl; break; } } /// \e int getPrimalStatus() { return lpx_get_prim_stat(lp); } /// \e void printPrimalStatus(int i) { switch (i) { case LPX_P_UNDEF: cout << "LPX_P_UNDEF" << endl; break; case LPX_P_FEAS: cout << "LPX_P_FEAS" << endl; break; case LPX_P_INFEAS: cout << "LPX_P_INFEAS" << endl; break; case LPX_P_NOFEAS: cout << "LPX_P_NOFEAS" << endl; break; } } /// \e int getDualStatus() { return lpx_get_dual_stat(lp); } /// \e void printDualStatus(int i) { switch (i) { case LPX_D_UNDEF: cout << "LPX_D_UNDEF" << endl; break; case LPX_D_FEAS: cout << "LPX_D_FEAS" << endl; break; case LPX_D_INFEAS: cout << "LPX_D_INFEAS" << endl; break; case LPX_D_NOFEAS: cout << "LPX_D_NOFEAS" << endl; break; } } /// Returns the status of the slack variable assigned to row \c row_it. int getRowStat(const RowIt& row_it) { return lpx_get_row_stat(lp, row_iter_map[row_it]); } /// \e void printRowStatus(int i) { switch (i) { case LPX_BS: cout << "LPX_BS" << endl; break; case LPX_NL: cout << "LPX_NL" << endl; break; case LPX_NU: cout << "LPX_NU" << endl; break; case LPX_NF: cout << "LPX_NF" << endl; break; case LPX_NS: cout << "LPX_NS" << endl; break; } } /// Returns the status of the variable assigned to column \c col_it. int getColStat(const ColIt& col_it) { return lpx_get_col_stat(lp, col_iter_map[col_it]); } /// \e void printColStatus(int i) { switch (i) { case LPX_BS: cout << "LPX_BS" << endl; break; case LPX_NL: cout << "LPX_NL" << endl; break; case LPX_NU: cout << "LPX_NU" << endl; break; case LPX_NF: cout << "LPX_NF" << endl; break; case LPX_NS: cout << "LPX_NS" << endl; break; } } }; /// @} } //namespace lemon #endif //LEMON_LP_SOLVER_WRAPPER_H