lemon/glpk.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 746 e4554cd6b2bf
child 989 38e1d4383262
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
alpar@461
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
alpar@461
     2
 *
alpar@461
     3
 * This file is a part of LEMON, a generic C++ optimization library.
alpar@461
     4
 *
alpar@877
     5
 * Copyright (C) 2003-2010
alpar@461
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@461
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@461
     8
 *
alpar@461
     9
 * Permission to use, modify and distribute this software is granted
alpar@461
    10
 * provided that this copyright notice appears in all copies. For
alpar@461
    11
 * precise terms see the accompanying LICENSE file.
alpar@461
    12
 *
alpar@461
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@461
    14
 * express or implied, and with no claim as to its suitability for any
alpar@461
    15
 * purpose.
alpar@461
    16
 *
alpar@461
    17
 */
alpar@461
    18
alpar@461
    19
///\file
alpar@461
    20
///\brief Implementation of the LEMON GLPK LP and MIP solver interface.
alpar@461
    21
alpar@461
    22
#include <lemon/glpk.h>
alpar@461
    23
#include <glpk.h>
alpar@461
    24
alpar@461
    25
#include <lemon/assert.h>
alpar@461
    26
alpar@461
    27
namespace lemon {
alpar@461
    28
alpar@461
    29
  // GlpkBase members
alpar@461
    30
alpar@461
    31
  GlpkBase::GlpkBase() : LpBase() {
alpar@461
    32
    lp = glp_create_prob();
alpar@461
    33
    glp_create_index(lp);
deba@576
    34
    messageLevel(MESSAGE_NOTHING);
alpar@461
    35
  }
alpar@461
    36
alpar@461
    37
  GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() {
alpar@461
    38
    lp = glp_create_prob();
alpar@461
    39
    glp_copy_prob(lp, other.lp, GLP_ON);
alpar@461
    40
    glp_create_index(lp);
alpar@461
    41
    rows = other.rows;
alpar@461
    42
    cols = other.cols;
deba@576
    43
    messageLevel(MESSAGE_NOTHING);
alpar@461
    44
  }
alpar@461
    45
alpar@461
    46
  GlpkBase::~GlpkBase() {
alpar@461
    47
    glp_delete_prob(lp);
alpar@461
    48
  }
alpar@461
    49
alpar@461
    50
  int GlpkBase::_addCol() {
alpar@461
    51
    int i = glp_add_cols(lp, 1);
alpar@461
    52
    glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0);
alpar@461
    53
    return i;
alpar@461
    54
  }
alpar@461
    55
alpar@461
    56
  int GlpkBase::_addRow() {
alpar@461
    57
    int i = glp_add_rows(lp, 1);
alpar@461
    58
    glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0);
alpar@461
    59
    return i;
alpar@461
    60
  }
alpar@461
    61
alpar@877
    62
  int GlpkBase::_addRow(Value lo, ExprIterator b,
deba@746
    63
                        ExprIterator e, Value up) {
deba@746
    64
    int i = glp_add_rows(lp, 1);
deba@746
    65
deba@746
    66
    if (lo == -INF) {
deba@746
    67
      if (up == INF) {
deba@746
    68
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
deba@746
    69
      } else {
deba@746
    70
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
alpar@877
    71
      }
deba@746
    72
    } else {
deba@746
    73
      if (up == INF) {
deba@746
    74
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
alpar@877
    75
      } else if (lo != up) {
deba@746
    76
        glp_set_row_bnds(lp, i, GLP_DB, lo, up);
deba@746
    77
      } else {
deba@746
    78
        glp_set_row_bnds(lp, i, GLP_FX, lo, up);
deba@746
    79
      }
deba@746
    80
    }
deba@746
    81
deba@746
    82
    std::vector<int> indexes;
deba@746
    83
    std::vector<Value> values;
deba@746
    84
deba@746
    85
    indexes.push_back(0);
deba@746
    86
    values.push_back(0);
deba@746
    87
deba@746
    88
    for(ExprIterator it = b; it != e; ++it) {
deba@746
    89
      indexes.push_back(it->first);
deba@746
    90
      values.push_back(it->second);
deba@746
    91
    }
deba@746
    92
deba@746
    93
    glp_set_mat_row(lp, i, values.size() - 1,
deba@746
    94
                    &indexes.front(), &values.front());
deba@746
    95
    return i;
deba@746
    96
  }
deba@746
    97
alpar@461
    98
  void GlpkBase::_eraseCol(int i) {
alpar@461
    99
    int ca[2];
alpar@461
   100
    ca[1] = i;
alpar@461
   101
    glp_del_cols(lp, 1, ca);
alpar@461
   102
  }
alpar@461
   103
alpar@461
   104
  void GlpkBase::_eraseRow(int i) {
alpar@461
   105
    int ra[2];
alpar@461
   106
    ra[1] = i;
alpar@461
   107
    glp_del_rows(lp, 1, ra);
alpar@461
   108
  }
alpar@461
   109
alpar@461
   110
  void GlpkBase::_eraseColId(int i) {
alpar@461
   111
    cols.eraseIndex(i);
alpar@461
   112
    cols.shiftIndices(i);
alpar@461
   113
  }
alpar@461
   114
alpar@461
   115
  void GlpkBase::_eraseRowId(int i) {
alpar@461
   116
    rows.eraseIndex(i);
alpar@461
   117
    rows.shiftIndices(i);
alpar@461
   118
  }
alpar@461
   119
alpar@461
   120
  void GlpkBase::_getColName(int c, std::string& name) const {
alpar@461
   121
    const char *str = glp_get_col_name(lp, c);
alpar@461
   122
    if (str) name = str;
alpar@461
   123
    else name.clear();
alpar@461
   124
  }
alpar@461
   125
alpar@461
   126
  void GlpkBase::_setColName(int c, const std::string & name) {
alpar@461
   127
    glp_set_col_name(lp, c, const_cast<char*>(name.c_str()));
alpar@461
   128
alpar@461
   129
  }
alpar@461
   130
alpar@461
   131
  int GlpkBase::_colByName(const std::string& name) const {
alpar@461
   132
    int k = glp_find_col(lp, const_cast<char*>(name.c_str()));
alpar@461
   133
    return k > 0 ? k : -1;
alpar@461
   134
  }
alpar@461
   135
alpar@461
   136
  void GlpkBase::_getRowName(int r, std::string& name) const {
alpar@461
   137
    const char *str = glp_get_row_name(lp, r);
alpar@461
   138
    if (str) name = str;
alpar@461
   139
    else name.clear();
alpar@461
   140
  }
alpar@461
   141
alpar@461
   142
  void GlpkBase::_setRowName(int r, const std::string & name) {
alpar@461
   143
    glp_set_row_name(lp, r, const_cast<char*>(name.c_str()));
alpar@461
   144
alpar@461
   145
  }
alpar@461
   146
alpar@461
   147
  int GlpkBase::_rowByName(const std::string& name) const {
alpar@461
   148
    int k = glp_find_row(lp, const_cast<char*>(name.c_str()));
alpar@461
   149
    return k > 0 ? k : -1;
alpar@461
   150
  }
alpar@461
   151
alpar@461
   152
  void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
alpar@461
   153
    std::vector<int> indexes;
alpar@461
   154
    std::vector<Value> values;
alpar@461
   155
alpar@461
   156
    indexes.push_back(0);
alpar@461
   157
    values.push_back(0);
alpar@461
   158
alpar@461
   159
    for(ExprIterator it = b; it != e; ++it) {
alpar@461
   160
      indexes.push_back(it->first);
alpar@461
   161
      values.push_back(it->second);
alpar@461
   162
    }
alpar@461
   163
alpar@461
   164
    glp_set_mat_row(lp, i, values.size() - 1,
alpar@461
   165
                    &indexes.front(), &values.front());
alpar@461
   166
  }
alpar@461
   167
alpar@461
   168
  void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const {
alpar@461
   169
    int length = glp_get_mat_row(lp, ix, 0, 0);
alpar@461
   170
alpar@461
   171
    std::vector<int> indexes(length + 1);
alpar@461
   172
    std::vector<Value> values(length + 1);
alpar@461
   173
alpar@461
   174
    glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
alpar@461
   175
alpar@461
   176
    for (int i = 1; i <= length; ++i) {
alpar@461
   177
      *b = std::make_pair(indexes[i], values[i]);
alpar@461
   178
      ++b;
alpar@461
   179
    }
alpar@461
   180
  }
alpar@461
   181
alpar@461
   182
  void GlpkBase::_setColCoeffs(int ix, ExprIterator b,
alpar@461
   183
                                     ExprIterator e) {
alpar@461
   184
alpar@461
   185
    std::vector<int> indexes;
alpar@461
   186
    std::vector<Value> values;
alpar@461
   187
alpar@461
   188
    indexes.push_back(0);
alpar@461
   189
    values.push_back(0);
alpar@461
   190
alpar@461
   191
    for(ExprIterator it = b; it != e; ++it) {
alpar@461
   192
      indexes.push_back(it->first);
alpar@461
   193
      values.push_back(it->second);
alpar@461
   194
    }
alpar@461
   195
alpar@461
   196
    glp_set_mat_col(lp, ix, values.size() - 1,
alpar@461
   197
                    &indexes.front(), &values.front());
alpar@461
   198
  }
alpar@461
   199
alpar@461
   200
  void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const {
alpar@461
   201
    int length = glp_get_mat_col(lp, ix, 0, 0);
alpar@461
   202
alpar@461
   203
    std::vector<int> indexes(length + 1);
alpar@461
   204
    std::vector<Value> values(length + 1);
alpar@461
   205
alpar@461
   206
    glp_get_mat_col(lp, ix, &indexes.front(), &values.front());
alpar@461
   207
alpar@461
   208
    for (int i = 1; i  <= length; ++i) {
alpar@461
   209
      *b = std::make_pair(indexes[i], values[i]);
alpar@461
   210
      ++b;
alpar@461
   211
    }
alpar@461
   212
  }
alpar@461
   213
alpar@461
   214
  void GlpkBase::_setCoeff(int ix, int jx, Value value) {
alpar@461
   215
alpar@461
   216
    if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) {
alpar@461
   217
alpar@461
   218
      int length = glp_get_mat_row(lp, ix, 0, 0);
alpar@461
   219
alpar@461
   220
      std::vector<int> indexes(length + 2);
alpar@461
   221
      std::vector<Value> values(length + 2);
alpar@461
   222
alpar@461
   223
      glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
alpar@461
   224
alpar@461
   225
      //The following code does not suppose that the elements of the
alpar@461
   226
      //array indexes are sorted
alpar@461
   227
      bool found = false;
alpar@461
   228
      for (int i = 1; i  <= length; ++i) {
alpar@461
   229
        if (indexes[i] == jx) {
alpar@461
   230
          found = true;
alpar@461
   231
          values[i] = value;
alpar@461
   232
          break;
alpar@461
   233
        }
alpar@461
   234
      }
alpar@461
   235
      if (!found) {
alpar@461
   236
        ++length;
alpar@461
   237
        indexes[length] = jx;
alpar@461
   238
        values[length] = value;
alpar@461
   239
      }
alpar@461
   240
alpar@461
   241
      glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front());
alpar@461
   242
alpar@461
   243
    } else {
alpar@461
   244
alpar@461
   245
      int length = glp_get_mat_col(lp, jx, 0, 0);
alpar@461
   246
alpar@461
   247
      std::vector<int> indexes(length + 2);
alpar@461
   248
      std::vector<Value> values(length + 2);
alpar@461
   249
alpar@461
   250
      glp_get_mat_col(lp, jx, &indexes.front(), &values.front());
alpar@461
   251
alpar@461
   252
      //The following code does not suppose that the elements of the
alpar@461
   253
      //array indexes are sorted
alpar@461
   254
      bool found = false;
alpar@461
   255
      for (int i = 1; i <= length; ++i) {
alpar@461
   256
        if (indexes[i] == ix) {
alpar@461
   257
          found = true;
alpar@461
   258
          values[i] = value;
alpar@461
   259
          break;
alpar@461
   260
        }
alpar@461
   261
      }
alpar@461
   262
      if (!found) {
alpar@461
   263
        ++length;
alpar@461
   264
        indexes[length] = ix;
alpar@461
   265
        values[length] = value;
alpar@461
   266
      }
alpar@461
   267
alpar@461
   268
      glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front());
alpar@461
   269
    }
alpar@461
   270
alpar@461
   271
  }
alpar@461
   272
alpar@461
   273
  GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const {
alpar@461
   274
alpar@461
   275
    int length = glp_get_mat_row(lp, ix, 0, 0);
alpar@461
   276
alpar@461
   277
    std::vector<int> indexes(length + 1);
alpar@461
   278
    std::vector<Value> values(length + 1);
alpar@461
   279
alpar@461
   280
    glp_get_mat_row(lp, ix, &indexes.front(), &values.front());
alpar@461
   281
alpar@461
   282
    for (int i = 1; i  <= length; ++i) {
alpar@461
   283
      if (indexes[i] == jx) {
alpar@461
   284
        return values[i];
alpar@461
   285
      }
alpar@461
   286
    }
alpar@461
   287
alpar@461
   288
    return 0;
alpar@461
   289
  }
alpar@461
   290
alpar@461
   291
  void GlpkBase::_setColLowerBound(int i, Value lo) {
alpar@461
   292
    LEMON_ASSERT(lo != INF, "Invalid bound");
alpar@461
   293
alpar@461
   294
    int b = glp_get_col_type(lp, i);
alpar@461
   295
    double up = glp_get_col_ub(lp, i);
alpar@461
   296
    if (lo == -INF) {
alpar@461
   297
      switch (b) {
alpar@461
   298
      case GLP_FR:
alpar@461
   299
      case GLP_LO:
alpar@461
   300
        glp_set_col_bnds(lp, i, GLP_FR, lo, up);
alpar@461
   301
        break;
alpar@461
   302
      case GLP_UP:
alpar@461
   303
        break;
alpar@461
   304
      case GLP_DB:
alpar@461
   305
      case GLP_FX:
alpar@461
   306
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
alpar@461
   307
        break;
alpar@461
   308
      default:
alpar@461
   309
        break;
alpar@461
   310
      }
alpar@461
   311
    } else {
alpar@461
   312
      switch (b) {
alpar@461
   313
      case GLP_FR:
alpar@461
   314
      case GLP_LO:
alpar@461
   315
        glp_set_col_bnds(lp, i, GLP_LO, lo, up);
alpar@461
   316
        break;
alpar@461
   317
      case GLP_UP:
alpar@461
   318
      case GLP_DB:
alpar@461
   319
      case GLP_FX:
alpar@461
   320
        if (lo == up)
alpar@461
   321
          glp_set_col_bnds(lp, i, GLP_FX, lo, up);
alpar@461
   322
        else
alpar@461
   323
          glp_set_col_bnds(lp, i, GLP_DB, lo, up);
alpar@461
   324
        break;
alpar@461
   325
      default:
alpar@461
   326
        break;
alpar@461
   327
      }
alpar@461
   328
    }
alpar@461
   329
  }
alpar@461
   330
alpar@461
   331
  GlpkBase::Value GlpkBase::_getColLowerBound(int i) const {
alpar@461
   332
    int b = glp_get_col_type(lp, i);
alpar@461
   333
    switch (b) {
alpar@461
   334
    case GLP_LO:
alpar@461
   335
    case GLP_DB:
alpar@461
   336
    case GLP_FX:
alpar@461
   337
      return glp_get_col_lb(lp, i);
alpar@461
   338
    default:
alpar@461
   339
      return -INF;
alpar@461
   340
    }
alpar@461
   341
  }
alpar@461
   342
alpar@461
   343
  void GlpkBase::_setColUpperBound(int i, Value up) {
alpar@461
   344
    LEMON_ASSERT(up != -INF, "Invalid bound");
alpar@461
   345
alpar@461
   346
    int b = glp_get_col_type(lp, i);
alpar@461
   347
    double lo = glp_get_col_lb(lp, i);
alpar@461
   348
    if (up == INF) {
alpar@461
   349
      switch (b) {
alpar@461
   350
      case GLP_FR:
alpar@461
   351
      case GLP_LO:
alpar@461
   352
        break;
alpar@461
   353
      case GLP_UP:
alpar@461
   354
        glp_set_col_bnds(lp, i, GLP_FR, lo, up);
alpar@461
   355
        break;
alpar@461
   356
      case GLP_DB:
alpar@461
   357
      case GLP_FX:
alpar@461
   358
        glp_set_col_bnds(lp, i, GLP_LO, lo, up);
alpar@461
   359
        break;
alpar@461
   360
      default:
alpar@461
   361
        break;
alpar@461
   362
      }
alpar@461
   363
    } else {
alpar@461
   364
      switch (b) {
alpar@461
   365
      case GLP_FR:
alpar@461
   366
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
alpar@461
   367
        break;
alpar@461
   368
      case GLP_UP:
alpar@461
   369
        glp_set_col_bnds(lp, i, GLP_UP, lo, up);
alpar@461
   370
        break;
alpar@461
   371
      case GLP_LO:
alpar@461
   372
      case GLP_DB:
alpar@461
   373
      case GLP_FX:
alpar@461
   374
        if (lo == up)
alpar@461
   375
          glp_set_col_bnds(lp, i, GLP_FX, lo, up);
alpar@461
   376
        else
alpar@461
   377
          glp_set_col_bnds(lp, i, GLP_DB, lo, up);
alpar@461
   378
        break;
alpar@461
   379
      default:
alpar@461
   380
        break;
alpar@461
   381
      }
alpar@461
   382
    }
alpar@461
   383
alpar@461
   384
  }
alpar@461
   385
alpar@461
   386
  GlpkBase::Value GlpkBase::_getColUpperBound(int i) const {
alpar@461
   387
    int b = glp_get_col_type(lp, i);
alpar@461
   388
      switch (b) {
alpar@461
   389
      case GLP_UP:
alpar@461
   390
      case GLP_DB:
alpar@461
   391
      case GLP_FX:
alpar@461
   392
        return glp_get_col_ub(lp, i);
alpar@461
   393
      default:
alpar@461
   394
        return INF;
alpar@461
   395
      }
alpar@461
   396
  }
alpar@461
   397
alpar@461
   398
  void GlpkBase::_setRowLowerBound(int i, Value lo) {
alpar@461
   399
    LEMON_ASSERT(lo != INF, "Invalid bound");
alpar@461
   400
alpar@461
   401
    int b = glp_get_row_type(lp, i);
alpar@461
   402
    double up = glp_get_row_ub(lp, i);
alpar@461
   403
    if (lo == -INF) {
alpar@461
   404
      switch (b) {
alpar@461
   405
      case GLP_FR:
alpar@461
   406
      case GLP_LO:
alpar@461
   407
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
alpar@461
   408
        break;
alpar@461
   409
      case GLP_UP:
alpar@461
   410
        break;
alpar@461
   411
      case GLP_DB:
alpar@461
   412
      case GLP_FX:
alpar@461
   413
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
alpar@461
   414
        break;
alpar@461
   415
      default:
alpar@461
   416
        break;
alpar@461
   417
      }
alpar@461
   418
    } else {
alpar@461
   419
      switch (b) {
alpar@461
   420
      case GLP_FR:
alpar@461
   421
      case GLP_LO:
alpar@461
   422
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
alpar@461
   423
        break;
alpar@461
   424
      case GLP_UP:
alpar@461
   425
      case GLP_DB:
alpar@461
   426
      case GLP_FX:
alpar@461
   427
        if (lo == up)
alpar@461
   428
          glp_set_row_bnds(lp, i, GLP_FX, lo, up);
alpar@461
   429
        else
alpar@461
   430
          glp_set_row_bnds(lp, i, GLP_DB, lo, up);
alpar@461
   431
        break;
alpar@461
   432
      default:
alpar@461
   433
        break;
alpar@461
   434
      }
alpar@461
   435
    }
alpar@461
   436
alpar@461
   437
  }
alpar@461
   438
alpar@461
   439
  GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const {
alpar@461
   440
    int b = glp_get_row_type(lp, i);
alpar@461
   441
    switch (b) {
alpar@461
   442
    case GLP_LO:
alpar@461
   443
    case GLP_DB:
alpar@461
   444
    case GLP_FX:
alpar@461
   445
      return glp_get_row_lb(lp, i);
alpar@461
   446
    default:
alpar@461
   447
      return -INF;
alpar@461
   448
    }
alpar@461
   449
  }
alpar@461
   450
alpar@461
   451
  void GlpkBase::_setRowUpperBound(int i, Value up) {
alpar@461
   452
    LEMON_ASSERT(up != -INF, "Invalid bound");
alpar@461
   453
alpar@461
   454
    int b = glp_get_row_type(lp, i);
alpar@461
   455
    double lo = glp_get_row_lb(lp, i);
alpar@461
   456
    if (up == INF) {
alpar@461
   457
      switch (b) {
alpar@461
   458
      case GLP_FR:
alpar@461
   459
      case GLP_LO:
alpar@461
   460
        break;
alpar@461
   461
      case GLP_UP:
alpar@461
   462
        glp_set_row_bnds(lp, i, GLP_FR, lo, up);
alpar@461
   463
        break;
alpar@461
   464
      case GLP_DB:
alpar@461
   465
      case GLP_FX:
alpar@461
   466
        glp_set_row_bnds(lp, i, GLP_LO, lo, up);
alpar@461
   467
        break;
alpar@461
   468
      default:
alpar@461
   469
        break;
alpar@461
   470
      }
alpar@461
   471
    } else {
alpar@461
   472
      switch (b) {
alpar@461
   473
      case GLP_FR:
alpar@461
   474
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
alpar@461
   475
        break;
alpar@461
   476
      case GLP_UP:
alpar@461
   477
        glp_set_row_bnds(lp, i, GLP_UP, lo, up);
alpar@461
   478
        break;
alpar@461
   479
      case GLP_LO:
alpar@461
   480
      case GLP_DB:
alpar@461
   481
      case GLP_FX:
alpar@461
   482
        if (lo == up)
alpar@461
   483
          glp_set_row_bnds(lp, i, GLP_FX, lo, up);
alpar@461
   484
        else
alpar@461
   485
          glp_set_row_bnds(lp, i, GLP_DB, lo, up);
alpar@461
   486
        break;
alpar@461
   487
      default:
alpar@461
   488
        break;
alpar@461
   489
      }
alpar@461
   490
    }
alpar@461
   491
  }
alpar@461
   492
alpar@461
   493
  GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const {
alpar@461
   494
    int b = glp_get_row_type(lp, i);
alpar@461
   495
    switch (b) {
alpar@461
   496
    case GLP_UP:
alpar@461
   497
    case GLP_DB:
alpar@461
   498
    case GLP_FX:
alpar@461
   499
      return glp_get_row_ub(lp, i);
alpar@461
   500
    default:
alpar@461
   501
      return INF;
alpar@461
   502
    }
alpar@461
   503
  }
alpar@461
   504
alpar@461
   505
  void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) {
alpar@461
   506
    for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
alpar@461
   507
      glp_set_obj_coef(lp, i, 0.0);
alpar@461
   508
    }
alpar@461
   509
    for (ExprIterator it = b; it != e; ++it) {
alpar@461
   510
      glp_set_obj_coef(lp, it->first, it->second);
alpar@461
   511
    }
alpar@461
   512
  }
alpar@461
   513
alpar@461
   514
  void GlpkBase::_getObjCoeffs(InsertIterator b) const {
alpar@461
   515
    for (int i = 1; i <= glp_get_num_cols(lp); ++i) {
alpar@461
   516
      Value val = glp_get_obj_coef(lp, i);
alpar@461
   517
      if (val != 0.0) {
alpar@461
   518
        *b = std::make_pair(i, val);
alpar@461
   519
        ++b;
alpar@461
   520
      }
alpar@461
   521
    }
alpar@461
   522
  }
alpar@461
   523
alpar@461
   524
  void GlpkBase::_setObjCoeff(int i, Value obj_coef) {
alpar@461
   525
    //i = 0 means the constant term (shift)
alpar@461
   526
    glp_set_obj_coef(lp, i, obj_coef);
alpar@461
   527
  }
alpar@461
   528
alpar@461
   529
  GlpkBase::Value GlpkBase::_getObjCoeff(int i) const {
alpar@461
   530
    //i = 0 means the constant term (shift)
alpar@461
   531
    return glp_get_obj_coef(lp, i);
alpar@461
   532
  }
alpar@461
   533
alpar@461
   534
  void GlpkBase::_setSense(GlpkBase::Sense sense) {
alpar@461
   535
    switch (sense) {
alpar@461
   536
    case MIN:
alpar@461
   537
      glp_set_obj_dir(lp, GLP_MIN);
alpar@461
   538
      break;
alpar@461
   539
    case MAX:
alpar@461
   540
      glp_set_obj_dir(lp, GLP_MAX);
alpar@461
   541
      break;
alpar@461
   542
    }
alpar@461
   543
  }
alpar@461
   544
alpar@461
   545
  GlpkBase::Sense GlpkBase::_getSense() const {
alpar@461
   546
    switch(glp_get_obj_dir(lp)) {
alpar@461
   547
    case GLP_MIN:
alpar@461
   548
      return MIN;
alpar@461
   549
    case GLP_MAX:
alpar@461
   550
      return MAX;
alpar@461
   551
    default:
alpar@461
   552
      LEMON_ASSERT(false, "Wrong sense");
alpar@461
   553
      return GlpkBase::Sense();
alpar@461
   554
    }
alpar@461
   555
  }
alpar@461
   556
alpar@461
   557
  void GlpkBase::_clear() {
alpar@461
   558
    glp_erase_prob(lp);
alpar@461
   559
    rows.clear();
alpar@461
   560
    cols.clear();
alpar@461
   561
  }
alpar@461
   562
deba@537
   563
  void GlpkBase::freeEnv() {
deba@537
   564
    glp_free_env();
deba@537
   565
  }
deba@537
   566
deba@576
   567
  void GlpkBase::_messageLevel(MessageLevel level) {
deba@576
   568
    switch (level) {
deba@576
   569
    case MESSAGE_NOTHING:
deba@576
   570
      _message_level = GLP_MSG_OFF;
deba@576
   571
      break;
deba@576
   572
    case MESSAGE_ERROR:
deba@576
   573
      _message_level = GLP_MSG_ERR;
deba@576
   574
      break;
deba@576
   575
    case MESSAGE_WARNING:
deba@576
   576
      _message_level = GLP_MSG_ERR;
deba@576
   577
      break;
deba@576
   578
    case MESSAGE_NORMAL:
deba@576
   579
      _message_level = GLP_MSG_ON;
deba@576
   580
      break;
deba@576
   581
    case MESSAGE_VERBOSE:
deba@576
   582
      _message_level = GLP_MSG_ALL;
deba@576
   583
      break;
deba@576
   584
    }
deba@576
   585
  }
deba@576
   586
deba@538
   587
  GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper;
deba@538
   588
alpar@462
   589
  // GlpkLp members
alpar@461
   590
alpar@462
   591
  GlpkLp::GlpkLp()
deba@551
   592
    : LpBase(), LpSolver(), GlpkBase() {
deba@565
   593
    presolver(false);
alpar@461
   594
  }
alpar@461
   595
alpar@462
   596
  GlpkLp::GlpkLp(const GlpkLp& other)
deba@551
   597
    : LpBase(other), LpSolver(other), GlpkBase(other) {
deba@565
   598
    presolver(false);
alpar@461
   599
  }
alpar@461
   600
alpar@540
   601
  GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; }
alpar@540
   602
  GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); }
alpar@461
   603
alpar@462
   604
  const char* GlpkLp::_solverName() const { return "GlpkLp"; }
alpar@461
   605
alpar@462
   606
  void GlpkLp::_clear_temporals() {
alpar@461
   607
    _primal_ray.clear();
alpar@461
   608
    _dual_ray.clear();
alpar@461
   609
  }
alpar@461
   610
alpar@462
   611
  GlpkLp::SolveExitStatus GlpkLp::_solve() {
alpar@461
   612
    return solvePrimal();
alpar@461
   613
  }
alpar@461
   614
alpar@462
   615
  GlpkLp::SolveExitStatus GlpkLp::solvePrimal() {
alpar@461
   616
    _clear_temporals();
alpar@461
   617
alpar@461
   618
    glp_smcp smcp;
alpar@461
   619
    glp_init_smcp(&smcp);
alpar@461
   620
deba@576
   621
    smcp.msg_lev = _message_level;
deba@565
   622
    smcp.presolve = _presolve;
alpar@461
   623
deba@565
   624
    // If the basis is not valid we get an error return value.
deba@565
   625
    // In this case we can try to create a new basis.
deba@565
   626
    switch (glp_simplex(lp, &smcp)) {
deba@565
   627
    case 0:
deba@565
   628
      break;
deba@565
   629
    case GLP_EBADB:
deba@565
   630
    case GLP_ESING:
deba@565
   631
    case GLP_ECOND:
deba@566
   632
      glp_term_out(false);
deba@565
   633
      glp_adv_basis(lp, 0);
deba@566
   634
      glp_term_out(true);
deba@565
   635
      if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
deba@565
   636
      break;
deba@565
   637
    default:
deba@565
   638
      return UNSOLVED;
deba@565
   639
    }
deba@565
   640
alpar@461
   641
    return SOLVED;
alpar@461
   642
  }
alpar@461
   643
alpar@462
   644
  GlpkLp::SolveExitStatus GlpkLp::solveDual() {
alpar@461
   645
    _clear_temporals();
alpar@461
   646
alpar@461
   647
    glp_smcp smcp;
alpar@461
   648
    glp_init_smcp(&smcp);
alpar@461
   649
deba@576
   650
    smcp.msg_lev = _message_level;
alpar@461
   651
    smcp.meth = GLP_DUAL;
deba@565
   652
    smcp.presolve = _presolve;
alpar@461
   653
deba@565
   654
    // If the basis is not valid we get an error return value.
deba@565
   655
    // In this case we can try to create a new basis.
deba@565
   656
    switch (glp_simplex(lp, &smcp)) {
deba@565
   657
    case 0:
deba@565
   658
      break;
deba@565
   659
    case GLP_EBADB:
deba@565
   660
    case GLP_ESING:
deba@565
   661
    case GLP_ECOND:
deba@566
   662
      glp_term_out(false);
deba@565
   663
      glp_adv_basis(lp, 0);
deba@566
   664
      glp_term_out(true);
deba@565
   665
      if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
deba@565
   666
      break;
deba@565
   667
    default:
deba@565
   668
      return UNSOLVED;
deba@565
   669
    }
alpar@461
   670
    return SOLVED;
alpar@461
   671
  }
alpar@461
   672
alpar@462
   673
  GlpkLp::Value GlpkLp::_getPrimal(int i) const {
alpar@461
   674
    return glp_get_col_prim(lp, i);
alpar@461
   675
  }
alpar@461
   676
alpar@462
   677
  GlpkLp::Value GlpkLp::_getDual(int i) const {
alpar@461
   678
    return glp_get_row_dual(lp, i);
alpar@461
   679
  }
alpar@461
   680
alpar@462
   681
  GlpkLp::Value GlpkLp::_getPrimalValue() const {
alpar@461
   682
    return glp_get_obj_val(lp);
alpar@461
   683
  }
alpar@461
   684
alpar@462
   685
  GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const {
alpar@461
   686
    switch (glp_get_col_stat(lp, i)) {
alpar@461
   687
    case GLP_BS:
alpar@461
   688
      return BASIC;
alpar@461
   689
    case GLP_UP:
alpar@461
   690
      return UPPER;
alpar@461
   691
    case GLP_LO:
alpar@461
   692
      return LOWER;
alpar@461
   693
    case GLP_NF:
alpar@461
   694
      return FREE;
alpar@461
   695
    case GLP_NS:
alpar@461
   696
      return FIXED;
alpar@461
   697
    default:
alpar@461
   698
      LEMON_ASSERT(false, "Wrong column status");
alpar@462
   699
      return GlpkLp::VarStatus();
alpar@461
   700
    }
alpar@461
   701
  }
alpar@461
   702
alpar@462
   703
  GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const {
alpar@461
   704
    switch (glp_get_row_stat(lp, i)) {
alpar@461
   705
    case GLP_BS:
alpar@461
   706
      return BASIC;
alpar@461
   707
    case GLP_UP:
alpar@461
   708
      return UPPER;
alpar@461
   709
    case GLP_LO:
alpar@461
   710
      return LOWER;
alpar@461
   711
    case GLP_NF:
alpar@461
   712
      return FREE;
alpar@461
   713
    case GLP_NS:
alpar@461
   714
      return FIXED;
alpar@461
   715
    default:
alpar@461
   716
      LEMON_ASSERT(false, "Wrong row status");
alpar@462
   717
      return GlpkLp::VarStatus();
alpar@461
   718
    }
alpar@461
   719
  }
alpar@461
   720
alpar@462
   721
  GlpkLp::Value GlpkLp::_getPrimalRay(int i) const {
alpar@461
   722
    if (_primal_ray.empty()) {
alpar@461
   723
      int row_num = glp_get_num_rows(lp);
alpar@461
   724
      int col_num = glp_get_num_cols(lp);
alpar@461
   725
alpar@461
   726
      _primal_ray.resize(col_num + 1, 0.0);
alpar@461
   727
alpar@461
   728
      int index = glp_get_unbnd_ray(lp);
alpar@461
   729
      if (index != 0) {
alpar@461
   730
        // The primal ray is found in primal simplex second phase
alpar@461
   731
        LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
alpar@461
   732
                      glp_get_col_stat(lp, index - row_num)) != GLP_BS,
alpar@461
   733
                     "Wrong primal ray");
alpar@461
   734
alpar@461
   735
        bool negate = glp_get_obj_dir(lp) == GLP_MAX;
alpar@461
   736
alpar@461
   737
        if (index > row_num) {
alpar@461
   738
          _primal_ray[index - row_num] = 1.0;
alpar@461
   739
          if (glp_get_col_dual(lp, index - row_num) > 0) {
alpar@461
   740
            negate = !negate;
alpar@461
   741
          }
alpar@461
   742
        } else {
alpar@461
   743
          if (glp_get_row_dual(lp, index) > 0) {
alpar@461
   744
            negate = !negate;
alpar@461
   745
          }
alpar@461
   746
        }
alpar@461
   747
alpar@461
   748
        std::vector<int> ray_indexes(row_num + 1);
alpar@461
   749
        std::vector<Value> ray_values(row_num + 1);
alpar@461
   750
        int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(),
alpar@461
   751
                                          &ray_values.front());
alpar@461
   752
alpar@461
   753
        for (int i = 1; i <= ray_length; ++i) {
alpar@461
   754
          if (ray_indexes[i] > row_num) {
alpar@461
   755
            _primal_ray[ray_indexes[i] - row_num] = ray_values[i];
alpar@461
   756
          }
alpar@461
   757
        }
alpar@461
   758
alpar@461
   759
        if (negate) {
alpar@461
   760
          for (int i = 1; i <= col_num; ++i) {
alpar@461
   761
            _primal_ray[i] = - _primal_ray[i];
alpar@461
   762
          }
alpar@461
   763
        }
alpar@461
   764
      } else {
alpar@461
   765
        for (int i = 1; i <= col_num; ++i) {
alpar@461
   766
          _primal_ray[i] = glp_get_col_prim(lp, i);
alpar@461
   767
        }
alpar@461
   768
      }
alpar@461
   769
    }
alpar@461
   770
    return _primal_ray[i];
alpar@461
   771
  }
alpar@461
   772
alpar@462
   773
  GlpkLp::Value GlpkLp::_getDualRay(int i) const {
alpar@461
   774
    if (_dual_ray.empty()) {
alpar@461
   775
      int row_num = glp_get_num_rows(lp);
alpar@461
   776
alpar@461
   777
      _dual_ray.resize(row_num + 1, 0.0);
alpar@461
   778
alpar@461
   779
      int index = glp_get_unbnd_ray(lp);
alpar@461
   780
      if (index != 0) {
alpar@461
   781
        // The dual ray is found in dual simplex second phase
alpar@461
   782
        LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) :
alpar@461
   783
                      glp_get_col_stat(lp, index - row_num)) == GLP_BS,
alpar@461
   784
alpar@461
   785
                     "Wrong dual ray");
alpar@461
   786
alpar@461
   787
        int idx;
alpar@461
   788
        bool negate = false;
alpar@461
   789
alpar@461
   790
        if (index > row_num) {
alpar@461
   791
          idx = glp_get_col_bind(lp, index - row_num);
alpar@461
   792
          if (glp_get_col_prim(lp, index - row_num) >
alpar@461
   793
              glp_get_col_ub(lp, index - row_num)) {
alpar@461
   794
            negate = true;
alpar@461
   795
          }
alpar@461
   796
        } else {
alpar@461
   797
          idx = glp_get_row_bind(lp, index);
alpar@461
   798
          if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) {
alpar@461
   799
            negate = true;
alpar@461
   800
          }
alpar@461
   801
        }
alpar@461
   802
alpar@461
   803
        _dual_ray[idx] = negate ?  - 1.0 : 1.0;
alpar@461
   804
alpar@461
   805
        glp_btran(lp, &_dual_ray.front());
alpar@461
   806
      } else {
alpar@461
   807
        double eps = 1e-7;
alpar@461
   808
        // The dual ray is found in primal simplex first phase
alpar@461
   809
        // We assume that the glpk minimizes the slack to get feasible solution
alpar@461
   810
        for (int i = 1; i <= row_num; ++i) {
alpar@461
   811
          int index = glp_get_bhead(lp, i);
alpar@461
   812
          if (index <= row_num) {
alpar@461
   813
            double res = glp_get_row_prim(lp, index);
alpar@461
   814
            if (res > glp_get_row_ub(lp, index) + eps) {
alpar@461
   815
              _dual_ray[i] = -1;
alpar@461
   816
            } else if (res < glp_get_row_lb(lp, index) - eps) {
alpar@461
   817
              _dual_ray[i] = 1;
alpar@461
   818
            } else {
alpar@461
   819
              _dual_ray[i] = 0;
alpar@461
   820
            }
alpar@461
   821
            _dual_ray[i] *= glp_get_rii(lp, index);
alpar@461
   822
          } else {
alpar@461
   823
            double res = glp_get_col_prim(lp, index - row_num);
alpar@461
   824
            if (res > glp_get_col_ub(lp, index - row_num) + eps) {
alpar@461
   825
              _dual_ray[i] = -1;
alpar@461
   826
            } else if (res < glp_get_col_lb(lp, index - row_num) - eps) {
alpar@461
   827
              _dual_ray[i] = 1;
alpar@461
   828
            } else {
alpar@461
   829
              _dual_ray[i] = 0;
alpar@461
   830
            }
alpar@461
   831
            _dual_ray[i] /= glp_get_sjj(lp, index - row_num);
alpar@461
   832
          }
alpar@461
   833
        }
alpar@461
   834
alpar@461
   835
        glp_btran(lp, &_dual_ray.front());
alpar@461
   836
alpar@461
   837
        for (int i = 1; i <= row_num; ++i) {
alpar@461
   838
          _dual_ray[i] /= glp_get_rii(lp, i);
alpar@461
   839
        }
alpar@461
   840
      }
alpar@461
   841
    }
alpar@461
   842
    return _dual_ray[i];
alpar@461
   843
  }
alpar@461
   844
alpar@462
   845
  GlpkLp::ProblemType GlpkLp::_getPrimalType() const {
alpar@461
   846
    if (glp_get_status(lp) == GLP_OPT)
alpar@461
   847
      return OPTIMAL;
alpar@461
   848
    switch (glp_get_prim_stat(lp)) {
alpar@461
   849
    case GLP_UNDEF:
alpar@461
   850
      return UNDEFINED;
alpar@461
   851
    case GLP_FEAS:
alpar@461
   852
    case GLP_INFEAS:
alpar@461
   853
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
alpar@461
   854
        return UNBOUNDED;
alpar@461
   855
      } else {
alpar@461
   856
        return UNDEFINED;
alpar@461
   857
      }
alpar@461
   858
    case GLP_NOFEAS:
alpar@461
   859
      return INFEASIBLE;
alpar@461
   860
    default:
alpar@461
   861
      LEMON_ASSERT(false, "Wrong primal type");
alpar@462
   862
      return  GlpkLp::ProblemType();
alpar@461
   863
    }
alpar@461
   864
  }
alpar@461
   865
alpar@462
   866
  GlpkLp::ProblemType GlpkLp::_getDualType() const {
alpar@461
   867
    if (glp_get_status(lp) == GLP_OPT)
alpar@461
   868
      return OPTIMAL;
alpar@461
   869
    switch (glp_get_dual_stat(lp)) {
alpar@461
   870
    case GLP_UNDEF:
alpar@461
   871
      return UNDEFINED;
alpar@461
   872
    case GLP_FEAS:
alpar@461
   873
    case GLP_INFEAS:
alpar@461
   874
      if (glp_get_prim_stat(lp) == GLP_NOFEAS) {
alpar@461
   875
        return UNBOUNDED;
alpar@461
   876
      } else {
alpar@461
   877
        return UNDEFINED;
alpar@461
   878
      }
alpar@461
   879
    case GLP_NOFEAS:
alpar@461
   880
      return INFEASIBLE;
alpar@461
   881
    default:
alpar@461
   882
      LEMON_ASSERT(false, "Wrong primal type");
alpar@462
   883
      return  GlpkLp::ProblemType();
alpar@461
   884
    }
alpar@461
   885
  }
alpar@461
   886
deba@565
   887
  void GlpkLp::presolver(bool presolve) {
deba@565
   888
    _presolve = presolve;
alpar@461
   889
  }
alpar@461
   890
alpar@462
   891
  // GlpkMip members
alpar@461
   892
alpar@462
   893
  GlpkMip::GlpkMip()
deba@551
   894
    : LpBase(), MipSolver(), GlpkBase() {
alpar@461
   895
  }
alpar@461
   896
alpar@462
   897
  GlpkMip::GlpkMip(const GlpkMip& other)
deba@551
   898
    : LpBase(), MipSolver(), GlpkBase(other) {
alpar@461
   899
  }
alpar@461
   900
alpar@462
   901
  void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) {
alpar@461
   902
    switch (col_type) {
alpar@461
   903
    case INTEGER:
alpar@461
   904
      glp_set_col_kind(lp, i, GLP_IV);
alpar@461
   905
      break;
alpar@461
   906
    case REAL:
alpar@461
   907
      glp_set_col_kind(lp, i, GLP_CV);
alpar@461
   908
      break;
alpar@461
   909
    }
alpar@461
   910
  }
alpar@461
   911
alpar@462
   912
  GlpkMip::ColTypes GlpkMip::_getColType(int i) const {
alpar@461
   913
    switch (glp_get_col_kind(lp, i)) {
alpar@461
   914
    case GLP_IV:
alpar@461
   915
    case GLP_BV:
alpar@461
   916
      return INTEGER;
alpar@461
   917
    default:
alpar@461
   918
      return REAL;
alpar@461
   919
    }
alpar@461
   920
alpar@461
   921
  }
alpar@461
   922
alpar@462
   923
  GlpkMip::SolveExitStatus GlpkMip::_solve() {
alpar@461
   924
    glp_smcp smcp;
alpar@461
   925
    glp_init_smcp(&smcp);
alpar@461
   926
deba@576
   927
    smcp.msg_lev = _message_level;
alpar@461
   928
    smcp.meth = GLP_DUAL;
alpar@461
   929
deba@565
   930
    // If the basis is not valid we get an error return value.
deba@565
   931
    // In this case we can try to create a new basis.
deba@565
   932
    switch (glp_simplex(lp, &smcp)) {
deba@565
   933
    case 0:
deba@565
   934
      break;
deba@565
   935
    case GLP_EBADB:
deba@565
   936
    case GLP_ESING:
deba@565
   937
    case GLP_ECOND:
deba@566
   938
      glp_term_out(false);
deba@565
   939
      glp_adv_basis(lp, 0);
deba@566
   940
      glp_term_out(true);
deba@565
   941
      if (glp_simplex(lp, &smcp) != 0) return UNSOLVED;
deba@565
   942
      break;
deba@565
   943
    default:
deba@565
   944
      return UNSOLVED;
deba@565
   945
    }
deba@565
   946
alpar@461
   947
    if (glp_get_status(lp) != GLP_OPT) return SOLVED;
alpar@461
   948
alpar@461
   949
    glp_iocp iocp;
alpar@461
   950
    glp_init_iocp(&iocp);
alpar@461
   951
deba@576
   952
    iocp.msg_lev = _message_level;
alpar@461
   953
alpar@461
   954
    if (glp_intopt(lp, &iocp) != 0) return UNSOLVED;
alpar@461
   955
    return SOLVED;
alpar@461
   956
  }
alpar@461
   957
alpar@461
   958
alpar@462
   959
  GlpkMip::ProblemType GlpkMip::_getType() const {
alpar@461
   960
    switch (glp_get_status(lp)) {
alpar@461
   961
    case GLP_OPT:
alpar@461
   962
      switch (glp_mip_status(lp)) {
alpar@461
   963
      case GLP_UNDEF:
alpar@461
   964
        return UNDEFINED;
alpar@461
   965
      case GLP_NOFEAS:
alpar@461
   966
        return INFEASIBLE;
alpar@461
   967
      case GLP_FEAS:
alpar@461
   968
        return FEASIBLE;
alpar@461
   969
      case GLP_OPT:
alpar@461
   970
        return OPTIMAL;
alpar@461
   971
      default:
alpar@461
   972
        LEMON_ASSERT(false, "Wrong problem type.");
alpar@462
   973
        return GlpkMip::ProblemType();
alpar@461
   974
      }
alpar@461
   975
    case GLP_NOFEAS:
alpar@461
   976
      return INFEASIBLE;
alpar@461
   977
    case GLP_INFEAS:
alpar@461
   978
    case GLP_FEAS:
alpar@461
   979
      if (glp_get_dual_stat(lp) == GLP_NOFEAS) {
alpar@461
   980
        return UNBOUNDED;
alpar@461
   981
      } else {
alpar@461
   982
        return UNDEFINED;
alpar@461
   983
      }
alpar@461
   984
    default:
alpar@461
   985
      LEMON_ASSERT(false, "Wrong problem type.");
alpar@462
   986
      return GlpkMip::ProblemType();
alpar@461
   987
    }
alpar@461
   988
  }
alpar@461
   989
alpar@462
   990
  GlpkMip::Value GlpkMip::_getSol(int i) const {
alpar@461
   991
    return glp_mip_col_val(lp, i);
alpar@461
   992
  }
alpar@461
   993
alpar@462
   994
  GlpkMip::Value GlpkMip::_getSolValue() const {
alpar@461
   995
    return glp_mip_obj_val(lp);
alpar@461
   996
  }
alpar@461
   997
alpar@540
   998
  GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; }
alpar@540
   999
  GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); }
alpar@461
  1000
alpar@462
  1001
  const char* GlpkMip::_solverName() const { return "GlpkMip"; }
alpar@461
  1002
alpar@461
  1003
} //END OF NAMESPACE LEMON