lemon/glpk.cc
changeset 708 994c7df296c9
parent 558 e7017ec2d5cd
child 785 8d281761dea4
     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