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();
34 messageLevel(MESSAGE_NOTHING);
37 GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
38 lp = glp_create_prob();
39 glp_copy_prob(lp, other.lp, GLP_ON);
43 messageLevel(MESSAGE_NOTHING);
46 GlpkBase::~GlpkBase() {
50 int GlpkBase::_addCol() {
51 int i = glp_add_cols(lp, 1);
52 glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
56 int GlpkBase::_addRow() {
57 int i = glp_add_rows(lp, 1);
58 glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
62 void GlpkBase::_eraseCol(int i) {
65 glp_del_cols(lp, 1, ca);
68 void GlpkBase::_eraseRow(int i) {
71 glp_del_rows(lp, 1, ra);
74 void GlpkBase::_eraseColId(int i) {
79 void GlpkBase::_eraseRowId(int i) {
84 void GlpkBase::_getColName(int c, std::string& name) const {
85 const char *str = glp_get_col_name(lp, c);
90 void GlpkBase::_setColName(int c, const std::string & name) {
91 glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
95 int GlpkBase::_colByName(const std::string& name) const {
96 int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
97 return k > 0 ? k : -1;
100 void GlpkBase::_getRowName(int r, std::string& name) const {
101 const char *str = glp_get_row_name(lp, r);
106 void GlpkBase::_setRowName(int r, const std::string & name) {
107 glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
111 int GlpkBase::_rowByName(const std::string& name) const {
112 int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
113 return k > 0 ? k : -1;
116 void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
117 std::vector<int> indexes;
118 std::vector<Value> values;
120 indexes.push_back(0);
123 for(ExprIterator it = b; it != e; ++it) {
124 indexes.push_back(it->first);
125 values.push_back(it->second);
128 glp_set_mat_row(lp, i, values.size() - 1,
129 &indexes.front(), &values.front());
132 void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
133 int length = glp_get_mat_row(lp, ix, 0, 0);
135 std::vector<int> indexes(length + 1);
136 std::vector<Value> values(length + 1);
138 glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
140 for (int i = 1; i <= length; ++i) {
141 *b = std::make_pair(indexes[i], values[i]);
146 void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
149 std::vector<int> indexes;
150 std::vector<Value> values;
152 indexes.push_back(0);
155 for(ExprIterator it = b; it != e; ++it) {
156 indexes.push_back(it->first);
157 values.push_back(it->second);
160 glp_set_mat_col(lp, ix, values.size() - 1,
161 &indexes.front(), &values.front());
164 void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
165 int length = glp_get_mat_col(lp, ix, 0, 0);
167 std::vector<int> indexes(length + 1);
168 std::vector<Value> values(length + 1);
170 glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
172 for (int i = 1; i <= length; ++i) {
173 *b = std::make_pair(indexes[i], values[i]);
178 void GlpkBase::_setCoeff(int ix, int jx, Value value) {
180 if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
182 int length = glp_get_mat_row(lp, ix, 0, 0);
184 std::vector<int> indexes(length + 2);
185 std::vector<Value> values(length + 2);
187 glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
189 //The following code does not suppose that the elements of the
190 //array indexes are sorted
192 for (int i = 1; i <= length; ++i) {
193 if (indexes[i] == jx) {
201 indexes[length] = jx;
202 values[length] = value;
205 glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
209 int length = glp_get_mat_col(lp, jx, 0, 0);
211 std::vector<int> indexes(length + 2);
212 std::vector<Value> values(length + 2);
214 glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
216 //The following code does not suppose that the elements of the
217 //array indexes are sorted
219 for (int i = 1; i <= length; ++i) {
220 if (indexes[i] == ix) {
228 indexes[length] = ix;
229 values[length] = value;
232 glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
237 GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
239 int length = glp_get_mat_row(lp, ix, 0, 0);
241 std::vector<int> indexes(length + 1);
242 std::vector<Value> values(length + 1);
244 glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
246 for (int i = 1; i <= length; ++i) {
247 if (indexes[i] == jx) {
255 void GlpkBase::_setColLowerBound(int i, Value lo) {
256 LEMON_ASSERT(lo != INF, "Invalid bound");
258 int b = glp_get_col_type(lp, i);
259 double up = glp_get_col_ub(lp, i);
264 glp_set_col_bnds(lp, i, GLP_FR, lo, up);
270 glp_set_col_bnds(lp, i, GLP_UP, lo, up);
279 glp_set_col_bnds(lp, i, GLP_LO, lo, up);
285 glp_set_col_bnds(lp, i, GLP_FX, lo, up);
287 glp_set_col_bnds(lp, i, GLP_DB, lo, up);
295 GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
296 int b = glp_get_col_type(lp, i);
301 return glp_get_col_lb(lp, i);
307 void GlpkBase::_setColUpperBound(int i, Value up) {
308 LEMON_ASSERT(up != -INF, "Invalid bound");
310 int b = glp_get_col_type(lp, i);
311 double lo = glp_get_col_lb(lp, i);
318 glp_set_col_bnds(lp, i, GLP_FR, lo, up);
322 glp_set_col_bnds(lp, i, GLP_LO, lo, up);
330 glp_set_col_bnds(lp, i, GLP_UP, lo, up);
333 glp_set_col_bnds(lp, i, GLP_UP, lo, up);
339 glp_set_col_bnds(lp, i, GLP_FX, lo, up);
341 glp_set_col_bnds(lp, i, GLP_DB, lo, up);
350 GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
351 int b = glp_get_col_type(lp, i);
356 return glp_get_col_ub(lp, i);
362 void GlpkBase::_setRowLowerBound(int i, Value lo) {
363 LEMON_ASSERT(lo != INF, "Invalid bound");
365 int b = glp_get_row_type(lp, i);
366 double up = glp_get_row_ub(lp, i);
371 glp_set_row_bnds(lp, i, GLP_FR, lo, up);
377 glp_set_row_bnds(lp, i, GLP_UP, lo, up);
386 glp_set_row_bnds(lp, i, GLP_LO, lo, up);
392 glp_set_row_bnds(lp, i, GLP_FX, lo, up);
394 glp_set_row_bnds(lp, i, GLP_DB, lo, up);
403 GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
404 int b = glp_get_row_type(lp, i);
409 return glp_get_row_lb(lp, i);
415 void GlpkBase::_setRowUpperBound(int i, Value up) {
416 LEMON_ASSERT(up != -INF, "Invalid bound");
418 int b = glp_get_row_type(lp, i);
419 double lo = glp_get_row_lb(lp, i);
426 glp_set_row_bnds(lp, i, GLP_FR, lo, up);
430 glp_set_row_bnds(lp, i, GLP_LO, lo, up);
438 glp_set_row_bnds(lp, i, GLP_UP, lo, up);
441 glp_set_row_bnds(lp, i, GLP_UP, lo, up);
447 glp_set_row_bnds(lp, i, GLP_FX, lo, up);
449 glp_set_row_bnds(lp, i, GLP_DB, lo, up);
457 GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
458 int b = glp_get_row_type(lp, i);
463 return glp_get_row_ub(lp, i);
469 void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
470 for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
471 glp_set_obj_coef(lp, i, 0.0);
473 for (ExprIterator it = b; it != e; ++it) {
474 glp_set_obj_coef(lp, it->first, it->second);
478 void GlpkBase::_getObjCoeffs(InsertIterator b) const {
479 for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
480 Value val = glp_get_obj_coef(lp, i);
482 *b = std::make_pair(i, val);
488 void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
489 //i = 0 means the constant term (shift)
490 glp_set_obj_coef(lp, i, obj_coef);
493 GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
494 //i = 0 means the constant term (shift)
495 return glp_get_obj_coef(lp, i);
498 void GlpkBase::_setSense(GlpkBase::Sense sense) {
501 glp_set_obj_dir(lp, GLP_MIN);
504 glp_set_obj_dir(lp, GLP_MAX);
509 GlpkBase::Sense GlpkBase::_getSense() const {
510 switch(glp_get_obj_dir(lp)) {
516 LEMON_ASSERT(false, "Wrong sense");
517 return GlpkBase::Sense();
521 void GlpkBase::_clear() {
525 void GlpkBase::freeEnv() {
529 void GlpkBase::_messageLevel(MessageLevel level) {
531 case MESSAGE_NOTHING:
532 _message_level = GLP_MSG_OFF;
535 _message_level = GLP_MSG_ERR;
537 case MESSAGE_WARNING:
538 _message_level = GLP_MSG_ERR;
541 _message_level = GLP_MSG_ON;
543 case MESSAGE_VERBOSE:
544 _message_level = GLP_MSG_ALL;
549 GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
554 : LpBase(), LpSolver(), GlpkBase() {
558 GlpkLp::GlpkLp(const GlpkLp& other)
559 : LpBase(other), LpSolver(other), GlpkBase(other) {
563 GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; }
564 GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); }
566 const char* GlpkLp::_solverName() const { return "GlpkLp"; }
568 void GlpkLp::_clear_temporals() {
573 GlpkLp::SolveExitStatus GlpkLp::_solve() {
574 return solvePrimal();
577 GlpkLp::SolveExitStatus GlpkLp::solvePrimal() {
581 glp_init_smcp(&smcp);
583 smcp.msg_lev = _message_level;
584 smcp.presolve = _presolve;
586 // If the basis is not valid we get an error return value.
587 // In this case we can try to create a new basis.
588 switch (glp_simplex(lp, &smcp)) {
595 glp_adv_basis(lp, 0);
597 if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
606 GlpkLp::SolveExitStatus GlpkLp::solveDual() {
610 glp_init_smcp(&smcp);
612 smcp.msg_lev = _message_level;
613 smcp.meth = GLP_DUAL;
614 smcp.presolve = _presolve;
616 // If the basis is not valid we get an error return value.
617 // In this case we can try to create a new basis.
618 switch (glp_simplex(lp, &smcp)) {
625 glp_adv_basis(lp, 0);
627 if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
635 GlpkLp::Value GlpkLp::_getPrimal(int i) const {
636 return glp_get_col_prim(lp, i);
639 GlpkLp::Value GlpkLp::_getDual(int i) const {
640 return glp_get_row_dual(lp, i);
643 GlpkLp::Value GlpkLp::_getPrimalValue() const {
644 return glp_get_obj_val(lp);
647 GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const {
648 switch (glp_get_col_stat(lp, i)) {
660 LEMON_ASSERT(false, "Wrong column status");
661 return GlpkLp::VarStatus();
665 GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const {
666 switch (glp_get_row_stat(lp, i)) {
678 LEMON_ASSERT(false, "Wrong row status");
679 return GlpkLp::VarStatus();
683 GlpkLp::Value GlpkLp::_getPrimalRay(int i) const {
684 if (_primal_ray.empty()) {
685 int row_num = glp_get_num_rows(lp);
686 int col_num = glp_get_num_cols(lp);
688 _primal_ray.resize(col_num + 1, 0.0);
690 int index = glp_get_unbnd_ray(lp);
692 // The primal ray is found in primal simplex second phase
693 LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
694 glp_get_col_stat(lp, index - row_num)) != GLP_BS,
697 bool negate = glp_get_obj_dir(lp) == GLP_MAX;
699 if (index > row_num) {
700 _primal_ray[index - row_num] = 1.0;
701 if (glp_get_col_dual(lp, index - row_num) > 0) {
705 if (glp_get_row_dual(lp, index) > 0) {
710 std::vector<int> ray_indexes(row_num + 1);
711 std::vector<Value> ray_values(row_num + 1);
712 int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
713 &ray_values.front());
715 for (int i = 1; i <= ray_length; ++i) {
716 if (ray_indexes[i] > row_num) {
717 _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
722 for (int i = 1; i <= col_num; ++i) {
723 _primal_ray[i] = - _primal_ray[i];
727 for (int i = 1; i <= col_num; ++i) {
728 _primal_ray[i] = glp_get_col_prim(lp, i);
732 return _primal_ray[i];
735 GlpkLp::Value GlpkLp::_getDualRay(int i) const {
736 if (_dual_ray.empty()) {
737 int row_num = glp_get_num_rows(lp);
739 _dual_ray.resize(row_num + 1, 0.0);
741 int index = glp_get_unbnd_ray(lp);
743 // The dual ray is found in dual simplex second phase
744 LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
745 glp_get_col_stat(lp, index - row_num)) == GLP_BS,
752 if (index > row_num) {
753 idx = glp_get_col_bind(lp, index - row_num);
754 if (glp_get_col_prim(lp, index - row_num) >
755 glp_get_col_ub(lp, index - row_num)) {
759 idx = glp_get_row_bind(lp, index);
760 if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
765 _dual_ray[idx] = negate ? - 1.0 : 1.0;
767 glp_btran(lp, &_dual_ray.front());
770 // The dual ray is found in primal simplex first phase
771 // We assume that the glpk minimizes the slack to get feasible solution
772 for (int i = 1; i <= row_num; ++i) {
773 int index = glp_get_bhead(lp, i);
774 if (index <= row_num) {
775 double res = glp_get_row_prim(lp, index);
776 if (res > glp_get_row_ub(lp, index) + eps) {
778 } else if (res < glp_get_row_lb(lp, index) - eps) {
783 _dual_ray[i] *= glp_get_rii(lp, index);
785 double res = glp_get_col_prim(lp, index - row_num);
786 if (res > glp_get_col_ub(lp, index - row_num) + eps) {
788 } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
793 _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
797 glp_btran(lp, &_dual_ray.front());
799 for (int i = 1; i <= row_num; ++i) {
800 _dual_ray[i] /= glp_get_rii(lp, i);
807 GlpkLp::ProblemType GlpkLp::_getPrimalType() const {
808 if (glp_get_status(lp) == GLP_OPT)
810 switch (glp_get_prim_stat(lp)) {
815 if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
823 LEMON_ASSERT(false, "Wrong primal type");
824 return GlpkLp::ProblemType();
828 GlpkLp::ProblemType GlpkLp::_getDualType() const {
829 if (glp_get_status(lp) == GLP_OPT)
831 switch (glp_get_dual_stat(lp)) {
836 if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
844 LEMON_ASSERT(false, "Wrong primal type");
845 return GlpkLp::ProblemType();
849 void GlpkLp::presolver(bool presolve) {
850 _presolve = presolve;
856 : LpBase(), MipSolver(), GlpkBase() {
859 GlpkMip::GlpkMip(const GlpkMip& other)
860 : LpBase(), MipSolver(), GlpkBase(other) {
863 void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
866 glp_set_col_kind(lp, i, GLP_IV);
869 glp_set_col_kind(lp, i, GLP_CV);
874 GlpkMip::ColTypes GlpkMip::_getColType(int i) const {
875 switch (glp_get_col_kind(lp, i)) {
885 GlpkMip::SolveExitStatus GlpkMip::_solve() {
887 glp_init_smcp(&smcp);
889 smcp.msg_lev = _message_level;
890 smcp.meth = GLP_DUAL;
892 // If the basis is not valid we get an error return value.
893 // In this case we can try to create a new basis.
894 switch (glp_simplex(lp, &smcp)) {
901 glp_adv_basis(lp, 0);
903 if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
909 if (glp_get_status(lp) != GLP_OPT) return SOLVED;
912 glp_init_iocp(&iocp);
914 iocp.msg_lev = _message_level;
916 if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
921 GlpkMip::ProblemType GlpkMip::_getType() const {
922 switch (glp_get_status(lp)) {
924 switch (glp_mip_status(lp)) {
934 LEMON_ASSERT(false, "Wrong problem type.");
935 return GlpkMip::ProblemType();
941 if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
947 LEMON_ASSERT(false, "Wrong problem type.");
948 return GlpkMip::ProblemType();
952 GlpkMip::Value GlpkMip::_getSol(int i) const {
953 return glp_mip_col_val(lp, i);
956 GlpkMip::Value GlpkMip::_getSolValue() const {
957 return glp_mip_obj_val(lp);
960 GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; }
961 GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); }
963 const char* GlpkMip::_solverName() const { return "GlpkMip"; }
965 } //END OF NAMESPACE LEMON