lemon/soplex.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 982 bb70ad62c95f
parent 587 9db62975c32b
child 793 e4554cd6b2bf
child 1081 f1398882a928
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
 *
alpar@484
     5
 * Copyright (C) 2003-2008
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
#include <iostream>
alpar@484
    20
#include <lemon/soplex.h>
alpar@484
    21
alpar@586
    22
#include <soplex.h>
deba@623
    23
#include <spxout.h>
alpar@484
    24
alpar@484
    25
alpar@484
    26
///\file
alpar@484
    27
///\brief Implementation of the LEMON-SOPLEX lp solver interface.
alpar@484
    28
namespace lemon {
alpar@484
    29
alpar@485
    30
  SoplexLp::SoplexLp() {
alpar@484
    31
    soplex = new soplex::SoPlex;
deba@623
    32
    messageLevel(MESSAGE_NOTHING);
alpar@484
    33
  }
alpar@484
    34
alpar@485
    35
  SoplexLp::~SoplexLp() {
alpar@484
    36
    delete soplex;
alpar@484
    37
  }
alpar@484
    38
alpar@485
    39
  SoplexLp::SoplexLp(const SoplexLp& lp) {
alpar@484
    40
    rows = lp.rows;
alpar@484
    41
    cols = lp.cols;
alpar@484
    42
alpar@484
    43
    soplex = new soplex::SoPlex;
alpar@484
    44
    (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
alpar@484
    45
alpar@484
    46
    _col_names = lp._col_names;
alpar@484
    47
    _col_names_ref = lp._col_names_ref;
alpar@484
    48
alpar@484
    49
    _row_names = lp._row_names;
alpar@484
    50
    _row_names_ref = lp._row_names_ref;
alpar@484
    51
deba@623
    52
    messageLevel(MESSAGE_NOTHING);
alpar@484
    53
  }
alpar@484
    54
alpar@485
    55
  void SoplexLp::_clear_temporals() {
alpar@484
    56
    _primal_values.clear();
alpar@484
    57
    _dual_values.clear();
alpar@484
    58
  }
alpar@484
    59
alpar@587
    60
  SoplexLp* SoplexLp::newSolver() const {
alpar@485
    61
    SoplexLp* newlp = new SoplexLp();
alpar@484
    62
    return newlp;
alpar@484
    63
  }
alpar@484
    64
alpar@587
    65
  SoplexLp* SoplexLp::cloneSolver() const {
alpar@485
    66
    SoplexLp* newlp = new SoplexLp(*this);
alpar@484
    67
    return newlp;
alpar@484
    68
  }
alpar@484
    69
alpar@485
    70
  const char* SoplexLp::_solverName() const { return "SoplexLp"; }
alpar@484
    71
alpar@485
    72
  int SoplexLp::_addCol() {
alpar@484
    73
    soplex::LPCol c;
alpar@484
    74
    c.setLower(-soplex::infinity);
alpar@484
    75
    c.setUpper(soplex::infinity);
alpar@484
    76
    soplex->addCol(c);
alpar@484
    77
alpar@484
    78
    _col_names.push_back(std::string());
alpar@484
    79
alpar@484
    80
    return soplex->nCols() - 1;
alpar@484
    81
  }
alpar@484
    82
alpar@485
    83
  int SoplexLp::_addRow() {
alpar@484
    84
    soplex::LPRow r;
alpar@484
    85
    r.setLhs(-soplex::infinity);
alpar@484
    86
    r.setRhs(soplex::infinity);
alpar@484
    87
    soplex->addRow(r);
alpar@484
    88
alpar@484
    89
    _row_names.push_back(std::string());
alpar@484
    90
alpar@484
    91
    return soplex->nRows() - 1;
alpar@484
    92
  }
alpar@484
    93
alpar@484
    94
alpar@485
    95
  void SoplexLp::_eraseCol(int i) {
alpar@484
    96
    soplex->removeCol(i);
alpar@484
    97
    _col_names_ref.erase(_col_names[i]);
alpar@484
    98
    _col_names[i] = _col_names.back();
alpar@484
    99
    _col_names_ref[_col_names.back()] = i;
alpar@484
   100
    _col_names.pop_back();
alpar@484
   101
  }
alpar@484
   102
alpar@485
   103
  void SoplexLp::_eraseRow(int i) {
alpar@484
   104
    soplex->removeRow(i);
alpar@484
   105
    _row_names_ref.erase(_row_names[i]);
alpar@484
   106
    _row_names[i] = _row_names.back();
alpar@484
   107
    _row_names_ref[_row_names.back()] = i;
alpar@484
   108
    _row_names.pop_back();
alpar@484
   109
  }
alpar@484
   110
alpar@485
   111
  void SoplexLp::_eraseColId(int i) {
alpar@484
   112
    cols.eraseIndex(i);
alpar@484
   113
    cols.relocateIndex(i, cols.maxIndex());
alpar@484
   114
  }
alpar@485
   115
  void SoplexLp::_eraseRowId(int i) {
alpar@484
   116
    rows.eraseIndex(i);
alpar@484
   117
    rows.relocateIndex(i, rows.maxIndex());
alpar@484
   118
  }
alpar@484
   119
alpar@485
   120
  void SoplexLp::_getColName(int c, std::string &name) const {
alpar@484
   121
    name = _col_names[c];
alpar@484
   122
  }
alpar@484
   123
alpar@485
   124
  void SoplexLp::_setColName(int c, const std::string &name) {
alpar@484
   125
    _col_names_ref.erase(_col_names[c]);
alpar@484
   126
    _col_names[c] = name;
alpar@484
   127
    if (!name.empty()) {
alpar@484
   128
      _col_names_ref.insert(std::make_pair(name, c));
alpar@484
   129
    }
alpar@484
   130
  }
alpar@484
   131
alpar@485
   132
  int SoplexLp::_colByName(const std::string& name) const {
alpar@484
   133
    std::map<std::string, int>::const_iterator it =
alpar@484
   134
      _col_names_ref.find(name);
alpar@484
   135
    if (it != _col_names_ref.end()) {
alpar@484
   136
      return it->second;
alpar@484
   137
    } else {
alpar@484
   138
      return -1;
alpar@484
   139
    }
alpar@484
   140
  }
alpar@484
   141
alpar@485
   142
  void SoplexLp::_getRowName(int r, std::string &name) const {
alpar@484
   143
    name = _row_names[r];
alpar@484
   144
  }
alpar@484
   145
alpar@485
   146
  void SoplexLp::_setRowName(int r, const std::string &name) {
alpar@484
   147
    _row_names_ref.erase(_row_names[r]);
alpar@484
   148
    _row_names[r] = name;
alpar@484
   149
    if (!name.empty()) {
alpar@484
   150
      _row_names_ref.insert(std::make_pair(name, r));
alpar@484
   151
    }
alpar@484
   152
  }
alpar@484
   153
alpar@485
   154
  int SoplexLp::_rowByName(const std::string& name) const {
alpar@484
   155
    std::map<std::string, int>::const_iterator it =
alpar@484
   156
      _row_names_ref.find(name);
alpar@484
   157
    if (it != _row_names_ref.end()) {
alpar@484
   158
      return it->second;
alpar@484
   159
    } else {
alpar@484
   160
      return -1;
alpar@484
   161
    }
alpar@484
   162
  }
alpar@484
   163
alpar@484
   164
alpar@485
   165
  void SoplexLp::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
alpar@484
   166
    for (int j = 0; j < soplex->nCols(); ++j) {
alpar@484
   167
      soplex->changeElement(i, j, 0.0);
alpar@484
   168
    }
alpar@484
   169
    for(ExprIterator it = b; it != e; ++it) {
alpar@484
   170
      soplex->changeElement(i, it->first, it->second);
alpar@484
   171
    }
alpar@484
   172
  }
alpar@484
   173
alpar@485
   174
  void SoplexLp::_getRowCoeffs(int i, InsertIterator b) const {
alpar@484
   175
    const soplex::SVector& vec = soplex->rowVector(i);
alpar@484
   176
    for (int k = 0; k < vec.size(); ++k) {
alpar@484
   177
      *b = std::make_pair(vec.index(k), vec.value(k));
alpar@484
   178
      ++b;
alpar@484
   179
    }
alpar@484
   180
  }
alpar@484
   181
alpar@485
   182
  void SoplexLp::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
alpar@484
   183
    for (int i = 0; i < soplex->nRows(); ++i) {
alpar@484
   184
      soplex->changeElement(i, j, 0.0);
alpar@484
   185
    }
alpar@484
   186
    for(ExprIterator it = b; it != e; ++it) {
alpar@484
   187
      soplex->changeElement(it->first, j, it->second);
alpar@484
   188
    }
alpar@484
   189
  }
alpar@484
   190
alpar@485
   191
  void SoplexLp::_getColCoeffs(int i, InsertIterator b) const {
alpar@484
   192
    const soplex::SVector& vec = soplex->colVector(i);
alpar@484
   193
    for (int k = 0; k < vec.size(); ++k) {
alpar@484
   194
      *b = std::make_pair(vec.index(k), vec.value(k));
alpar@484
   195
      ++b;
alpar@484
   196
    }
alpar@484
   197
  }
alpar@484
   198
alpar@485
   199
  void SoplexLp::_setCoeff(int i, int j, Value value) {
alpar@484
   200
    soplex->changeElement(i, j, value);
alpar@484
   201
  }
alpar@484
   202
alpar@485
   203
  SoplexLp::Value SoplexLp::_getCoeff(int i, int j) const {
alpar@484
   204
    return soplex->rowVector(i)[j];
alpar@484
   205
  }
alpar@484
   206
alpar@485
   207
  void SoplexLp::_setColLowerBound(int i, Value value) {
alpar@484
   208
    LEMON_ASSERT(value != INF, "Invalid bound");
alpar@484
   209
    soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
alpar@484
   210
  }
alpar@484
   211
alpar@485
   212
  SoplexLp::Value SoplexLp::_getColLowerBound(int i) const {
alpar@484
   213
    double value = soplex->lower(i);
alpar@484
   214
    return value != -soplex::infinity ? value : -INF;
alpar@484
   215
  }
alpar@484
   216
alpar@485
   217
  void SoplexLp::_setColUpperBound(int i, Value value) {
alpar@484
   218
    LEMON_ASSERT(value != -INF, "Invalid bound");
alpar@484
   219
    soplex->changeUpper(i, value != INF ? value : soplex::infinity);
alpar@484
   220
  }
alpar@484
   221
alpar@485
   222
  SoplexLp::Value SoplexLp::_getColUpperBound(int i) const {
alpar@484
   223
    double value = soplex->upper(i);
alpar@484
   224
    return value != soplex::infinity ? value : INF;
alpar@484
   225
  }
alpar@484
   226
alpar@485
   227
  void SoplexLp::_setRowLowerBound(int i, Value lb) {
alpar@484
   228
    LEMON_ASSERT(lb != INF, "Invalid bound");
alpar@484
   229
    soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
alpar@484
   230
  }
alpar@484
   231
alpar@485
   232
  SoplexLp::Value SoplexLp::_getRowLowerBound(int i) const {
alpar@484
   233
    double res = soplex->lhs(i);
alpar@484
   234
    return res == -soplex::infinity ? -INF : res;
alpar@484
   235
  }
alpar@484
   236
alpar@485
   237
  void SoplexLp::_setRowUpperBound(int i, Value ub) {
alpar@484
   238
    LEMON_ASSERT(ub != -INF, "Invalid bound");
alpar@484
   239
    soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
alpar@484
   240
  }
alpar@484
   241
alpar@485
   242
  SoplexLp::Value SoplexLp::_getRowUpperBound(int i) const {
alpar@484
   243
    double res = soplex->rhs(i);
alpar@484
   244
    return res == soplex::infinity ? INF : res;
alpar@484
   245
  }
alpar@484
   246
alpar@485
   247
  void SoplexLp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
alpar@484
   248
    for (int j = 0; j < soplex->nCols(); ++j) {
alpar@484
   249
      soplex->changeObj(j, 0.0);
alpar@484
   250
    }
alpar@484
   251
    for (ExprIterator it = b; it != e; ++it) {
alpar@484
   252
      soplex->changeObj(it->first, it->second);
alpar@484
   253
    }
alpar@484
   254
  }
alpar@484
   255
alpar@485
   256
  void SoplexLp::_getObjCoeffs(InsertIterator b) const {
alpar@484
   257
    for (int j = 0; j < soplex->nCols(); ++j) {
alpar@484
   258
      Value coef = soplex->obj(j);
alpar@484
   259
      if (coef != 0.0) {
alpar@484
   260
        *b = std::make_pair(j, coef);
alpar@484
   261
        ++b;
alpar@484
   262
      }
alpar@484
   263
    }
alpar@484
   264
  }
alpar@484
   265
alpar@485
   266
  void SoplexLp::_setObjCoeff(int i, Value obj_coef) {
alpar@484
   267
    soplex->changeObj(i, obj_coef);
alpar@484
   268
  }
alpar@484
   269
alpar@485
   270
  SoplexLp::Value SoplexLp::_getObjCoeff(int i) const {
alpar@484
   271
    return soplex->obj(i);
alpar@484
   272
  }
alpar@484
   273
alpar@485
   274
  SoplexLp::SolveExitStatus SoplexLp::_solve() {
alpar@484
   275
alpar@484
   276
    _clear_temporals();
deba@623
   277
    
deba@623
   278
    _applyMessageLevel();
alpar@484
   279
alpar@484
   280
    soplex::SPxSolver::Status status = soplex->solve();
alpar@484
   281
alpar@484
   282
    switch (status) {
alpar@484
   283
    case soplex::SPxSolver::OPTIMAL:
alpar@484
   284
    case soplex::SPxSolver::INFEASIBLE:
alpar@484
   285
    case soplex::SPxSolver::UNBOUNDED:
alpar@484
   286
      return SOLVED;
alpar@484
   287
    default:
alpar@484
   288
      return UNSOLVED;
alpar@484
   289
    }
alpar@484
   290
  }
alpar@484
   291
alpar@485
   292
  SoplexLp::Value SoplexLp::_getPrimal(int i) const {
alpar@484
   293
    if (_primal_values.empty()) {
alpar@484
   294
      _primal_values.resize(soplex->nCols());
alpar@484
   295
      soplex::Vector pv(_primal_values.size(), &_primal_values.front());
alpar@484
   296
      soplex->getPrimal(pv);
alpar@484
   297
    }
alpar@484
   298
    return _primal_values[i];
alpar@484
   299
  }
alpar@484
   300
alpar@485
   301
  SoplexLp::Value SoplexLp::_getDual(int i) const {
alpar@484
   302
    if (_dual_values.empty()) {
alpar@484
   303
      _dual_values.resize(soplex->nRows());
alpar@484
   304
      soplex::Vector dv(_dual_values.size(), &_dual_values.front());
alpar@484
   305
      soplex->getDual(dv);
alpar@484
   306
    }
alpar@484
   307
    return _dual_values[i];
alpar@484
   308
  }
alpar@484
   309
alpar@485
   310
  SoplexLp::Value SoplexLp::_getPrimalValue() const {
alpar@484
   311
    return soplex->objValue();
alpar@484
   312
  }
alpar@484
   313
alpar@485
   314
  SoplexLp::VarStatus SoplexLp::_getColStatus(int i) const {
alpar@484
   315
    switch (soplex->getBasisColStatus(i)) {
alpar@484
   316
    case soplex::SPxSolver::BASIC:
alpar@484
   317
      return BASIC;
alpar@484
   318
    case soplex::SPxSolver::ON_UPPER:
alpar@484
   319
      return UPPER;
alpar@484
   320
    case soplex::SPxSolver::ON_LOWER:
alpar@484
   321
      return LOWER;
alpar@484
   322
    case soplex::SPxSolver::FIXED:
alpar@484
   323
      return FIXED;
alpar@484
   324
    case soplex::SPxSolver::ZERO:
alpar@484
   325
      return FREE;
alpar@484
   326
    default:
alpar@484
   327
      LEMON_ASSERT(false, "Wrong column status");
alpar@484
   328
      return VarStatus();
alpar@484
   329
    }
alpar@484
   330
  }
alpar@484
   331
alpar@485
   332
  SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const {
alpar@484
   333
    switch (soplex->getBasisRowStatus(i)) {
alpar@484
   334
    case soplex::SPxSolver::BASIC:
alpar@484
   335
      return BASIC;
alpar@484
   336
    case soplex::SPxSolver::ON_UPPER:
alpar@484
   337
      return UPPER;
alpar@484
   338
    case soplex::SPxSolver::ON_LOWER:
alpar@484
   339
      return LOWER;
alpar@484
   340
    case soplex::SPxSolver::FIXED:
alpar@484
   341
      return FIXED;
alpar@484
   342
    case soplex::SPxSolver::ZERO:
alpar@484
   343
      return FREE;
alpar@484
   344
    default:
alpar@484
   345
      LEMON_ASSERT(false, "Wrong row status");
alpar@484
   346
      return VarStatus();
alpar@484
   347
    }
alpar@484
   348
  }
alpar@484
   349
alpar@485
   350
  SoplexLp::Value SoplexLp::_getPrimalRay(int i) const {
alpar@484
   351
    if (_primal_ray.empty()) {
alpar@484
   352
      _primal_ray.resize(soplex->nCols());
alpar@484
   353
      soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
alpar@484
   354
      soplex->getDualfarkas(pv);
alpar@484
   355
    }
alpar@484
   356
    return _primal_ray[i];
alpar@484
   357
  }
alpar@484
   358
alpar@485
   359
  SoplexLp::Value SoplexLp::_getDualRay(int i) const {
alpar@484
   360
    if (_dual_ray.empty()) {
alpar@484
   361
      _dual_ray.resize(soplex->nRows());
alpar@484
   362
      soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
alpar@484
   363
      soplex->getDualfarkas(dv);
alpar@484
   364
    }
alpar@484
   365
    return _dual_ray[i];
alpar@484
   366
  }
alpar@484
   367
alpar@485
   368
  SoplexLp::ProblemType SoplexLp::_getPrimalType() const {
alpar@484
   369
    switch (soplex->status()) {
alpar@484
   370
    case soplex::SPxSolver::OPTIMAL:
alpar@484
   371
      return OPTIMAL;
alpar@484
   372
    case soplex::SPxSolver::UNBOUNDED:
alpar@484
   373
      return UNBOUNDED;
alpar@484
   374
    case soplex::SPxSolver::INFEASIBLE:
alpar@484
   375
      return INFEASIBLE;
alpar@484
   376
    default:
alpar@484
   377
      return UNDEFINED;
alpar@484
   378
    }
alpar@484
   379
  }
alpar@484
   380
alpar@485
   381
  SoplexLp::ProblemType SoplexLp::_getDualType() const {
alpar@484
   382
    switch (soplex->status()) {
alpar@484
   383
    case soplex::SPxSolver::OPTIMAL:
alpar@484
   384
      return OPTIMAL;
alpar@484
   385
    case soplex::SPxSolver::UNBOUNDED:
alpar@484
   386
      return UNBOUNDED;
alpar@484
   387
    case soplex::SPxSolver::INFEASIBLE:
alpar@484
   388
      return INFEASIBLE;
alpar@484
   389
    default:
alpar@484
   390
      return UNDEFINED;
alpar@484
   391
    }
alpar@484
   392
  }
alpar@484
   393
alpar@485
   394
  void SoplexLp::_setSense(Sense sense) {
alpar@484
   395
    switch (sense) {
alpar@484
   396
    case MIN:
alpar@484
   397
      soplex->changeSense(soplex::SPxSolver::MINIMIZE);
alpar@484
   398
      break;
alpar@484
   399
    case MAX:
alpar@484
   400
      soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
alpar@484
   401
    }
alpar@484
   402
  }
alpar@484
   403
alpar@485
   404
  SoplexLp::Sense SoplexLp::_getSense() const {
alpar@484
   405
    switch (soplex->spxSense()) {
alpar@484
   406
    case soplex::SPxSolver::MAXIMIZE:
alpar@484
   407
      return MAX;
alpar@484
   408
    case soplex::SPxSolver::MINIMIZE:
alpar@484
   409
      return MIN;
alpar@484
   410
    default:
alpar@484
   411
      LEMON_ASSERT(false, "Wrong sense.");
alpar@485
   412
      return SoplexLp::Sense();
alpar@484
   413
    }
alpar@484
   414
  }
alpar@484
   415
alpar@485
   416
  void SoplexLp::_clear() {
alpar@484
   417
    soplex->clear();
alpar@484
   418
    _col_names.clear();
alpar@484
   419
    _col_names_ref.clear();
alpar@484
   420
    _row_names.clear();
alpar@484
   421
    _row_names_ref.clear();
alpar@484
   422
    cols.clear();
alpar@484
   423
    rows.clear();
alpar@484
   424
    _clear_temporals();
alpar@484
   425
  }
alpar@484
   426
deba@623
   427
  void SoplexLp::_messageLevel(MessageLevel level) {
deba@623
   428
    switch (level) {
deba@623
   429
    case MESSAGE_NOTHING:
deba@623
   430
      _message_level = -1;
deba@623
   431
      break;
deba@623
   432
    case MESSAGE_ERROR:
deba@623
   433
      _message_level = soplex::SPxOut::ERROR;
deba@623
   434
      break;
deba@623
   435
    case MESSAGE_WARNING:
deba@623
   436
      _message_level = soplex::SPxOut::WARNING;
deba@623
   437
      break;
deba@623
   438
    case MESSAGE_NORMAL:
deba@623
   439
      _message_level = soplex::SPxOut::INFO2;
deba@623
   440
      break;
deba@623
   441
    case MESSAGE_VERBOSE:
deba@623
   442
      _message_level = soplex::SPxOut::DEBUG;
deba@623
   443
      break;
deba@623
   444
    }
deba@623
   445
  }
deba@623
   446
deba@623
   447
  void SoplexLp::_applyMessageLevel() {
deba@623
   448
    soplex::Param::setVerbose(_message_level);
deba@623
   449
  }
deba@623
   450
alpar@484
   451
} //namespace lemon
alpar@484
   452