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