lemon/lp_soplex.cc
author Balazs Dezso <deba@inf.elte.hu>
Tue, 02 Dec 2008 22:48:28 +0100
changeset 482 ed54c0d13df0
parent 481 7afc121e0689
permissions -rw-r--r--
Thorough redesign of the LP/MIP interface (#44)

- Redesigned class structure
- Redesigned iterators
- Some functions in the basic interface redesigned
- More complete setting functions
- Ray retrieving functions
- Lot of improvements
- Cplex common env
- CLP macro definition to config.h.in
- Update lp.h to also use soplex and clp
- Remove default_solver_name
- New solverName() function in solvers
- Handle exceptions for MipCplex test
- Rename tolerance parameter to epsilon
- Rename MapIt to CoeffIt
- Lot of documentation improvements
- Various bugfixes
deba@481
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@481
     2
 *
deba@481
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@481
     4
 *
deba@481
     5
 * Copyright (C) 2003-2008
deba@481
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@481
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@481
     8
 *
deba@481
     9
 * Permission to use, modify and distribute this software is granted
deba@481
    10
 * provided that this copyright notice appears in all copies. For
deba@481
    11
 * precise terms see the accompanying LICENSE file.
deba@481
    12
 *
deba@481
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@481
    14
 * express or implied, and with no claim as to its suitability for any
deba@481
    15
 * purpose.
deba@481
    16
 *
deba@481
    17
 */
deba@481
    18
deba@482
    19
#include <iostream>
deba@482
    20
#include <lemon/lp_soplex.h>
deba@481
    21
deba@481
    22
#include <soplex/soplex.h>
deba@481
    23
deba@481
    24
deba@481
    25
///\file
deba@481
    26
///\brief Implementation of the LEMON-SOPLEX lp solver interface.
deba@481
    27
namespace lemon {
deba@481
    28
deba@482
    29
  LpSoplex::LpSoplex() {
deba@481
    30
    soplex = new soplex::SoPlex;
deba@481
    31
  }
deba@481
    32
deba@481
    33
  LpSoplex::~LpSoplex() {
deba@481
    34
    delete soplex;
deba@481
    35
  }
deba@481
    36
deba@482
    37
  LpSoplex::LpSoplex(const LpSoplex& lp) {
deba@481
    38
    rows = lp.rows;
deba@481
    39
    cols = lp.cols;
deba@481
    40
deba@481
    41
    soplex = new soplex::SoPlex;
deba@481
    42
    (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
deba@481
    43
deba@482
    44
    _col_names = lp._col_names;
deba@482
    45
    _col_names_ref = lp._col_names_ref;
deba@481
    46
deba@482
    47
    _row_names = lp._row_names;
deba@482
    48
    _row_names_ref = lp._row_names_ref;
deba@481
    49
deba@481
    50
  }
deba@481
    51
deba@482
    52
  void LpSoplex::_clear_temporals() {
deba@482
    53
    _primal_values.clear();
deba@482
    54
    _dual_values.clear();
deba@482
    55
  }
deba@482
    56
deba@482
    57
  LpSoplex* LpSoplex::_newSolver() const {
deba@481
    58
    LpSoplex* newlp = new LpSoplex();
deba@481
    59
    return newlp;
deba@481
    60
  }
deba@481
    61
deba@482
    62
  LpSoplex* LpSoplex::_cloneSolver() const {
deba@481
    63
    LpSoplex* newlp = new LpSoplex(*this);
deba@481
    64
    return newlp;
deba@481
    65
  }
deba@481
    66
deba@482
    67
  const char* LpSoplex::_solverName() const { return "LpSoplex"; }
deba@482
    68
deba@481
    69
  int LpSoplex::_addCol() {
deba@481
    70
    soplex::LPCol c;
deba@481
    71
    c.setLower(-soplex::infinity);
deba@481
    72
    c.setUpper(soplex::infinity);
deba@481
    73
    soplex->addCol(c);
deba@481
    74
deba@482
    75
    _col_names.push_back(std::string());
deba@481
    76
deba@481
    77
    return soplex->nCols() - 1;
deba@481
    78
  }
deba@481
    79
deba@481
    80
  int LpSoplex::_addRow() {
deba@481
    81
    soplex::LPRow r;
deba@481
    82
    r.setLhs(-soplex::infinity);
deba@481
    83
    r.setRhs(soplex::infinity);
deba@481
    84
    soplex->addRow(r);
deba@481
    85
deba@482
    86
    _row_names.push_back(std::string());
deba@481
    87
deba@481
    88
    return soplex->nRows() - 1;
deba@481
    89
  }
deba@481
    90
deba@481
    91
deba@481
    92
  void LpSoplex::_eraseCol(int i) {
deba@481
    93
    soplex->removeCol(i);
deba@482
    94
    _col_names_ref.erase(_col_names[i]);
deba@482
    95
    _col_names[i] = _col_names.back();
deba@482
    96
    _col_names_ref[_col_names.back()] = i;
deba@482
    97
    _col_names.pop_back();
deba@481
    98
  }
deba@481
    99
deba@481
   100
  void LpSoplex::_eraseRow(int i) {
deba@481
   101
    soplex->removeRow(i);
deba@482
   102
    _row_names_ref.erase(_row_names[i]);
deba@482
   103
    _row_names[i] = _row_names.back();
deba@482
   104
    _row_names_ref[_row_names.back()] = i;
deba@482
   105
    _row_names.pop_back();
deba@482
   106
  }
deba@482
   107
deba@482
   108
  void LpSoplex::_eraseColId(int i) {
deba@482
   109
    cols.eraseIndex(i);
deba@482
   110
    cols.relocateIndex(i, cols.maxIndex());
deba@482
   111
  }
deba@482
   112
  void LpSoplex::_eraseRowId(int i) {
deba@482
   113
    rows.eraseIndex(i);
deba@482
   114
    rows.relocateIndex(i, rows.maxIndex());
deba@481
   115
  }
deba@481
   116
deba@481
   117
  void LpSoplex::_getColName(int c, std::string &name) const {
deba@482
   118
    name = _col_names[c];
deba@481
   119
  }
deba@481
   120
deba@481
   121
  void LpSoplex::_setColName(int c, const std::string &name) {
deba@482
   122
    _col_names_ref.erase(_col_names[c]);
deba@482
   123
    _col_names[c] = name;
deba@481
   124
    if (!name.empty()) {
deba@482
   125
      _col_names_ref.insert(std::make_pair(name, c));
deba@481
   126
    }
deba@481
   127
  }
deba@481
   128
deba@481
   129
  int LpSoplex::_colByName(const std::string& name) const {
deba@481
   130
    std::map<std::string, int>::const_iterator it =
deba@482
   131
      _col_names_ref.find(name);
deba@482
   132
    if (it != _col_names_ref.end()) {
deba@481
   133
      return it->second;
deba@481
   134
    } else {
deba@481
   135
      return -1;
deba@481
   136
    }
deba@481
   137
  }
deba@481
   138
deba@482
   139
  void LpSoplex::_getRowName(int r, std::string &name) const {
deba@482
   140
    name = _row_names[r];
deba@482
   141
  }
deba@481
   142
deba@482
   143
  void LpSoplex::_setRowName(int r, const std::string &name) {
deba@482
   144
    _row_names_ref.erase(_row_names[r]);
deba@482
   145
    _row_names[r] = name;
deba@482
   146
    if (!name.empty()) {
deba@482
   147
      _row_names_ref.insert(std::make_pair(name, r));
deba@482
   148
    }
deba@482
   149
  }
deba@482
   150
deba@482
   151
  int LpSoplex::_rowByName(const std::string& name) const {
deba@482
   152
    std::map<std::string, int>::const_iterator it =
deba@482
   153
      _row_names_ref.find(name);
deba@482
   154
    if (it != _row_names_ref.end()) {
deba@482
   155
      return it->second;
deba@482
   156
    } else {
deba@482
   157
      return -1;
deba@482
   158
    }
deba@482
   159
  }
deba@482
   160
deba@482
   161
deba@482
   162
  void LpSoplex::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
deba@481
   163
    for (int j = 0; j < soplex->nCols(); ++j) {
deba@481
   164
      soplex->changeElement(i, j, 0.0);
deba@481
   165
    }
deba@482
   166
    for(ExprIterator it = b; it != e; ++it) {
deba@481
   167
      soplex->changeElement(i, it->first, it->second);
deba@481
   168
    }
deba@481
   169
  }
deba@481
   170
deba@482
   171
  void LpSoplex::_getRowCoeffs(int i, InsertIterator b) const {
deba@481
   172
    const soplex::SVector& vec = soplex->rowVector(i);
deba@481
   173
    for (int k = 0; k < vec.size(); ++k) {
deba@481
   174
      *b = std::make_pair(vec.index(k), vec.value(k));
deba@481
   175
      ++b;
deba@481
   176
    }
deba@481
   177
  }
deba@481
   178
deba@482
   179
  void LpSoplex::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
deba@481
   180
    for (int i = 0; i < soplex->nRows(); ++i) {
deba@481
   181
      soplex->changeElement(i, j, 0.0);
deba@481
   182
    }
deba@482
   183
    for(ExprIterator it = b; it != e; ++it) {
deba@481
   184
      soplex->changeElement(it->first, j, it->second);
deba@481
   185
    }
deba@481
   186
  }
deba@481
   187
deba@482
   188
  void LpSoplex::_getColCoeffs(int i, InsertIterator b) const {
deba@481
   189
    const soplex::SVector& vec = soplex->colVector(i);
deba@481
   190
    for (int k = 0; k < vec.size(); ++k) {
deba@481
   191
      *b = std::make_pair(vec.index(k), vec.value(k));
deba@481
   192
      ++b;
deba@481
   193
    }
deba@481
   194
  }
deba@481
   195
deba@481
   196
  void LpSoplex::_setCoeff(int i, int j, Value value) {
deba@481
   197
    soplex->changeElement(i, j, value);
deba@481
   198
  }
deba@481
   199
deba@481
   200
  LpSoplex::Value LpSoplex::_getCoeff(int i, int j) const {
deba@481
   201
    return soplex->rowVector(i)[j];
deba@481
   202
  }
deba@481
   203
deba@481
   204
  void LpSoplex::_setColLowerBound(int i, Value value) {
deba@482
   205
    LEMON_ASSERT(value != INF, "Invalid bound");
deba@481
   206
    soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
deba@481
   207
  }
deba@481
   208
deba@481
   209
  LpSoplex::Value LpSoplex::_getColLowerBound(int i) const {
deba@481
   210
    double value = soplex->lower(i);
deba@481
   211
    return value != -soplex::infinity ? value : -INF;
deba@481
   212
  }
deba@481
   213
deba@481
   214
  void LpSoplex::_setColUpperBound(int i, Value value) {
deba@482
   215
    LEMON_ASSERT(value != -INF, "Invalid bound");
deba@481
   216
    soplex->changeUpper(i, value != INF ? value : soplex::infinity);
deba@481
   217
  }
deba@481
   218
deba@481
   219
  LpSoplex::Value LpSoplex::_getColUpperBound(int i) const {
deba@481
   220
    double value = soplex->upper(i);
deba@481
   221
    return value != soplex::infinity ? value : INF;
deba@481
   222
  }
deba@481
   223
deba@482
   224
  void LpSoplex::_setRowLowerBound(int i, Value lb) {
deba@482
   225
    LEMON_ASSERT(lb != INF, "Invalid bound");
deba@482
   226
    soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
deba@481
   227
  }
deba@482
   228
deba@482
   229
  LpSoplex::Value LpSoplex::_getRowLowerBound(int i) const {
deba@482
   230
    double res = soplex->lhs(i);
deba@482
   231
    return res == -soplex::infinity ? -INF : res;
deba@482
   232
  }
deba@482
   233
deba@482
   234
  void LpSoplex::_setRowUpperBound(int i, Value ub) {
deba@482
   235
    LEMON_ASSERT(ub != -INF, "Invalid bound");
deba@482
   236
    soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
deba@482
   237
  }
deba@482
   238
deba@482
   239
  LpSoplex::Value LpSoplex::_getRowUpperBound(int i) const {
deba@482
   240
    double res = soplex->rhs(i);
deba@482
   241
    return res == soplex::infinity ? INF : res;
deba@482
   242
  }
deba@482
   243
deba@482
   244
  void LpSoplex::_setObjCoeffs(ExprIterator b, ExprIterator e) {
deba@482
   245
    for (int j = 0; j < soplex->nCols(); ++j) {
deba@482
   246
      soplex->changeObj(j, 0.0);
deba@482
   247
    }
deba@482
   248
    for (ExprIterator it = b; it != e; ++it) {
deba@482
   249
      soplex->changeObj(it->first, it->second);
deba@482
   250
    }
deba@482
   251
  }
deba@482
   252
deba@482
   253
  void LpSoplex::_getObjCoeffs(InsertIterator b) const {
deba@482
   254
    for (int j = 0; j < soplex->nCols(); ++j) {
deba@482
   255
      Value coef = soplex->obj(j);
deba@482
   256
      if (coef != 0.0) {
deba@482
   257
        *b = std::make_pair(j, coef);
deba@482
   258
        ++b;
deba@482
   259
      }
deba@482
   260
    }
deba@481
   261
  }
deba@481
   262
deba@481
   263
  void LpSoplex::_setObjCoeff(int i, Value obj_coef) {
deba@481
   264
    soplex->changeObj(i, obj_coef);
deba@481
   265
  }
deba@481
   266
deba@481
   267
  LpSoplex::Value LpSoplex::_getObjCoeff(int i) const {
deba@481
   268
    return soplex->obj(i);
deba@481
   269
  }
deba@481
   270
deba@482
   271
  LpSoplex::SolveExitStatus LpSoplex::_solve() {
deba@481
   272
deba@482
   273
    _clear_temporals();
deba@482
   274
deba@481
   275
    soplex::SPxSolver::Status status = soplex->solve();
deba@481
   276
deba@481
   277
    switch (status) {
deba@481
   278
    case soplex::SPxSolver::OPTIMAL:
deba@481
   279
    case soplex::SPxSolver::INFEASIBLE:
deba@481
   280
    case soplex::SPxSolver::UNBOUNDED:
deba@481
   281
      return SOLVED;
deba@481
   282
    default:
deba@481
   283
      return UNSOLVED;
deba@481
   284
    }
deba@481
   285
  }
deba@481
   286
deba@481
   287
  LpSoplex::Value LpSoplex::_getPrimal(int i) const {
deba@482
   288
    if (_primal_values.empty()) {
deba@482
   289
      _primal_values.resize(soplex->nCols());
deba@482
   290
      soplex::Vector pv(_primal_values.size(), &_primal_values.front());
deba@482
   291
      soplex->getPrimal(pv);
deba@482
   292
    }
deba@482
   293
    return _primal_values[i];
deba@481
   294
  }
deba@481
   295
deba@481
   296
  LpSoplex::Value LpSoplex::_getDual(int i) const {
deba@482
   297
    if (_dual_values.empty()) {
deba@482
   298
      _dual_values.resize(soplex->nRows());
deba@482
   299
      soplex::Vector dv(_dual_values.size(), &_dual_values.front());
deba@482
   300
      soplex->getDual(dv);
deba@482
   301
    }
deba@482
   302
    return _dual_values[i];
deba@481
   303
  }
deba@481
   304
deba@481
   305
  LpSoplex::Value LpSoplex::_getPrimalValue() const {
deba@481
   306
    return soplex->objValue();
deba@481
   307
  }
deba@481
   308
deba@482
   309
  LpSoplex::VarStatus LpSoplex::_getColStatus(int i) const {
deba@482
   310
    switch (soplex->getBasisColStatus(i)) {
deba@482
   311
    case soplex::SPxSolver::BASIC:
deba@482
   312
      return BASIC;
deba@482
   313
    case soplex::SPxSolver::ON_UPPER:
deba@482
   314
      return UPPER;
deba@482
   315
    case soplex::SPxSolver::ON_LOWER:
deba@482
   316
      return LOWER;
deba@482
   317
    case soplex::SPxSolver::FIXED:
deba@482
   318
      return FIXED;
deba@482
   319
    case soplex::SPxSolver::ZERO:
deba@482
   320
      return FREE;
deba@482
   321
    default:
deba@482
   322
      LEMON_ASSERT(false, "Wrong column status");
deba@482
   323
      return VarStatus();
deba@482
   324
    }
deba@481
   325
  }
deba@481
   326
deba@482
   327
  LpSoplex::VarStatus LpSoplex::_getRowStatus(int i) const {
deba@482
   328
    switch (soplex->getBasisRowStatus(i)) {
deba@482
   329
    case soplex::SPxSolver::BASIC:
deba@482
   330
      return BASIC;
deba@482
   331
    case soplex::SPxSolver::ON_UPPER:
deba@482
   332
      return UPPER;
deba@482
   333
    case soplex::SPxSolver::ON_LOWER:
deba@482
   334
      return LOWER;
deba@482
   335
    case soplex::SPxSolver::FIXED:
deba@482
   336
      return FIXED;
deba@482
   337
    case soplex::SPxSolver::ZERO:
deba@482
   338
      return FREE;
deba@482
   339
    default:
deba@482
   340
      LEMON_ASSERT(false, "Wrong row status");
deba@482
   341
      return VarStatus();
deba@482
   342
    }
deba@482
   343
  }
deba@482
   344
deba@482
   345
  LpSoplex::Value LpSoplex::_getPrimalRay(int i) const {
deba@482
   346
    if (_primal_ray.empty()) {
deba@482
   347
      _primal_ray.resize(soplex->nCols());
deba@482
   348
      soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
deba@482
   349
      soplex->getDualfarkas(pv);
deba@482
   350
    }
deba@482
   351
    return _primal_ray[i];
deba@482
   352
  }
deba@482
   353
deba@482
   354
  LpSoplex::Value LpSoplex::_getDualRay(int i) const {
deba@482
   355
    if (_dual_ray.empty()) {
deba@482
   356
      _dual_ray.resize(soplex->nRows());
deba@482
   357
      soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
deba@482
   358
      soplex->getDualfarkas(dv);
deba@482
   359
    }
deba@482
   360
    return _dual_ray[i];
deba@482
   361
  }
deba@482
   362
deba@482
   363
  LpSoplex::ProblemType LpSoplex::_getPrimalType() const {
deba@481
   364
    switch (soplex->status()) {
deba@481
   365
    case soplex::SPxSolver::OPTIMAL:
deba@481
   366
      return OPTIMAL;
deba@481
   367
    case soplex::SPxSolver::UNBOUNDED:
deba@482
   368
      return UNBOUNDED;
deba@481
   369
    case soplex::SPxSolver::INFEASIBLE:
deba@481
   370
      return INFEASIBLE;
deba@481
   371
    default:
deba@481
   372
      return UNDEFINED;
deba@481
   373
    }
deba@481
   374
  }
deba@481
   375
deba@482
   376
  LpSoplex::ProblemType LpSoplex::_getDualType() const {
deba@481
   377
    switch (soplex->status()) {
deba@481
   378
    case soplex::SPxSolver::OPTIMAL:
deba@481
   379
      return OPTIMAL;
deba@481
   380
    case soplex::SPxSolver::UNBOUNDED:
deba@482
   381
      return UNBOUNDED;
deba@482
   382
    case soplex::SPxSolver::INFEASIBLE:
deba@481
   383
      return INFEASIBLE;
deba@481
   384
    default:
deba@481
   385
      return UNDEFINED;
deba@481
   386
    }
deba@481
   387
  }
deba@481
   388
deba@482
   389
  void LpSoplex::_setSense(Sense sense) {
deba@482
   390
    switch (sense) {
deba@482
   391
    case MIN:
deba@482
   392
      soplex->changeSense(soplex::SPxSolver::MINIMIZE);
deba@482
   393
      break;
deba@482
   394
    case MAX:
deba@482
   395
      soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
deba@481
   396
    }
deba@481
   397
  }
deba@481
   398
deba@482
   399
  LpSoplex::Sense LpSoplex::_getSense() const {
deba@482
   400
    switch (soplex->spxSense()) {
deba@482
   401
    case soplex::SPxSolver::MAXIMIZE:
deba@482
   402
      return MAX;
deba@482
   403
    case soplex::SPxSolver::MINIMIZE:
deba@482
   404
      return MIN;
deba@482
   405
    default:
deba@482
   406
      LEMON_ASSERT(false, "Wrong sense.");
deba@482
   407
      return LpSoplex::Sense();
deba@482
   408
    }
deba@481
   409
  }
deba@481
   410
deba@482
   411
  void LpSoplex::_clear() {
deba@482
   412
    soplex->clear();
deba@482
   413
    _col_names.clear();
deba@482
   414
    _col_names_ref.clear();
deba@482
   415
    _row_names.clear();
deba@482
   416
    _row_names_ref.clear();
deba@482
   417
    cols.clear();
deba@482
   418
    rows.clear();
deba@482
   419
    _clear_temporals();
deba@482
   420
  }
deba@481
   421
deba@481
   422
} //namespace lemon
deba@481
   423