lemon/lp_soplex.cc
author Balazs Dezso <deba@inf.elte.hu>
Tue, 02 Dec 2008 21:40:33 +0100
changeset 458 7afc121e0689
child 459 ed54c0d13df0
permissions -rw-r--r--
Port LP and MIP solvers from SVN -r3509 (#44)
deba@458
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@458
     2
 *
deba@458
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@458
     4
 *
deba@458
     5
 * Copyright (C) 2003-2008
deba@458
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@458
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@458
     8
 *
deba@458
     9
 * Permission to use, modify and distribute this software is granted
deba@458
    10
 * provided that this copyright notice appears in all copies. For
deba@458
    11
 * precise terms see the accompanying LICENSE file.
deba@458
    12
 *
deba@458
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@458
    14
 * express or implied, and with no claim as to its suitability for any
deba@458
    15
 * purpose.
deba@458
    16
 *
deba@458
    17
 */
deba@458
    18
deba@458
    19
#include<iostream>
deba@458
    20
#include<lemon/lp_soplex.h>
deba@458
    21
deba@458
    22
#include <soplex/soplex.h>
deba@458
    23
deba@458
    24
deba@458
    25
///\file
deba@458
    26
///\brief Implementation of the LEMON-SOPLEX lp solver interface.
deba@458
    27
namespace lemon {
deba@458
    28
deba@458
    29
  LpSoplex::LpSoplex() : LpSolverBase() {
deba@458
    30
    rows.setIdHandler(relocateIdHandler);
deba@458
    31
    cols.setIdHandler(relocateIdHandler);
deba@458
    32
    soplex = new soplex::SoPlex;
deba@458
    33
    solved = false;
deba@458
    34
  }
deba@458
    35
deba@458
    36
  LpSoplex::~LpSoplex() {
deba@458
    37
    delete soplex;
deba@458
    38
  }
deba@458
    39
deba@458
    40
  LpSoplex::LpSoplex(const LpSoplex& lp) : LpSolverBase() {
deba@458
    41
    rows = lp.rows;
deba@458
    42
    rows.setIdHandler(relocateIdHandler);
deba@458
    43
deba@458
    44
    cols = lp.cols;
deba@458
    45
    cols.setIdHandler(relocateIdHandler);
deba@458
    46
deba@458
    47
    soplex = new soplex::SoPlex;
deba@458
    48
    (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
deba@458
    49
deba@458
    50
    colNames = lp.colNames;
deba@458
    51
    invColNames = lp.invColNames;
deba@458
    52
deba@458
    53
    primal_value = lp.primal_value;
deba@458
    54
    dual_value = lp.dual_value;
deba@458
    55
deba@458
    56
  }
deba@458
    57
deba@458
    58
  LpSolverBase* LpSoplex::_newLp() {
deba@458
    59
    LpSoplex* newlp = new LpSoplex();
deba@458
    60
    return newlp;
deba@458
    61
  }
deba@458
    62
deba@458
    63
  LpSolverBase* LpSoplex::_copyLp() {
deba@458
    64
    LpSoplex* newlp = new LpSoplex(*this);
deba@458
    65
    return newlp;
deba@458
    66
  }
deba@458
    67
deba@458
    68
  int LpSoplex::_addCol() {
deba@458
    69
    soplex::LPCol c;
deba@458
    70
    c.setLower(-soplex::infinity);
deba@458
    71
    c.setUpper(soplex::infinity);
deba@458
    72
    soplex->addCol(c);
deba@458
    73
deba@458
    74
    colNames.push_back(std::string());
deba@458
    75
    primal_value.push_back(0.0);
deba@458
    76
    solved = false;
deba@458
    77
deba@458
    78
    return soplex->nCols() - 1;
deba@458
    79
  }
deba@458
    80
deba@458
    81
  int LpSoplex::_addRow() {
deba@458
    82
    soplex::LPRow r;
deba@458
    83
    r.setLhs(-soplex::infinity);
deba@458
    84
    r.setRhs(soplex::infinity);
deba@458
    85
    soplex->addRow(r);
deba@458
    86
deba@458
    87
    dual_value.push_back(0.0);
deba@458
    88
    solved = false;
deba@458
    89
deba@458
    90
    return soplex->nRows() - 1;
deba@458
    91
  }
deba@458
    92
deba@458
    93
deba@458
    94
  void LpSoplex::_eraseCol(int i) {
deba@458
    95
    soplex->removeCol(i);
deba@458
    96
    invColNames.erase(colNames[i]);
deba@458
    97
    colNames[i] = colNames.back();
deba@458
    98
    invColNames[colNames.back()] = i;
deba@458
    99
    colNames.pop_back();
deba@458
   100
    primal_value[i] = primal_value.back();
deba@458
   101
    primal_value.pop_back();
deba@458
   102
    solved = false;
deba@458
   103
  }
deba@458
   104
deba@458
   105
  void LpSoplex::_eraseRow(int i) {
deba@458
   106
    soplex->removeRow(i);
deba@458
   107
    dual_value[i] = dual_value.back();
deba@458
   108
    dual_value.pop_back();
deba@458
   109
    solved = false;
deba@458
   110
  }
deba@458
   111
deba@458
   112
  void LpSoplex::_getColName(int c, std::string &name) const {
deba@458
   113
    name = colNames[c];
deba@458
   114
  }
deba@458
   115
deba@458
   116
  void LpSoplex::_setColName(int c, const std::string &name) {
deba@458
   117
    invColNames.erase(colNames[c]);
deba@458
   118
    colNames[c] = name;
deba@458
   119
    if (!name.empty()) {
deba@458
   120
      invColNames.insert(std::make_pair(name, c));
deba@458
   121
    }
deba@458
   122
  }
deba@458
   123
deba@458
   124
  int LpSoplex::_colByName(const std::string& name) const {
deba@458
   125
    std::map<std::string, int>::const_iterator it =
deba@458
   126
      invColNames.find(name);
deba@458
   127
    if (it != invColNames.end()) {
deba@458
   128
      return it->second;
deba@458
   129
    } else {
deba@458
   130
      return -1;
deba@458
   131
    }
deba@458
   132
  }
deba@458
   133
deba@458
   134
deba@458
   135
  void LpSoplex::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e) {
deba@458
   136
    for (int j = 0; j < soplex->nCols(); ++j) {
deba@458
   137
      soplex->changeElement(i, j, 0.0);
deba@458
   138
    }
deba@458
   139
    for(ConstRowIterator it = b; it != e; ++it) {
deba@458
   140
      soplex->changeElement(i, it->first, it->second);
deba@458
   141
    }
deba@458
   142
    solved = false;
deba@458
   143
  }
deba@458
   144
deba@458
   145
  void LpSoplex::_getRowCoeffs(int i, RowIterator b) const {
deba@458
   146
    const soplex::SVector& vec = soplex->rowVector(i);
deba@458
   147
    for (int k = 0; k < vec.size(); ++k) {
deba@458
   148
      *b = std::make_pair(vec.index(k), vec.value(k));
deba@458
   149
      ++b;
deba@458
   150
    }
deba@458
   151
  }
deba@458
   152
deba@458
   153
  void LpSoplex::_setColCoeffs(int j, ConstColIterator b, ConstColIterator e) {
deba@458
   154
    for (int i = 0; i < soplex->nRows(); ++i) {
deba@458
   155
      soplex->changeElement(i, j, 0.0);
deba@458
   156
    }
deba@458
   157
    for(ConstColIterator it = b; it != e; ++it) {
deba@458
   158
      soplex->changeElement(it->first, j, it->second);
deba@458
   159
    }
deba@458
   160
    solved = false;
deba@458
   161
  }
deba@458
   162
deba@458
   163
  void LpSoplex::_getColCoeffs(int i, ColIterator b) const {
deba@458
   164
    const soplex::SVector& vec = soplex->colVector(i);
deba@458
   165
    for (int k = 0; k < vec.size(); ++k) {
deba@458
   166
      *b = std::make_pair(vec.index(k), vec.value(k));
deba@458
   167
      ++b;
deba@458
   168
    }
deba@458
   169
  }
deba@458
   170
deba@458
   171
  void LpSoplex::_setCoeff(int i, int j, Value value) {
deba@458
   172
    soplex->changeElement(i, j, value);
deba@458
   173
    solved = false;
deba@458
   174
  }
deba@458
   175
deba@458
   176
  LpSoplex::Value LpSoplex::_getCoeff(int i, int j) const {
deba@458
   177
    return soplex->rowVector(i)[j];
deba@458
   178
  }
deba@458
   179
deba@458
   180
  void LpSoplex::_setColLowerBound(int i, Value value) {
deba@458
   181
    soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
deba@458
   182
    solved = false;
deba@458
   183
  }
deba@458
   184
deba@458
   185
  LpSoplex::Value LpSoplex::_getColLowerBound(int i) const {
deba@458
   186
    double value = soplex->lower(i);
deba@458
   187
    return value != -soplex::infinity ? value : -INF;
deba@458
   188
  }
deba@458
   189
deba@458
   190
  void LpSoplex::_setColUpperBound(int i, Value value) {
deba@458
   191
    soplex->changeUpper(i, value != INF ? value : soplex::infinity);
deba@458
   192
    solved = false;
deba@458
   193
  }
deba@458
   194
deba@458
   195
  LpSoplex::Value LpSoplex::_getColUpperBound(int i) const {
deba@458
   196
    double value = soplex->upper(i);
deba@458
   197
    return value != soplex::infinity ? value : INF;
deba@458
   198
  }
deba@458
   199
deba@458
   200
  void LpSoplex::_setRowBounds(int i, Value lb, Value ub) {
deba@458
   201
    soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity,
deba@458
   202
                        ub != INF ? ub : soplex::infinity);
deba@458
   203
    solved = false;
deba@458
   204
  }
deba@458
   205
  void LpSoplex::_getRowBounds(int i, Value &lower, Value &upper) const {
deba@458
   206
    lower = soplex->lhs(i);
deba@458
   207
    if (lower == -soplex::infinity) lower = -INF;
deba@458
   208
    upper = soplex->rhs(i);
deba@458
   209
    if (upper == -soplex::infinity) upper = INF;
deba@458
   210
  }
deba@458
   211
deba@458
   212
  void LpSoplex::_setObjCoeff(int i, Value obj_coef) {
deba@458
   213
    soplex->changeObj(i, obj_coef);
deba@458
   214
    solved = false;
deba@458
   215
  }
deba@458
   216
deba@458
   217
  LpSoplex::Value LpSoplex::_getObjCoeff(int i) const {
deba@458
   218
    return soplex->obj(i);
deba@458
   219
  }
deba@458
   220
deba@458
   221
  void LpSoplex::_clearObj() {
deba@458
   222
    for (int i = 0; i < soplex->nCols(); ++i) {
deba@458
   223
      soplex->changeObj(i, 0.0);
deba@458
   224
    }
deba@458
   225
    solved = false;
deba@458
   226
  }
deba@458
   227
deba@458
   228
  LpSoplex::SolveExitStatus LpSoplex::_solve() {
deba@458
   229
    soplex::SPxSolver::Status status = soplex->solve();
deba@458
   230
deba@458
   231
    soplex::Vector pv(primal_value.size(), &primal_value[0]);
deba@458
   232
    soplex->getPrimal(pv);
deba@458
   233
deba@458
   234
    soplex::Vector dv(dual_value.size(), &dual_value[0]);
deba@458
   235
    soplex->getDual(dv);
deba@458
   236
deba@458
   237
    switch (status) {
deba@458
   238
    case soplex::SPxSolver::OPTIMAL:
deba@458
   239
    case soplex::SPxSolver::INFEASIBLE:
deba@458
   240
    case soplex::SPxSolver::UNBOUNDED:
deba@458
   241
      solved = true;
deba@458
   242
      return SOLVED;
deba@458
   243
    default:
deba@458
   244
      return UNSOLVED;
deba@458
   245
    }
deba@458
   246
  }
deba@458
   247
deba@458
   248
  LpSoplex::Value LpSoplex::_getPrimal(int i) const {
deba@458
   249
    return primal_value[i];
deba@458
   250
  }
deba@458
   251
deba@458
   252
  LpSoplex::Value LpSoplex::_getDual(int i) const {
deba@458
   253
    return dual_value[i];
deba@458
   254
  }
deba@458
   255
deba@458
   256
  LpSoplex::Value LpSoplex::_getPrimalValue() const {
deba@458
   257
    return soplex->objValue();
deba@458
   258
  }
deba@458
   259
deba@458
   260
  bool LpSoplex::_isBasicCol(int i) const {
deba@458
   261
    return soplex->getBasisColStatus(i) == soplex::SPxSolver::BASIC;
deba@458
   262
  }
deba@458
   263
deba@458
   264
  LpSoplex::SolutionStatus LpSoplex::_getPrimalStatus() const {
deba@458
   265
    if (!solved) return UNDEFINED;
deba@458
   266
    switch (soplex->status()) {
deba@458
   267
    case soplex::SPxSolver::OPTIMAL:
deba@458
   268
      return OPTIMAL;
deba@458
   269
    case soplex::SPxSolver::UNBOUNDED:
deba@458
   270
      return INFINITE;
deba@458
   271
    case soplex::SPxSolver::INFEASIBLE:
deba@458
   272
      return INFEASIBLE;
deba@458
   273
    default:
deba@458
   274
      return UNDEFINED;
deba@458
   275
    }
deba@458
   276
  }
deba@458
   277
deba@458
   278
  LpSoplex::SolutionStatus LpSoplex::_getDualStatus() const {
deba@458
   279
    if (!solved) return UNDEFINED;
deba@458
   280
    switch (soplex->status()) {
deba@458
   281
    case soplex::SPxSolver::OPTIMAL:
deba@458
   282
      return OPTIMAL;
deba@458
   283
    case soplex::SPxSolver::UNBOUNDED:
deba@458
   284
      return INFEASIBLE;
deba@458
   285
    default:
deba@458
   286
      return UNDEFINED;
deba@458
   287
    }
deba@458
   288
  }
deba@458
   289
deba@458
   290
  LpSoplex::ProblemTypes LpSoplex::_getProblemType() const {
deba@458
   291
    if (!solved) return UNKNOWN;
deba@458
   292
    switch (soplex->status()) {
deba@458
   293
    case soplex::SPxSolver::OPTIMAL:
deba@458
   294
      return PRIMAL_DUAL_FEASIBLE;
deba@458
   295
    case soplex::SPxSolver::UNBOUNDED:
deba@458
   296
      return PRIMAL_FEASIBLE_DUAL_INFEASIBLE;
deba@458
   297
    default:
deba@458
   298
      return UNKNOWN;
deba@458
   299
    }
deba@458
   300
  }
deba@458
   301
deba@458
   302
  void LpSoplex::_setMax() {
deba@458
   303
    soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
deba@458
   304
    solved = false;
deba@458
   305
  }
deba@458
   306
  void LpSoplex::_setMin() {
deba@458
   307
    soplex->changeSense(soplex::SPxSolver::MINIMIZE);
deba@458
   308
    solved = false;
deba@458
   309
  }
deba@458
   310
  bool LpSoplex::_isMax() const {
deba@458
   311
    return soplex->spxSense() == soplex::SPxSolver::MAXIMIZE;
deba@458
   312
  }
deba@458
   313
deba@458
   314
deba@458
   315
} //namespace lemon
deba@458
   316