1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2009
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
20 ///\brief Implementation of the LEMON GLPK LP and MIP solver interface.
22 #include <lemon/glpk.h>
25 #include <lemon/assert.h>
31 GlpkBase::GlpkBase() : LpBase() {
32 lp = glp_create_prob();
36 GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
37 lp = glp_create_prob();
38 glp_copy_prob(lp, other.lp, GLP_ON);
44 GlpkBase::~GlpkBase() {
48 int GlpkBase::_addCol() {
49 int i = glp_add_cols(lp, 1);
50 glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
54 int GlpkBase::_addRow() {
55 int i = glp_add_rows(lp, 1);
56 glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
60 void GlpkBase::_eraseCol(int i) {
63 glp_del_cols(lp, 1, ca);
66 void GlpkBase::_eraseRow(int i) {
69 glp_del_rows(lp, 1, ra);
72 void GlpkBase::_eraseColId(int i) {
77 void GlpkBase::_eraseRowId(int i) {
82 void GlpkBase::_getColName(int c, std::string& name) const {
83 const char *str = glp_get_col_name(lp, c);
88 void GlpkBase::_setColName(int c, const std::string & name) {
89 glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
93 int GlpkBase::_colByName(const std::string& name) const {
94 int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
95 return k > 0 ? k : -1;
98 void GlpkBase::_getRowName(int r, std::string& name) const {
99 const char *str = glp_get_row_name(lp, r);
104 void GlpkBase::_setRowName(int r, const std::string & name) {
105 glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
109 int GlpkBase::_rowByName(const std::string& name) const {
110 int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
111 return k > 0 ? k : -1;
114 void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
115 std::vector<int> indexes;
116 std::vector<Value> values;
118 indexes.push_back(0);
121 for(ExprIterator it = b; it != e; ++it) {
122 indexes.push_back(it->first);
123 values.push_back(it->second);
126 glp_set_mat_row(lp, i, values.size() - 1,
127 &indexes.front(), &values.front());
130 void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
131 int length = glp_get_mat_row(lp, ix, 0, 0);
133 std::vector<int> indexes(length + 1);
134 std::vector<Value> values(length + 1);
136 glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
138 for (int i = 1; i <= length; ++i) {
139 *b = std::make_pair(indexes[i], values[i]);
144 void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
147 std::vector<int> indexes;
148 std::vector<Value> values;
150 indexes.push_back(0);
153 for(ExprIterator it = b; it != e; ++it) {
154 indexes.push_back(it->first);
155 values.push_back(it->second);
158 glp_set_mat_col(lp, ix, values.size() - 1,
159 &indexes.front(), &values.front());
162 void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
163 int length = glp_get_mat_col(lp, ix, 0, 0);
165 std::vector<int> indexes(length + 1);
166 std::vector<Value> values(length + 1);
168 glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
170 for (int i = 1; i <= length; ++i) {
171 *b = std::make_pair(indexes[i], values[i]);
176 void GlpkBase::_setCoeff(int ix, int jx, Value value) {
178 if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
180 int length = glp_get_mat_row(lp, ix, 0, 0);
182 std::vector<int> indexes(length + 2);
183 std::vector<Value> values(length + 2);
185 glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
187 //The following code does not suppose that the elements of the
188 //array indexes are sorted
190 for (int i = 1; i <= length; ++i) {
191 if (indexes[i] == jx) {
199 indexes[length] = jx;
200 values[length] = value;
203 glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
207 int length = glp_get_mat_col(lp, jx, 0, 0);
209 std::vector<int> indexes(length + 2);
210 std::vector<Value> values(length + 2);
212 glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
214 //The following code does not suppose that the elements of the
215 //array indexes are sorted
217 for (int i = 1; i <= length; ++i) {
218 if (indexes[i] == ix) {
226 indexes[length] = ix;
227 values[length] = value;
230 glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
235 GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
237 int length = glp_get_mat_row(lp, ix, 0, 0);
239 std::vector<int> indexes(length + 1);
240 std::vector<Value> values(length + 1);
242 glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
244 for (int i = 1; i <= length; ++i) {
245 if (indexes[i] == jx) {
253 void GlpkBase::_setColLowerBound(int i, Value lo) {
254 LEMON_ASSERT(lo != INF, "Invalid bound");
256 int b = glp_get_col_type(lp, i);
257 double up = glp_get_col_ub(lp, i);
262 glp_set_col_bnds(lp, i, GLP_FR, lo, up);
268 glp_set_col_bnds(lp, i, GLP_UP, lo, up);
277 glp_set_col_bnds(lp, i, GLP_LO, lo, up);
283 glp_set_col_bnds(lp, i, GLP_FX, lo, up);
285 glp_set_col_bnds(lp, i, GLP_DB, lo, up);
293 GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
294 int b = glp_get_col_type(lp, i);
299 return glp_get_col_lb(lp, i);
305 void GlpkBase::_setColUpperBound(int i, Value up) {
306 LEMON_ASSERT(up != -INF, "Invalid bound");
308 int b = glp_get_col_type(lp, i);
309 double lo = glp_get_col_lb(lp, i);
316 glp_set_col_bnds(lp, i, GLP_FR, lo, up);
320 glp_set_col_bnds(lp, i, GLP_LO, lo, up);
328 glp_set_col_bnds(lp, i, GLP_UP, lo, up);
331 glp_set_col_bnds(lp, i, GLP_UP, lo, up);
337 glp_set_col_bnds(lp, i, GLP_FX, lo, up);
339 glp_set_col_bnds(lp, i, GLP_DB, lo, up);
348 GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
349 int b = glp_get_col_type(lp, i);
354 return glp_get_col_ub(lp, i);
360 void GlpkBase::_setRowLowerBound(int i, Value lo) {
361 LEMON_ASSERT(lo != INF, "Invalid bound");
363 int b = glp_get_row_type(lp, i);
364 double up = glp_get_row_ub(lp, i);
369 glp_set_row_bnds(lp, i, GLP_FR, lo, up);
375 glp_set_row_bnds(lp, i, GLP_UP, lo, up);
384 glp_set_row_bnds(lp, i, GLP_LO, lo, up);
390 glp_set_row_bnds(lp, i, GLP_FX, lo, up);
392 glp_set_row_bnds(lp, i, GLP_DB, lo, up);
401 GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
402 int b = glp_get_row_type(lp, i);
407 return glp_get_row_lb(lp, i);
413 void GlpkBase::_setRowUpperBound(int i, Value up) {
414 LEMON_ASSERT(up != -INF, "Invalid bound");
416 int b = glp_get_row_type(lp, i);
417 double lo = glp_get_row_lb(lp, i);
424 glp_set_row_bnds(lp, i, GLP_FR, lo, up);
428 glp_set_row_bnds(lp, i, GLP_LO, lo, up);
436 glp_set_row_bnds(lp, i, GLP_UP, lo, up);
439 glp_set_row_bnds(lp, i, GLP_UP, lo, up);
445 glp_set_row_bnds(lp, i, GLP_FX, lo, up);
447 glp_set_row_bnds(lp, i, GLP_DB, lo, up);
455 GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
456 int b = glp_get_row_type(lp, i);
461 return glp_get_row_ub(lp, i);
467 void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
468 for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
469 glp_set_obj_coef(lp, i, 0.0);
471 for (ExprIterator it = b; it != e; ++it) {
472 glp_set_obj_coef(lp, it->first, it->second);
476 void GlpkBase::_getObjCoeffs(InsertIterator b) const {
477 for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
478 Value val = glp_get_obj_coef(lp, i);
480 *b = std::make_pair(i, val);
486 void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
487 //i = 0 means the constant term (shift)
488 glp_set_obj_coef(lp, i, obj_coef);
491 GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
492 //i = 0 means the constant term (shift)
493 return glp_get_obj_coef(lp, i);
496 void GlpkBase::_setSense(GlpkBase::Sense sense) {
499 glp_set_obj_dir(lp, GLP_MIN);
502 glp_set_obj_dir(lp, GLP_MAX);
507 GlpkBase::Sense GlpkBase::_getSense() const {
508 switch(glp_get_obj_dir(lp)) {
514 LEMON_ASSERT(false, "Wrong sense");
515 return GlpkBase::Sense();
519 void GlpkBase::_clear() {
525 void GlpkBase::freeEnv() {
529 GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
534 : LpBase(), LpSolver(), GlpkBase() {
535 messageLevel(MESSAGE_NO_OUTPUT);
539 GlpkLp::GlpkLp(const GlpkLp& other)
540 : LpBase(other), LpSolver(other), GlpkBase(other) {
541 messageLevel(MESSAGE_NO_OUTPUT);
545 GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; }
546 GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); }
548 const char* GlpkLp::_solverName() const { return "GlpkLp"; }
550 void GlpkLp::_clear_temporals() {
555 GlpkLp::SolveExitStatus GlpkLp::_solve() {
556 return solvePrimal();
559 GlpkLp::SolveExitStatus GlpkLp::solvePrimal() {
563 glp_init_smcp(&smcp);
565 switch (_message_level) {
566 case MESSAGE_NO_OUTPUT:
567 smcp.msg_lev = GLP_MSG_OFF;
569 case MESSAGE_ERROR_MESSAGE:
570 smcp.msg_lev = GLP_MSG_ERR;
572 case MESSAGE_NORMAL_OUTPUT:
573 smcp.msg_lev = GLP_MSG_ON;
575 case MESSAGE_FULL_OUTPUT:
576 smcp.msg_lev = GLP_MSG_ALL;
579 smcp.presolve = _presolve;
581 // If the basis is not valid we get an error return value.
582 // In this case we can try to create a new basis.
583 switch (glp_simplex(lp, &smcp)) {
589 lpx_set_int_parm(lp, LPX_K_MSGLEV, smcp.msg_lev);
590 glp_adv_basis(lp, 0);
591 if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
600 GlpkLp::SolveExitStatus GlpkLp::solveDual() {
604 glp_init_smcp(&smcp);
606 switch (_message_level) {
607 case MESSAGE_NO_OUTPUT:
608 smcp.msg_lev = GLP_MSG_OFF;
610 case MESSAGE_ERROR_MESSAGE:
611 smcp.msg_lev = GLP_MSG_ERR;
613 case MESSAGE_NORMAL_OUTPUT:
614 smcp.msg_lev = GLP_MSG_ON;
616 case MESSAGE_FULL_OUTPUT:
617 smcp.msg_lev = GLP_MSG_ALL;
620 smcp.meth = GLP_DUAL;
621 smcp.presolve = _presolve;
623 // If the basis is not valid we get an error return value.
624 // In this case we can try to create a new basis.
625 switch (glp_simplex(lp, &smcp)) {
631 lpx_set_int_parm(lp, LPX_K_MSGLEV, smcp.msg_lev);
632 glp_adv_basis(lp, 0);
633 if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
641 GlpkLp::Value GlpkLp::_getPrimal(int i) const {
642 return glp_get_col_prim(lp, i);
645 GlpkLp::Value GlpkLp::_getDual(int i) const {
646 return glp_get_row_dual(lp, i);
649 GlpkLp::Value GlpkLp::_getPrimalValue() const {
650 return glp_get_obj_val(lp);
653 GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const {
654 switch (glp_get_col_stat(lp, i)) {
666 LEMON_ASSERT(false, "Wrong column status");
667 return GlpkLp::VarStatus();
671 GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const {
672 switch (glp_get_row_stat(lp, i)) {
684 LEMON_ASSERT(false, "Wrong row status");
685 return GlpkLp::VarStatus();
689 GlpkLp::Value GlpkLp::_getPrimalRay(int i) const {
690 if (_primal_ray.empty()) {
691 int row_num = glp_get_num_rows(lp);
692 int col_num = glp_get_num_cols(lp);
694 _primal_ray.resize(col_num + 1, 0.0);
696 int index = glp_get_unbnd_ray(lp);
698 // The primal ray is found in primal simplex second phase
699 LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
700 glp_get_col_stat(lp, index - row_num)) != GLP_BS,
703 bool negate = glp_get_obj_dir(lp) == GLP_MAX;
705 if (index > row_num) {
706 _primal_ray[index - row_num] = 1.0;
707 if (glp_get_col_dual(lp, index - row_num) > 0) {
711 if (glp_get_row_dual(lp, index) > 0) {
716 std::vector<int> ray_indexes(row_num + 1);
717 std::vector<Value> ray_values(row_num + 1);
718 int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
719 &ray_values.front());
721 for (int i = 1; i <= ray_length; ++i) {
722 if (ray_indexes[i] > row_num) {
723 _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
728 for (int i = 1; i <= col_num; ++i) {
729 _primal_ray[i] = - _primal_ray[i];
733 for (int i = 1; i <= col_num; ++i) {
734 _primal_ray[i] = glp_get_col_prim(lp, i);
738 return _primal_ray[i];
741 GlpkLp::Value GlpkLp::_getDualRay(int i) const {
742 if (_dual_ray.empty()) {
743 int row_num = glp_get_num_rows(lp);
745 _dual_ray.resize(row_num + 1, 0.0);
747 int index = glp_get_unbnd_ray(lp);
749 // The dual ray is found in dual simplex second phase
750 LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
751 glp_get_col_stat(lp, index - row_num)) == GLP_BS,
758 if (index > row_num) {
759 idx = glp_get_col_bind(lp, index - row_num);
760 if (glp_get_col_prim(lp, index - row_num) >
761 glp_get_col_ub(lp, index - row_num)) {
765 idx = glp_get_row_bind(lp, index);
766 if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
771 _dual_ray[idx] = negate ? - 1.0 : 1.0;
773 glp_btran(lp, &_dual_ray.front());
776 // The dual ray is found in primal simplex first phase
777 // We assume that the glpk minimizes the slack to get feasible solution
778 for (int i = 1; i <= row_num; ++i) {
779 int index = glp_get_bhead(lp, i);
780 if (index <= row_num) {
781 double res = glp_get_row_prim(lp, index);
782 if (res > glp_get_row_ub(lp, index) + eps) {
784 } else if (res < glp_get_row_lb(lp, index) - eps) {
789 _dual_ray[i] *= glp_get_rii(lp, index);
791 double res = glp_get_col_prim(lp, index - row_num);
792 if (res > glp_get_col_ub(lp, index - row_num) + eps) {
794 } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
799 _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
803 glp_btran(lp, &_dual_ray.front());
805 for (int i = 1; i <= row_num; ++i) {
806 _dual_ray[i] /= glp_get_rii(lp, i);
813 GlpkLp::ProblemType GlpkLp::_getPrimalType() const {
814 if (glp_get_status(lp) == GLP_OPT)
816 switch (glp_get_prim_stat(lp)) {
821 if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
829 LEMON_ASSERT(false, "Wrong primal type");
830 return GlpkLp::ProblemType();
834 GlpkLp::ProblemType GlpkLp::_getDualType() const {
835 if (glp_get_status(lp) == GLP_OPT)
837 switch (glp_get_dual_stat(lp)) {
842 if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
850 LEMON_ASSERT(false, "Wrong primal type");
851 return GlpkLp::ProblemType();
855 void GlpkLp::presolver(bool presolve) {
856 _presolve = presolve;
859 void GlpkLp::messageLevel(MessageLevel m) {
866 : LpBase(), MipSolver(), GlpkBase() {
867 messageLevel(MESSAGE_NO_OUTPUT);
870 GlpkMip::GlpkMip(const GlpkMip& other)
871 : LpBase(), MipSolver(), GlpkBase(other) {
872 messageLevel(MESSAGE_NO_OUTPUT);
875 void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
878 glp_set_col_kind(lp, i, GLP_IV);
881 glp_set_col_kind(lp, i, GLP_CV);
886 GlpkMip::ColTypes GlpkMip::_getColType(int i) const {
887 switch (glp_get_col_kind(lp, i)) {
897 GlpkMip::SolveExitStatus GlpkMip::_solve() {
899 glp_init_smcp(&smcp);
901 switch (_message_level) {
902 case MESSAGE_NO_OUTPUT:
903 smcp.msg_lev = GLP_MSG_OFF;
905 case MESSAGE_ERROR_MESSAGE:
906 smcp.msg_lev = GLP_MSG_ERR;
908 case MESSAGE_NORMAL_OUTPUT:
909 smcp.msg_lev = GLP_MSG_ON;
911 case MESSAGE_FULL_OUTPUT:
912 smcp.msg_lev = GLP_MSG_ALL;
915 smcp.meth = GLP_DUAL;
917 // If the basis is not valid we get an error return value.
918 // In this case we can try to create a new basis.
919 switch (glp_simplex(lp, &smcp)) {
925 lpx_set_int_parm(lp, LPX_K_MSGLEV, smcp.msg_lev);
926 glp_adv_basis(lp, 0);
927 if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
933 if (glp_get_status(lp) != GLP_OPT) return SOLVED;
936 glp_init_iocp(&iocp);
938 switch (_message_level) {
939 case MESSAGE_NO_OUTPUT:
940 iocp.msg_lev = GLP_MSG_OFF;
942 case MESSAGE_ERROR_MESSAGE:
943 iocp.msg_lev = GLP_MSG_ERR;
945 case MESSAGE_NORMAL_OUTPUT:
946 iocp.msg_lev = GLP_MSG_ON;
948 case MESSAGE_FULL_OUTPUT:
949 iocp.msg_lev = GLP_MSG_ALL;
953 if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
958 GlpkMip::ProblemType GlpkMip::_getType() const {
959 switch (glp_get_status(lp)) {
961 switch (glp_mip_status(lp)) {
971 LEMON_ASSERT(false, "Wrong problem type.");
972 return GlpkMip::ProblemType();
978 if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
984 LEMON_ASSERT(false, "Wrong problem type.");
985 return GlpkMip::ProblemType();
989 GlpkMip::Value GlpkMip::_getSol(int i) const {
990 return glp_mip_col_val(lp, i);
993 GlpkMip::Value GlpkMip::_getSolValue() const {
994 return glp_mip_obj_val(lp);
997 GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; }
998 GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); }
1000 const char* GlpkMip::_solverName() const { return "GlpkMip"; }
1002 void GlpkMip::messageLevel(MessageLevel m) {
1006 } //END OF NAMESPACE LEMON