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