/* -*- C++ -*- * lemon/lp_glpk.cc - 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_GLPK_CC #define LEMON_LP_GLPK_CC ///\file ///\brief Implementation of the LEMON-GLPK lp solver interface. #include //#include namespace lemon { LpGlpk::LpGlpk() : Parent(), lp(lpx_create_prob()) { ///\todo constrol function for this: lpx_set_int_parm(lp, LPX_K_DUAL, 1); messageLevel(0); } LpGlpk::~LpGlpk() { lpx_delete_prob(lp); } int LpGlpk::_addCol() { int i=lpx_add_cols(lp, 1); _setColLowerBound(i, -INF); _setColUpperBound(i, INF); return i; } ///\e LpSolverBase &LpGlpk::_newLp() { LpGlpk* newlp=new LpGlpk(); return *newlp; } ///\e LpSolverBase &LpGlpk::_copyLp() { LpGlpk* newlp=new LpGlpk(); //Coefficient matrix, row bounds lpx_add_rows(newlp->lp, lpx_get_num_rows(lp)); lpx_add_cols(newlp->lp, lpx_get_num_cols(lp)); int len; int ind[1+lpx_get_num_cols(lp)]; Value val[1+lpx_get_num_cols(lp)]; for (int i=1;i<=lpx_get_num_rows(lp);++i){ len=lpx_get_mat_row(lp,i,ind,val); lpx_set_mat_row(newlp->lp, i,len,ind,val); lpx_set_row_bnds(newlp->lp,i,lpx_get_row_type(lp,i), lpx_get_row_lb(lp,i),lpx_get_row_ub(lp,i)); } //Objective function, coloumn bounds lpx_set_obj_dir(newlp->lp, lpx_get_obj_dir(lp)); //Objectif function's constant term treated separately lpx_set_obj_coef(newlp->lp,0,lpx_get_obj_coef(lp,0)); for (int i=1;i<=lpx_get_num_cols(lp);++i){ lpx_set_obj_coef(newlp->lp,i,lpx_get_obj_coef(lp,i)); lpx_set_col_bnds(newlp->lp,i,lpx_get_col_type(lp,i), lpx_get_col_lb(lp,i),lpx_get_col_ub(lp,i)); } return *newlp; } int LpGlpk::_addRow() { int i=lpx_add_rows(lp, 1); return i; } void LpGlpk::_eraseCol(int i) { int cols[2]; cols[1]=i; lpx_del_cols(lp, 1, cols); } void LpGlpk::_eraseRow(int i) { int rows[2]; rows[1]=i; lpx_del_rows(lp, 1, rows); } void LpGlpk::_setRowCoeffs(int i, int length, const int * indices, const Value * values ) { lpx_set_mat_row(lp, i, length, const_cast(indices) , const_cast(values)); } void LpGlpk::_setColCoeffs(int i, int length, const int * indices, const Value * values) { lpx_set_mat_col(lp, i, length, const_cast(indices), const_cast(values)); } void LpGlpk::_setCoeff(int row, int col, Value value) { ///FIXME Of course this is not efficient at all, but GLPK knows not more. // First approach: get one row, apply changes and set it again //(one idea to improve this: maybe it is better to do this with 1 coloumn) int mem_length=2+lpx_get_num_cols(lp); int* indices = new int[mem_length]; Value* values = new Value[mem_length]; int length=lpx_get_mat_row(lp, row, indices, values); //The following code does not suppose that the elements of the array indices are sorted int i=1; bool found=false; while (i <= length && !found){ if (indices[i]==col){ found = true; values[i]=value; } ++i; } if (!found){ ++length; indices[length]=col; values[length]=value; } lpx_set_mat_row(lp, row, length, indices, values); delete [] indices; delete [] values; } void LpGlpk::_setColLowerBound(int i, Value 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 } } } void LpGlpk::_setColUpperBound(int i, Value 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); break; case LPX_UP: lpx_set_col_bnds(lp, i, LPX_UP, lo, up); break; case LPX_LO: 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 } } } // void LpGlpk::_setRowLowerBound(int i, Value 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 // } // } // } // void LpGlpk::_setRowUpperBound(int i, Value 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); // break; // case LPX_UP: // lpx_set_row_bnds(lp, i, LPX_UP, lo, up); // break; // case LPX_LO: // 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 // } // } // } void LpGlpk::_setRowBounds(int i, Value lb, Value ub) { //Bad parameter if (lb==INF || ub==-INF) { //FIXME error } if (lb == -INF){ if (ub == INF){ lpx_set_row_bnds(lp, i, LPX_FR, lb, ub); } else{ lpx_set_row_bnds(lp, i, LPX_UP, lb, ub); } } else{ if (ub==INF){ lpx_set_row_bnds(lp, i, LPX_LO, lb, ub); } else{ if (lb == ub){ lpx_set_row_bnds(lp, i, LPX_FX, lb, ub); } else{ lpx_set_row_bnds(lp, i, LPX_DB, lb, ub); } } } } void LpGlpk::_setObjCoeff(int i, Value obj_coef) { //i=0 means the constant term (shift) lpx_set_obj_coef(lp, i, obj_coef); } void LpGlpk::_clearObj() { for (int i=0;i<=lpx_get_num_cols(lp);++i){ lpx_set_obj_coef(lp, i, 0); } } // void LpGlpk::_setObj(int length, // int const * indices, // Value const * values ) // { // Value new_values[1+lpx_num_cols()]; // for (i=0;i<=lpx_num_cols();++i){ // new_values[i]=0; // } // for (i=1;i<=length;++i){ // new_values[indices[i]]=values[i]; // } // for (i=0;i<=lpx_num_cols();++i){ // lpx_set_obj_coef(lp, i, new_values[i]); // } // } LpGlpk::SolveExitStatus LpGlpk::_solve() { int i = lpx_simplex(lp); switch (i) { case LPX_E_OK: return SOLVED; default: return UNSOLVED; } } LpGlpk::Value LpGlpk::_getPrimal(int i) { return lpx_get_col_prim(lp,i); } LpGlpk::Value LpGlpk::_getDual(int i) { return lpx_get_row_dual(lp,i); } LpGlpk::Value LpGlpk::_getPrimalValue() { return lpx_get_obj_val(lp); } bool LpGlpk::_isBasicCol(int i) { return (lpx_get_col_stat(lp, i)==LPX_BS); } LpGlpk::SolutionStatus LpGlpk::_getPrimalStatus() { int stat= lpx_get_status(lp); switch (stat) { case LPX_UNDEF://Undefined (no solve has been run yet) return UNDEFINED; case LPX_NOFEAS://There is no feasible solution (primal, I guess) case LPX_INFEAS://Infeasible return INFEASIBLE; case LPX_UNBND://Unbounded return INFINITE; case LPX_FEAS://Feasible return FEASIBLE; case LPX_OPT://Feasible return OPTIMAL; default: return UNDEFINED; //to avoid gcc warning //FIXME error } } LpGlpk::SolutionStatus LpGlpk::_getDualStatus() { // std::cout<<"Itt megy: "<