1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lemon/glpk.cc Thu Dec 10 17:05:35 2009 +0100
1.3 @@ -0,0 +1,967 @@
1.4 +/* -*- mode: C++; indent-tabs-mode: nil; -*-
1.5 + *
1.6 + * This file is a part of LEMON, a generic C++ optimization library.
1.7 + *
1.8 + * Copyright (C) 2003-2009
1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.11 + *
1.12 + * Permission to use, modify and distribute this software is granted
1.13 + * provided that this copyright notice appears in all copies. For
1.14 + * precise terms see the accompanying LICENSE file.
1.15 + *
1.16 + * This software is provided "AS IS" with no warranty of any kind,
1.17 + * express or implied, and with no claim as to its suitability for any
1.18 + * purpose.
1.19 + *
1.20 + */
1.21 +
1.22 +///\file
1.23 +///\brief Implementation of the LEMON GLPK LP and MIP solver interface.
1.24 +
1.25 +#include <lemon/glpk.h>
1.26 +#include <glpk.h>
1.27 +
1.28 +#include <lemon/assert.h>
1.29 +
1.30 +namespace lemon {
1.31 +
1.32 + // GlpkBase members
1.33 +
1.34 + GlpkBase::GlpkBase() : LpBase() {
1.35 + lp = glp_create_prob();
1.36 + glp_create_index(lp);
1.37 + messageLevel(MESSAGE_NOTHING);
1.38 + }
1.39 +
1.40 + GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
1.41 + lp = glp_create_prob();
1.42 + glp_copy_prob(lp, other.lp, GLP_ON);
1.43 + glp_create_index(lp);
1.44 + rows = other.rows;
1.45 + cols = other.cols;
1.46 + messageLevel(MESSAGE_NOTHING);
1.47 + }
1.48 +
1.49 + GlpkBase::~GlpkBase() {
1.50 + glp_delete_prob(lp);
1.51 + }
1.52 +
1.53 + int GlpkBase::_addCol() {
1.54 + int i = glp_add_cols(lp, 1);
1.55 + glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
1.56 + return i;
1.57 + }
1.58 +
1.59 + int GlpkBase::_addRow() {
1.60 + int i = glp_add_rows(lp, 1);
1.61 + glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
1.62 + return i;
1.63 + }
1.64 +
1.65 + void GlpkBase::_eraseCol(int i) {
1.66 + int ca[2];
1.67 + ca[1] = i;
1.68 + glp_del_cols(lp, 1, ca);
1.69 + }
1.70 +
1.71 + void GlpkBase::_eraseRow(int i) {
1.72 + int ra[2];
1.73 + ra[1] = i;
1.74 + glp_del_rows(lp, 1, ra);
1.75 + }
1.76 +
1.77 + void GlpkBase::_eraseColId(int i) {
1.78 + cols.eraseIndex(i);
1.79 + cols.shiftIndices(i);
1.80 + }
1.81 +
1.82 + void GlpkBase::_eraseRowId(int i) {
1.83 + rows.eraseIndex(i);
1.84 + rows.shiftIndices(i);
1.85 + }
1.86 +
1.87 + void GlpkBase::_getColName(int c, std::string& name) const {
1.88 + const char *str = glp_get_col_name(lp, c);
1.89 + if (str) name = str;
1.90 + else name.clear();
1.91 + }
1.92 +
1.93 + void GlpkBase::_setColName(int c, const std::string & name) {
1.94 + glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
1.95 +
1.96 + }
1.97 +
1.98 + int GlpkBase::_colByName(const std::string& name) const {
1.99 + int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
1.100 + return k > 0 ? k : -1;
1.101 + }
1.102 +
1.103 + void GlpkBase::_getRowName(int r, std::string& name) const {
1.104 + const char *str = glp_get_row_name(lp, r);
1.105 + if (str) name = str;
1.106 + else name.clear();
1.107 + }
1.108 +
1.109 + void GlpkBase::_setRowName(int r, const std::string & name) {
1.110 + glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
1.111 +
1.112 + }
1.113 +
1.114 + int GlpkBase::_rowByName(const std::string& name) const {
1.115 + int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
1.116 + return k > 0 ? k : -1;
1.117 + }
1.118 +
1.119 + void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
1.120 + std::vector<int> indexes;
1.121 + std::vector<Value> values;
1.122 +
1.123 + indexes.push_back(0);
1.124 + values.push_back(0);
1.125 +
1.126 + for(ExprIterator it = b; it != e; ++it) {
1.127 + indexes.push_back(it->first);
1.128 + values.push_back(it->second);
1.129 + }
1.130 +
1.131 + glp_set_mat_row(lp, i, values.size() - 1,
1.132 + &indexes.front(), &values.front());
1.133 + }
1.134 +
1.135 + void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
1.136 + int length = glp_get_mat_row(lp, ix, 0, 0);
1.137 +
1.138 + std::vector<int> indexes(length + 1);
1.139 + std::vector<Value> values(length + 1);
1.140 +
1.141 + glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
1.142 +
1.143 + for (int i = 1; i <= length; ++i) {
1.144 + *b = std::make_pair(indexes[i], values[i]);
1.145 + ++b;
1.146 + }
1.147 + }
1.148 +
1.149 + void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
1.150 + ExprIterator e) {
1.151 +
1.152 + std::vector<int> indexes;
1.153 + std::vector<Value> values;
1.154 +
1.155 + indexes.push_back(0);
1.156 + values.push_back(0);
1.157 +
1.158 + for(ExprIterator it = b; it != e; ++it) {
1.159 + indexes.push_back(it->first);
1.160 + values.push_back(it->second);
1.161 + }
1.162 +
1.163 + glp_set_mat_col(lp, ix, values.size() - 1,
1.164 + &indexes.front(), &values.front());
1.165 + }
1.166 +
1.167 + void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
1.168 + int length = glp_get_mat_col(lp, ix, 0, 0);
1.169 +
1.170 + std::vector<int> indexes(length + 1);
1.171 + std::vector<Value> values(length + 1);
1.172 +
1.173 + glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
1.174 +
1.175 + for (int i = 1; i <= length; ++i) {
1.176 + *b = std::make_pair(indexes[i], values[i]);
1.177 + ++b;
1.178 + }
1.179 + }
1.180 +
1.181 + void GlpkBase::_setCoeff(int ix, int jx, Value value) {
1.182 +
1.183 + if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
1.184 +
1.185 + int length = glp_get_mat_row(lp, ix, 0, 0);
1.186 +
1.187 + std::vector<int> indexes(length + 2);
1.188 + std::vector<Value> values(length + 2);
1.189 +
1.190 + glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
1.191 +
1.192 + //The following code does not suppose that the elements of the
1.193 + //array indexes are sorted
1.194 + bool found = false;
1.195 + for (int i = 1; i <= length; ++i) {
1.196 + if (indexes[i] == jx) {
1.197 + found = true;
1.198 + values[i] = value;
1.199 + break;
1.200 + }
1.201 + }
1.202 + if (!found) {
1.203 + ++length;
1.204 + indexes[length] = jx;
1.205 + values[length] = value;
1.206 + }
1.207 +
1.208 + glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
1.209 +
1.210 + } else {
1.211 +
1.212 + int length = glp_get_mat_col(lp, jx, 0, 0);
1.213 +
1.214 + std::vector<int> indexes(length + 2);
1.215 + std::vector<Value> values(length + 2);
1.216 +
1.217 + glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
1.218 +
1.219 + //The following code does not suppose that the elements of the
1.220 + //array indexes are sorted
1.221 + bool found = false;
1.222 + for (int i = 1; i <= length; ++i) {
1.223 + if (indexes[i] == ix) {
1.224 + found = true;
1.225 + values[i] = value;
1.226 + break;
1.227 + }
1.228 + }
1.229 + if (!found) {
1.230 + ++length;
1.231 + indexes[length] = ix;
1.232 + values[length] = value;
1.233 + }
1.234 +
1.235 + glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
1.236 + }
1.237 +
1.238 + }
1.239 +
1.240 + GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
1.241 +
1.242 + int length = glp_get_mat_row(lp, ix, 0, 0);
1.243 +
1.244 + std::vector<int> indexes(length + 1);
1.245 + std::vector<Value> values(length + 1);
1.246 +
1.247 + glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
1.248 +
1.249 + for (int i = 1; i <= length; ++i) {
1.250 + if (indexes[i] == jx) {
1.251 + return values[i];
1.252 + }
1.253 + }
1.254 +
1.255 + return 0;
1.256 + }
1.257 +
1.258 + void GlpkBase::_setColLowerBound(int i, Value lo) {
1.259 + LEMON_ASSERT(lo != INF, "Invalid bound");
1.260 +
1.261 + int b = glp_get_col_type(lp, i);
1.262 + double up = glp_get_col_ub(lp, i);
1.263 + if (lo == -INF) {
1.264 + switch (b) {
1.265 + case GLP_FR:
1.266 + case GLP_LO:
1.267 + glp_set_col_bnds(lp, i, GLP_FR, lo, up);
1.268 + break;
1.269 + case GLP_UP:
1.270 + break;
1.271 + case GLP_DB:
1.272 + case GLP_FX:
1.273 + glp_set_col_bnds(lp, i, GLP_UP, lo, up);
1.274 + break;
1.275 + default:
1.276 + break;
1.277 + }
1.278 + } else {
1.279 + switch (b) {
1.280 + case GLP_FR:
1.281 + case GLP_LO:
1.282 + glp_set_col_bnds(lp, i, GLP_LO, lo, up);
1.283 + break;
1.284 + case GLP_UP:
1.285 + case GLP_DB:
1.286 + case GLP_FX:
1.287 + if (lo == up)
1.288 + glp_set_col_bnds(lp, i, GLP_FX, lo, up);
1.289 + else
1.290 + glp_set_col_bnds(lp, i, GLP_DB, lo, up);
1.291 + break;
1.292 + default:
1.293 + break;
1.294 + }
1.295 + }
1.296 + }
1.297 +
1.298 + GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
1.299 + int b = glp_get_col_type(lp, i);
1.300 + switch (b) {
1.301 + case GLP_LO:
1.302 + case GLP_DB:
1.303 + case GLP_FX:
1.304 + return glp_get_col_lb(lp, i);
1.305 + default:
1.306 + return -INF;
1.307 + }
1.308 + }
1.309 +
1.310 + void GlpkBase::_setColUpperBound(int i, Value up) {
1.311 + LEMON_ASSERT(up != -INF, "Invalid bound");
1.312 +
1.313 + int b = glp_get_col_type(lp, i);
1.314 + double lo = glp_get_col_lb(lp, i);
1.315 + if (up == INF) {
1.316 + switch (b) {
1.317 + case GLP_FR:
1.318 + case GLP_LO:
1.319 + break;
1.320 + case GLP_UP:
1.321 + glp_set_col_bnds(lp, i, GLP_FR, lo, up);
1.322 + break;
1.323 + case GLP_DB:
1.324 + case GLP_FX:
1.325 + glp_set_col_bnds(lp, i, GLP_LO, lo, up);
1.326 + break;
1.327 + default:
1.328 + break;
1.329 + }
1.330 + } else {
1.331 + switch (b) {
1.332 + case GLP_FR:
1.333 + glp_set_col_bnds(lp, i, GLP_UP, lo, up);
1.334 + break;
1.335 + case GLP_UP:
1.336 + glp_set_col_bnds(lp, i, GLP_UP, lo, up);
1.337 + break;
1.338 + case GLP_LO:
1.339 + case GLP_DB:
1.340 + case GLP_FX:
1.341 + if (lo == up)
1.342 + glp_set_col_bnds(lp, i, GLP_FX, lo, up);
1.343 + else
1.344 + glp_set_col_bnds(lp, i, GLP_DB, lo, up);
1.345 + break;
1.346 + default:
1.347 + break;
1.348 + }
1.349 + }
1.350 +
1.351 + }
1.352 +
1.353 + GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
1.354 + int b = glp_get_col_type(lp, i);
1.355 + switch (b) {
1.356 + case GLP_UP:
1.357 + case GLP_DB:
1.358 + case GLP_FX:
1.359 + return glp_get_col_ub(lp, i);
1.360 + default:
1.361 + return INF;
1.362 + }
1.363 + }
1.364 +
1.365 + void GlpkBase::_setRowLowerBound(int i, Value lo) {
1.366 + LEMON_ASSERT(lo != INF, "Invalid bound");
1.367 +
1.368 + int b = glp_get_row_type(lp, i);
1.369 + double up = glp_get_row_ub(lp, i);
1.370 + if (lo == -INF) {
1.371 + switch (b) {
1.372 + case GLP_FR:
1.373 + case GLP_LO:
1.374 + glp_set_row_bnds(lp, i, GLP_FR, lo, up);
1.375 + break;
1.376 + case GLP_UP:
1.377 + break;
1.378 + case GLP_DB:
1.379 + case GLP_FX:
1.380 + glp_set_row_bnds(lp, i, GLP_UP, lo, up);
1.381 + break;
1.382 + default:
1.383 + break;
1.384 + }
1.385 + } else {
1.386 + switch (b) {
1.387 + case GLP_FR:
1.388 + case GLP_LO:
1.389 + glp_set_row_bnds(lp, i, GLP_LO, lo, up);
1.390 + break;
1.391 + case GLP_UP:
1.392 + case GLP_DB:
1.393 + case GLP_FX:
1.394 + if (lo == up)
1.395 + glp_set_row_bnds(lp, i, GLP_FX, lo, up);
1.396 + else
1.397 + glp_set_row_bnds(lp, i, GLP_DB, lo, up);
1.398 + break;
1.399 + default:
1.400 + break;
1.401 + }
1.402 + }
1.403 +
1.404 + }
1.405 +
1.406 + GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
1.407 + int b = glp_get_row_type(lp, i);
1.408 + switch (b) {
1.409 + case GLP_LO:
1.410 + case GLP_DB:
1.411 + case GLP_FX:
1.412 + return glp_get_row_lb(lp, i);
1.413 + default:
1.414 + return -INF;
1.415 + }
1.416 + }
1.417 +
1.418 + void GlpkBase::_setRowUpperBound(int i, Value up) {
1.419 + LEMON_ASSERT(up != -INF, "Invalid bound");
1.420 +
1.421 + int b = glp_get_row_type(lp, i);
1.422 + double lo = glp_get_row_lb(lp, i);
1.423 + if (up == INF) {
1.424 + switch (b) {
1.425 + case GLP_FR:
1.426 + case GLP_LO:
1.427 + break;
1.428 + case GLP_UP:
1.429 + glp_set_row_bnds(lp, i, GLP_FR, lo, up);
1.430 + break;
1.431 + case GLP_DB:
1.432 + case GLP_FX:
1.433 + glp_set_row_bnds(lp, i, GLP_LO, lo, up);
1.434 + break;
1.435 + default:
1.436 + break;
1.437 + }
1.438 + } else {
1.439 + switch (b) {
1.440 + case GLP_FR:
1.441 + glp_set_row_bnds(lp, i, GLP_UP, lo, up);
1.442 + break;
1.443 + case GLP_UP:
1.444 + glp_set_row_bnds(lp, i, GLP_UP, lo, up);
1.445 + break;
1.446 + case GLP_LO:
1.447 + case GLP_DB:
1.448 + case GLP_FX:
1.449 + if (lo == up)
1.450 + glp_set_row_bnds(lp, i, GLP_FX, lo, up);
1.451 + else
1.452 + glp_set_row_bnds(lp, i, GLP_DB, lo, up);
1.453 + break;
1.454 + default:
1.455 + break;
1.456 + }
1.457 + }
1.458 + }
1.459 +
1.460 + GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
1.461 + int b = glp_get_row_type(lp, i);
1.462 + switch (b) {
1.463 + case GLP_UP:
1.464 + case GLP_DB:
1.465 + case GLP_FX:
1.466 + return glp_get_row_ub(lp, i);
1.467 + default:
1.468 + return INF;
1.469 + }
1.470 + }
1.471 +
1.472 + void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
1.473 + for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
1.474 + glp_set_obj_coef(lp, i, 0.0);
1.475 + }
1.476 + for (ExprIterator it = b; it != e; ++it) {
1.477 + glp_set_obj_coef(lp, it->first, it->second);
1.478 + }
1.479 + }
1.480 +
1.481 + void GlpkBase::_getObjCoeffs(InsertIterator b) const {
1.482 + for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
1.483 + Value val = glp_get_obj_coef(lp, i);
1.484 + if (val != 0.0) {
1.485 + *b = std::make_pair(i, val);
1.486 + ++b;
1.487 + }
1.488 + }
1.489 + }
1.490 +
1.491 + void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
1.492 + //i = 0 means the constant term (shift)
1.493 + glp_set_obj_coef(lp, i, obj_coef);
1.494 + }
1.495 +
1.496 + GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
1.497 + //i = 0 means the constant term (shift)
1.498 + return glp_get_obj_coef(lp, i);
1.499 + }
1.500 +
1.501 + void GlpkBase::_setSense(GlpkBase::Sense sense) {
1.502 + switch (sense) {
1.503 + case MIN:
1.504 + glp_set_obj_dir(lp, GLP_MIN);
1.505 + break;
1.506 + case MAX:
1.507 + glp_set_obj_dir(lp, GLP_MAX);
1.508 + break;
1.509 + }
1.510 + }
1.511 +
1.512 + GlpkBase::Sense GlpkBase::_getSense() const {
1.513 + switch(glp_get_obj_dir(lp)) {
1.514 + case GLP_MIN:
1.515 + return MIN;
1.516 + case GLP_MAX:
1.517 + return MAX;
1.518 + default:
1.519 + LEMON_ASSERT(false, "Wrong sense");
1.520 + return GlpkBase::Sense();
1.521 + }
1.522 + }
1.523 +
1.524 + void GlpkBase::_clear() {
1.525 + glp_erase_prob(lp);
1.526 + rows.clear();
1.527 + cols.clear();
1.528 + }
1.529 +
1.530 + void GlpkBase::freeEnv() {
1.531 + glp_free_env();
1.532 + }
1.533 +
1.534 + void GlpkBase::_messageLevel(MessageLevel level) {
1.535 + switch (level) {
1.536 + case MESSAGE_NOTHING:
1.537 + _message_level = GLP_MSG_OFF;
1.538 + break;
1.539 + case MESSAGE_ERROR:
1.540 + _message_level = GLP_MSG_ERR;
1.541 + break;
1.542 + case MESSAGE_WARNING:
1.543 + _message_level = GLP_MSG_ERR;
1.544 + break;
1.545 + case MESSAGE_NORMAL:
1.546 + _message_level = GLP_MSG_ON;
1.547 + break;
1.548 + case MESSAGE_VERBOSE:
1.549 + _message_level = GLP_MSG_ALL;
1.550 + break;
1.551 + }
1.552 + }
1.553 +
1.554 + GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
1.555 +
1.556 + // GlpkLp members
1.557 +
1.558 + GlpkLp::GlpkLp()
1.559 + : LpBase(), LpSolver(), GlpkBase() {
1.560 + presolver(false);
1.561 + }
1.562 +
1.563 + GlpkLp::GlpkLp(const GlpkLp& other)
1.564 + : LpBase(other), LpSolver(other), GlpkBase(other) {
1.565 + presolver(false);
1.566 + }
1.567 +
1.568 + GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; }
1.569 + GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); }
1.570 +
1.571 + const char* GlpkLp::_solverName() const { return "GlpkLp"; }
1.572 +
1.573 + void GlpkLp::_clear_temporals() {
1.574 + _primal_ray.clear();
1.575 + _dual_ray.clear();
1.576 + }
1.577 +
1.578 + GlpkLp::SolveExitStatus GlpkLp::_solve() {
1.579 + return solvePrimal();
1.580 + }
1.581 +
1.582 + GlpkLp::SolveExitStatus GlpkLp::solvePrimal() {
1.583 + _clear_temporals();
1.584 +
1.585 + glp_smcp smcp;
1.586 + glp_init_smcp(&smcp);
1.587 +
1.588 + smcp.msg_lev = _message_level;
1.589 + smcp.presolve = _presolve;
1.590 +
1.591 + // If the basis is not valid we get an error return value.
1.592 + // In this case we can try to create a new basis.
1.593 + switch (glp_simplex(lp, &smcp)) {
1.594 + case 0:
1.595 + break;
1.596 + case GLP_EBADB:
1.597 + case GLP_ESING:
1.598 + case GLP_ECOND:
1.599 + glp_term_out(false);
1.600 + glp_adv_basis(lp, 0);
1.601 + glp_term_out(true);
1.602 + if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
1.603 + break;
1.604 + default:
1.605 + return UNSOLVED;
1.606 + }
1.607 +
1.608 + return SOLVED;
1.609 + }
1.610 +
1.611 + GlpkLp::SolveExitStatus GlpkLp::solveDual() {
1.612 + _clear_temporals();
1.613 +
1.614 + glp_smcp smcp;
1.615 + glp_init_smcp(&smcp);
1.616 +
1.617 + smcp.msg_lev = _message_level;
1.618 + smcp.meth = GLP_DUAL;
1.619 + smcp.presolve = _presolve;
1.620 +
1.621 + // If the basis is not valid we get an error return value.
1.622 + // In this case we can try to create a new basis.
1.623 + switch (glp_simplex(lp, &smcp)) {
1.624 + case 0:
1.625 + break;
1.626 + case GLP_EBADB:
1.627 + case GLP_ESING:
1.628 + case GLP_ECOND:
1.629 + glp_term_out(false);
1.630 + glp_adv_basis(lp, 0);
1.631 + glp_term_out(true);
1.632 + if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
1.633 + break;
1.634 + default:
1.635 + return UNSOLVED;
1.636 + }
1.637 + return SOLVED;
1.638 + }
1.639 +
1.640 + GlpkLp::Value GlpkLp::_getPrimal(int i) const {
1.641 + return glp_get_col_prim(lp, i);
1.642 + }
1.643 +
1.644 + GlpkLp::Value GlpkLp::_getDual(int i) const {
1.645 + return glp_get_row_dual(lp, i);
1.646 + }
1.647 +
1.648 + GlpkLp::Value GlpkLp::_getPrimalValue() const {
1.649 + return glp_get_obj_val(lp);
1.650 + }
1.651 +
1.652 + GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const {
1.653 + switch (glp_get_col_stat(lp, i)) {
1.654 + case GLP_BS:
1.655 + return BASIC;
1.656 + case GLP_UP:
1.657 + return UPPER;
1.658 + case GLP_LO:
1.659 + return LOWER;
1.660 + case GLP_NF:
1.661 + return FREE;
1.662 + case GLP_NS:
1.663 + return FIXED;
1.664 + default:
1.665 + LEMON_ASSERT(false, "Wrong column status");
1.666 + return GlpkLp::VarStatus();
1.667 + }
1.668 + }
1.669 +
1.670 + GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const {
1.671 + switch (glp_get_row_stat(lp, i)) {
1.672 + case GLP_BS:
1.673 + return BASIC;
1.674 + case GLP_UP:
1.675 + return UPPER;
1.676 + case GLP_LO:
1.677 + return LOWER;
1.678 + case GLP_NF:
1.679 + return FREE;
1.680 + case GLP_NS:
1.681 + return FIXED;
1.682 + default:
1.683 + LEMON_ASSERT(false, "Wrong row status");
1.684 + return GlpkLp::VarStatus();
1.685 + }
1.686 + }
1.687 +
1.688 + GlpkLp::Value GlpkLp::_getPrimalRay(int i) const {
1.689 + if (_primal_ray.empty()) {
1.690 + int row_num = glp_get_num_rows(lp);
1.691 + int col_num = glp_get_num_cols(lp);
1.692 +
1.693 + _primal_ray.resize(col_num + 1, 0.0);
1.694 +
1.695 + int index = glp_get_unbnd_ray(lp);
1.696 + if (index != 0) {
1.697 + // The primal ray is found in primal simplex second phase
1.698 + LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
1.699 + glp_get_col_stat(lp, index - row_num)) != GLP_BS,
1.700 + "Wrong primal ray");
1.701 +
1.702 + bool negate = glp_get_obj_dir(lp) == GLP_MAX;
1.703 +
1.704 + if (index > row_num) {
1.705 + _primal_ray[index - row_num] = 1.0;
1.706 + if (glp_get_col_dual(lp, index - row_num) > 0) {
1.707 + negate = !negate;
1.708 + }
1.709 + } else {
1.710 + if (glp_get_row_dual(lp, index) > 0) {
1.711 + negate = !negate;
1.712 + }
1.713 + }
1.714 +
1.715 + std::vector<int> ray_indexes(row_num + 1);
1.716 + std::vector<Value> ray_values(row_num + 1);
1.717 + int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
1.718 + &ray_values.front());
1.719 +
1.720 + for (int i = 1; i <= ray_length; ++i) {
1.721 + if (ray_indexes[i] > row_num) {
1.722 + _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
1.723 + }
1.724 + }
1.725 +
1.726 + if (negate) {
1.727 + for (int i = 1; i <= col_num; ++i) {
1.728 + _primal_ray[i] = - _primal_ray[i];
1.729 + }
1.730 + }
1.731 + } else {
1.732 + for (int i = 1; i <= col_num; ++i) {
1.733 + _primal_ray[i] = glp_get_col_prim(lp, i);
1.734 + }
1.735 + }
1.736 + }
1.737 + return _primal_ray[i];
1.738 + }
1.739 +
1.740 + GlpkLp::Value GlpkLp::_getDualRay(int i) const {
1.741 + if (_dual_ray.empty()) {
1.742 + int row_num = glp_get_num_rows(lp);
1.743 +
1.744 + _dual_ray.resize(row_num + 1, 0.0);
1.745 +
1.746 + int index = glp_get_unbnd_ray(lp);
1.747 + if (index != 0) {
1.748 + // The dual ray is found in dual simplex second phase
1.749 + LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
1.750 + glp_get_col_stat(lp, index - row_num)) == GLP_BS,
1.751 +
1.752 + "Wrong dual ray");
1.753 +
1.754 + int idx;
1.755 + bool negate = false;
1.756 +
1.757 + if (index > row_num) {
1.758 + idx = glp_get_col_bind(lp, index - row_num);
1.759 + if (glp_get_col_prim(lp, index - row_num) >
1.760 + glp_get_col_ub(lp, index - row_num)) {
1.761 + negate = true;
1.762 + }
1.763 + } else {
1.764 + idx = glp_get_row_bind(lp, index);
1.765 + if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
1.766 + negate = true;
1.767 + }
1.768 + }
1.769 +
1.770 + _dual_ray[idx] = negate ? - 1.0 : 1.0;
1.771 +
1.772 + glp_btran(lp, &_dual_ray.front());
1.773 + } else {
1.774 + double eps = 1e-7;
1.775 + // The dual ray is found in primal simplex first phase
1.776 + // We assume that the glpk minimizes the slack to get feasible solution
1.777 + for (int i = 1; i <= row_num; ++i) {
1.778 + int index = glp_get_bhead(lp, i);
1.779 + if (index <= row_num) {
1.780 + double res = glp_get_row_prim(lp, index);
1.781 + if (res > glp_get_row_ub(lp, index) + eps) {
1.782 + _dual_ray[i] = -1;
1.783 + } else if (res < glp_get_row_lb(lp, index) - eps) {
1.784 + _dual_ray[i] = 1;
1.785 + } else {
1.786 + _dual_ray[i] = 0;
1.787 + }
1.788 + _dual_ray[i] *= glp_get_rii(lp, index);
1.789 + } else {
1.790 + double res = glp_get_col_prim(lp, index - row_num);
1.791 + if (res > glp_get_col_ub(lp, index - row_num) + eps) {
1.792 + _dual_ray[i] = -1;
1.793 + } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
1.794 + _dual_ray[i] = 1;
1.795 + } else {
1.796 + _dual_ray[i] = 0;
1.797 + }
1.798 + _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
1.799 + }
1.800 + }
1.801 +
1.802 + glp_btran(lp, &_dual_ray.front());
1.803 +
1.804 + for (int i = 1; i <= row_num; ++i) {
1.805 + _dual_ray[i] /= glp_get_rii(lp, i);
1.806 + }
1.807 + }
1.808 + }
1.809 + return _dual_ray[i];
1.810 + }
1.811 +
1.812 + GlpkLp::ProblemType GlpkLp::_getPrimalType() const {
1.813 + if (glp_get_status(lp) == GLP_OPT)
1.814 + return OPTIMAL;
1.815 + switch (glp_get_prim_stat(lp)) {
1.816 + case GLP_UNDEF:
1.817 + return UNDEFINED;
1.818 + case GLP_FEAS:
1.819 + case GLP_INFEAS:
1.820 + if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
1.821 + return UNBOUNDED;
1.822 + } else {
1.823 + return UNDEFINED;
1.824 + }
1.825 + case GLP_NOFEAS:
1.826 + return INFEASIBLE;
1.827 + default:
1.828 + LEMON_ASSERT(false, "Wrong primal type");
1.829 + return GlpkLp::ProblemType();
1.830 + }
1.831 + }
1.832 +
1.833 + GlpkLp::ProblemType GlpkLp::_getDualType() const {
1.834 + if (glp_get_status(lp) == GLP_OPT)
1.835 + return OPTIMAL;
1.836 + switch (glp_get_dual_stat(lp)) {
1.837 + case GLP_UNDEF:
1.838 + return UNDEFINED;
1.839 + case GLP_FEAS:
1.840 + case GLP_INFEAS:
1.841 + if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
1.842 + return UNBOUNDED;
1.843 + } else {
1.844 + return UNDEFINED;
1.845 + }
1.846 + case GLP_NOFEAS:
1.847 + return INFEASIBLE;
1.848 + default:
1.849 + LEMON_ASSERT(false, "Wrong primal type");
1.850 + return GlpkLp::ProblemType();
1.851 + }
1.852 + }
1.853 +
1.854 + void GlpkLp::presolver(bool presolve) {
1.855 + _presolve = presolve;
1.856 + }
1.857 +
1.858 + // GlpkMip members
1.859 +
1.860 + GlpkMip::GlpkMip()
1.861 + : LpBase(), MipSolver(), GlpkBase() {
1.862 + }
1.863 +
1.864 + GlpkMip::GlpkMip(const GlpkMip& other)
1.865 + : LpBase(), MipSolver(), GlpkBase(other) {
1.866 + }
1.867 +
1.868 + void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
1.869 + switch (col_type) {
1.870 + case INTEGER:
1.871 + glp_set_col_kind(lp, i, GLP_IV);
1.872 + break;
1.873 + case REAL:
1.874 + glp_set_col_kind(lp, i, GLP_CV);
1.875 + break;
1.876 + }
1.877 + }
1.878 +
1.879 + GlpkMip::ColTypes GlpkMip::_getColType(int i) const {
1.880 + switch (glp_get_col_kind(lp, i)) {
1.881 + case GLP_IV:
1.882 + case GLP_BV:
1.883 + return INTEGER;
1.884 + default:
1.885 + return REAL;
1.886 + }
1.887 +
1.888 + }
1.889 +
1.890 + GlpkMip::SolveExitStatus GlpkMip::_solve() {
1.891 + glp_smcp smcp;
1.892 + glp_init_smcp(&smcp);
1.893 +
1.894 + smcp.msg_lev = _message_level;
1.895 + smcp.meth = GLP_DUAL;
1.896 +
1.897 + // If the basis is not valid we get an error return value.
1.898 + // In this case we can try to create a new basis.
1.899 + switch (glp_simplex(lp, &smcp)) {
1.900 + case 0:
1.901 + break;
1.902 + case GLP_EBADB:
1.903 + case GLP_ESING:
1.904 + case GLP_ECOND:
1.905 + glp_term_out(false);
1.906 + glp_adv_basis(lp, 0);
1.907 + glp_term_out(true);
1.908 + if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
1.909 + break;
1.910 + default:
1.911 + return UNSOLVED;
1.912 + }
1.913 +
1.914 + if (glp_get_status(lp) != GLP_OPT) return SOLVED;
1.915 +
1.916 + glp_iocp iocp;
1.917 + glp_init_iocp(&iocp);
1.918 +
1.919 + iocp.msg_lev = _message_level;
1.920 +
1.921 + if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
1.922 + return SOLVED;
1.923 + }
1.924 +
1.925 +
1.926 + GlpkMip::ProblemType GlpkMip::_getType() const {
1.927 + switch (glp_get_status(lp)) {
1.928 + case GLP_OPT:
1.929 + switch (glp_mip_status(lp)) {
1.930 + case GLP_UNDEF:
1.931 + return UNDEFINED;
1.932 + case GLP_NOFEAS:
1.933 + return INFEASIBLE;
1.934 + case GLP_FEAS:
1.935 + return FEASIBLE;
1.936 + case GLP_OPT:
1.937 + return OPTIMAL;
1.938 + default:
1.939 + LEMON_ASSERT(false, "Wrong problem type.");
1.940 + return GlpkMip::ProblemType();
1.941 + }
1.942 + case GLP_NOFEAS:
1.943 + return INFEASIBLE;
1.944 + case GLP_INFEAS:
1.945 + case GLP_FEAS:
1.946 + if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
1.947 + return UNBOUNDED;
1.948 + } else {
1.949 + return UNDEFINED;
1.950 + }
1.951 + default:
1.952 + LEMON_ASSERT(false, "Wrong problem type.");
1.953 + return GlpkMip::ProblemType();
1.954 + }
1.955 + }
1.956 +
1.957 + GlpkMip::Value GlpkMip::_getSol(int i) const {
1.958 + return glp_mip_col_val(lp, i);
1.959 + }
1.960 +
1.961 + GlpkMip::Value GlpkMip::_getSolValue() const {
1.962 + return glp_mip_obj_val(lp);
1.963 + }
1.964 +
1.965 + GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; }
1.966 + GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); }
1.967 +
1.968 + const char* GlpkMip::_solverName() const { return "GlpkMip"; }
1.969 +
1.970 +} //END OF NAMESPACE LEMON