lemon/glpk.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 982 bb70ad62c95f
parent 613 e7017ec2d5cd
child 793 e4554cd6b2bf
child 1140 8d281761dea4
permissions -rw-r--r--
Fix critical bug in preflow (#372)

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