lemon/lp_clp.cc
author Balazs Dezso <deba@inf.elte.hu>
Tue, 02 Dec 2008 22:48:28 +0100
changeset 482 ed54c0d13df0
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@482
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@482
     2
 *
deba@482
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@482
     4
 *
deba@482
     5
 * Copyright (C) 2003-2008
deba@482
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@482
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@482
     8
 *
deba@482
     9
 * Permission to use, modify and distribute this software is granted
deba@482
    10
 * provided that this copyright notice appears in all copies. For
deba@482
    11
 * precise terms see the accompanying LICENSE file.
deba@482
    12
 *
deba@482
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@482
    14
 * express or implied, and with no claim as to its suitability for any
deba@482
    15
 * purpose.
deba@482
    16
 *
deba@482
    17
 */
deba@482
    18
deba@482
    19
#include <lemon/lp_clp.h>
deba@482
    20
#include <coin/ClpSimplex.hpp>
deba@482
    21
deba@482
    22
namespace lemon {
deba@482
    23
deba@482
    24
  LpClp::LpClp() {
deba@482
    25
    _prob = new ClpSimplex();
deba@482
    26
    _init_temporals();
deba@482
    27
    messageLevel(MESSAGE_NO_OUTPUT);
deba@482
    28
  }
deba@482
    29
deba@482
    30
  LpClp::LpClp(const LpClp& other) {
deba@482
    31
    _prob = new ClpSimplex(*other._prob);
deba@482
    32
    rows = other.rows;
deba@482
    33
    cols = other.cols;
deba@482
    34
    _init_temporals();
deba@482
    35
    messageLevel(MESSAGE_NO_OUTPUT);
deba@482
    36
  }
deba@482
    37
deba@482
    38
  LpClp::~LpClp() {
deba@482
    39
    delete _prob;
deba@482
    40
    _clear_temporals();
deba@482
    41
  }
deba@482
    42
deba@482
    43
  void LpClp::_init_temporals() {
deba@482
    44
    _primal_ray = 0;
deba@482
    45
    _dual_ray = 0;
deba@482
    46
  }
deba@482
    47
deba@482
    48
  void LpClp::_clear_temporals() {
deba@482
    49
    if (_primal_ray) {
deba@482
    50
      delete[] _primal_ray;
deba@482
    51
      _primal_ray = 0;
deba@482
    52
    }
deba@482
    53
    if (_dual_ray) {
deba@482
    54
      delete[] _dual_ray;
deba@482
    55
      _dual_ray = 0;
deba@482
    56
    }
deba@482
    57
  }
deba@482
    58
deba@482
    59
  LpClp* LpClp::_newSolver() const {
deba@482
    60
    LpClp* newlp = new LpClp;
deba@482
    61
    return newlp;
deba@482
    62
  }
deba@482
    63
deba@482
    64
  LpClp* LpClp::_cloneSolver() const {
deba@482
    65
    LpClp* copylp = new LpClp(*this);
deba@482
    66
    return copylp;
deba@482
    67
  }
deba@482
    68
deba@482
    69
  const char* LpClp::_solverName() const { return "LpClp"; }
deba@482
    70
deba@482
    71
  int LpClp::_addCol() {
deba@482
    72
    _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0);
deba@482
    73
    return _prob->numberColumns() - 1;
deba@482
    74
  }
deba@482
    75
deba@482
    76
  int LpClp::_addRow() {
deba@482
    77
    _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
deba@482
    78
    return _prob->numberRows() - 1;
deba@482
    79
  }
deba@482
    80
deba@482
    81
deba@482
    82
  void LpClp::_eraseCol(int c) {
deba@482
    83
    _col_names_ref.erase(_prob->getColumnName(c));
deba@482
    84
    _prob->deleteColumns(1, &c);
deba@482
    85
  }
deba@482
    86
deba@482
    87
  void LpClp::_eraseRow(int r) {
deba@482
    88
    _row_names_ref.erase(_prob->getRowName(r));
deba@482
    89
    _prob->deleteRows(1, &r);
deba@482
    90
  }
deba@482
    91
deba@482
    92
  void LpClp::_eraseColId(int i) {
deba@482
    93
    cols.eraseIndex(i);
deba@482
    94
    cols.shiftIndices(i);
deba@482
    95
  }
deba@482
    96
deba@482
    97
  void LpClp::_eraseRowId(int i) {
deba@482
    98
    rows.eraseIndex(i);
deba@482
    99
    rows.shiftIndices(i);
deba@482
   100
  }
deba@482
   101
deba@482
   102
  void LpClp::_getColName(int c, std::string& name) const {
deba@482
   103
    name = _prob->getColumnName(c);
deba@482
   104
  }
deba@482
   105
deba@482
   106
  void LpClp::_setColName(int c, const std::string& name) {
deba@482
   107
    _prob->setColumnName(c, const_cast<std::string&>(name));
deba@482
   108
    _col_names_ref[name] = c;
deba@482
   109
  }
deba@482
   110
deba@482
   111
  int LpClp::_colByName(const std::string& name) const {
deba@482
   112
    std::map<std::string, int>::const_iterator it = _col_names_ref.find(name);
deba@482
   113
    return it != _col_names_ref.end() ? it->second : -1;
deba@482
   114
  }
deba@482
   115
deba@482
   116
  void LpClp::_getRowName(int r, std::string& name) const {
deba@482
   117
    name = _prob->getRowName(r);
deba@482
   118
  }
deba@482
   119
deba@482
   120
  void LpClp::_setRowName(int r, const std::string& name) {
deba@482
   121
    _prob->setRowName(r, const_cast<std::string&>(name));
deba@482
   122
    _row_names_ref[name] = r;
deba@482
   123
  }
deba@482
   124
deba@482
   125
  int LpClp::_rowByName(const std::string& name) const {
deba@482
   126
    std::map<std::string, int>::const_iterator it = _row_names_ref.find(name);
deba@482
   127
    return it != _row_names_ref.end() ? it->second : -1;
deba@482
   128
  }
deba@482
   129
deba@482
   130
deba@482
   131
  void LpClp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) {
deba@482
   132
    std::map<int, Value> coeffs;
deba@482
   133
deba@482
   134
    int n = _prob->clpMatrix()->getNumCols();
deba@482
   135
deba@482
   136
    const int* indices = _prob->clpMatrix()->getIndices();
deba@482
   137
    const double* elements = _prob->clpMatrix()->getElements();
deba@482
   138
deba@482
   139
    for (int i = 0; i < n; ++i) {
deba@482
   140
      CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
deba@482
   141
      CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
deba@482
   142
deba@482
   143
      const int* it = std::lower_bound(indices + begin, indices + end, ix);
deba@482
   144
      if (it != indices + end && *it == ix && elements[it - indices] != 0.0) {
deba@482
   145
        coeffs[i] = 0.0;
deba@482
   146
      }
deba@482
   147
    }
deba@482
   148
deba@482
   149
    for (ExprIterator it = b; it != e; ++it) {
deba@482
   150
      coeffs[it->first] = it->second;
deba@482
   151
    }
deba@482
   152
deba@482
   153
    for (std::map<int, Value>::iterator it = coeffs.begin();
deba@482
   154
         it != coeffs.end(); ++it) {
deba@482
   155
      _prob->modifyCoefficient(ix, it->first, it->second);
deba@482
   156
    }
deba@482
   157
  }
deba@482
   158
deba@482
   159
  void LpClp::_getRowCoeffs(int ix, InsertIterator b) const {
deba@482
   160
    int n = _prob->clpMatrix()->getNumCols();
deba@482
   161
deba@482
   162
    const int* indices = _prob->clpMatrix()->getIndices();
deba@482
   163
    const double* elements = _prob->clpMatrix()->getElements();
deba@482
   164
deba@482
   165
    for (int i = 0; i < n; ++i) {
deba@482
   166
      CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
deba@482
   167
      CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
deba@482
   168
deba@482
   169
      const int* it = std::lower_bound(indices + begin, indices + end, ix);
deba@482
   170
      if (it != indices + end && *it == ix) {
deba@482
   171
        *b = std::make_pair(i, elements[it - indices]);
deba@482
   172
      }
deba@482
   173
    }
deba@482
   174
  }
deba@482
   175
deba@482
   176
  void LpClp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
deba@482
   177
    std::map<int, Value> coeffs;
deba@482
   178
deba@482
   179
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
deba@482
   180
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
deba@482
   181
deba@482
   182
    const int* indices = _prob->clpMatrix()->getIndices();
deba@482
   183
    const double* elements = _prob->clpMatrix()->getElements();
deba@482
   184
deba@482
   185
    for (CoinBigIndex i = begin; i != end; ++i) {
deba@482
   186
      if (elements[i] != 0.0) {
deba@482
   187
        coeffs[indices[i]] = 0.0;
deba@482
   188
      }
deba@482
   189
    }
deba@482
   190
    for (ExprIterator it = b; it != e; ++it) {
deba@482
   191
      coeffs[it->first] = it->second;
deba@482
   192
    }
deba@482
   193
    for (std::map<int, Value>::iterator it = coeffs.begin();
deba@482
   194
         it != coeffs.end(); ++it) {
deba@482
   195
      _prob->modifyCoefficient(it->first, ix, it->second);
deba@482
   196
    }
deba@482
   197
  }
deba@482
   198
deba@482
   199
  void LpClp::_getColCoeffs(int ix, InsertIterator b) const {
deba@482
   200
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
deba@482
   201
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
deba@482
   202
deba@482
   203
    const int* indices = _prob->clpMatrix()->getIndices();
deba@482
   204
    const double* elements = _prob->clpMatrix()->getElements();
deba@482
   205
deba@482
   206
    for (CoinBigIndex i = begin; i != end; ++i) {
deba@482
   207
      *b = std::make_pair(indices[i], elements[i]);
deba@482
   208
      ++b;
deba@482
   209
    }
deba@482
   210
  }
deba@482
   211
deba@482
   212
  void LpClp::_setCoeff(int ix, int jx, Value value) {
deba@482
   213
    _prob->modifyCoefficient(ix, jx, value);
deba@482
   214
  }
deba@482
   215
deba@482
   216
  LpClp::Value LpClp::_getCoeff(int ix, int jx) const {
deba@482
   217
    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
deba@482
   218
    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
deba@482
   219
deba@482
   220
    const int* indices = _prob->clpMatrix()->getIndices();
deba@482
   221
    const double* elements = _prob->clpMatrix()->getElements();
deba@482
   222
deba@482
   223
    const int* it = std::lower_bound(indices + begin, indices + end, jx);
deba@482
   224
    if (it != indices + end && *it == jx) {
deba@482
   225
      return elements[it - indices];
deba@482
   226
    } else {
deba@482
   227
      return 0.0;
deba@482
   228
    }
deba@482
   229
  }
deba@482
   230
deba@482
   231
  void LpClp::_setColLowerBound(int i, Value lo) {
deba@482
   232
    _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
deba@482
   233
  }
deba@482
   234
deba@482
   235
  LpClp::Value LpClp::_getColLowerBound(int i) const {
deba@482
   236
    double val = _prob->getColLower()[i];
deba@482
   237
    return val == - COIN_DBL_MAX ? - INF : val;
deba@482
   238
  }
deba@482
   239
deba@482
   240
  void LpClp::_setColUpperBound(int i, Value up) {
deba@482
   241
    _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
deba@482
   242
  }
deba@482
   243
deba@482
   244
  LpClp::Value LpClp::_getColUpperBound(int i) const {
deba@482
   245
    double val = _prob->getColUpper()[i];
deba@482
   246
    return val == COIN_DBL_MAX ? INF : val;
deba@482
   247
  }
deba@482
   248
deba@482
   249
  void LpClp::_setRowLowerBound(int i, Value lo) {
deba@482
   250
    _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
deba@482
   251
  }
deba@482
   252
deba@482
   253
  LpClp::Value LpClp::_getRowLowerBound(int i) const {
deba@482
   254
    double val = _prob->getRowLower()[i];
deba@482
   255
    return val == - COIN_DBL_MAX ? - INF : val;
deba@482
   256
  }
deba@482
   257
deba@482
   258
  void LpClp::_setRowUpperBound(int i, Value up) {
deba@482
   259
    _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
deba@482
   260
  }
deba@482
   261
deba@482
   262
  LpClp::Value LpClp::_getRowUpperBound(int i) const {
deba@482
   263
    double val = _prob->getRowUpper()[i];
deba@482
   264
    return val == COIN_DBL_MAX ? INF : val;
deba@482
   265
  }
deba@482
   266
deba@482
   267
  void LpClp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
deba@482
   268
    int num = _prob->clpMatrix()->getNumCols();
deba@482
   269
    for (int i = 0; i < num; ++i) {
deba@482
   270
      _prob->setObjectiveCoefficient(i, 0.0);
deba@482
   271
    }
deba@482
   272
    for (ExprIterator it = b; it != e; ++it) {
deba@482
   273
      _prob->setObjectiveCoefficient(it->first, it->second);
deba@482
   274
    }
deba@482
   275
  }
deba@482
   276
deba@482
   277
  void LpClp::_getObjCoeffs(InsertIterator b) const {
deba@482
   278
    int num = _prob->clpMatrix()->getNumCols();
deba@482
   279
    for (int i = 0; i < num; ++i) {
deba@482
   280
      Value coef = _prob->getObjCoefficients()[i];
deba@482
   281
      if (coef != 0.0) {
deba@482
   282
        *b = std::make_pair(i, coef);
deba@482
   283
        ++b;
deba@482
   284
      }
deba@482
   285
    }
deba@482
   286
  }
deba@482
   287
deba@482
   288
  void LpClp::_setObjCoeff(int i, Value obj_coef) {
deba@482
   289
    _prob->setObjectiveCoefficient(i, obj_coef);
deba@482
   290
  }
deba@482
   291
deba@482
   292
  LpClp::Value LpClp::_getObjCoeff(int i) const {
deba@482
   293
    return _prob->getObjCoefficients()[i];
deba@482
   294
  }
deba@482
   295
deba@482
   296
  LpClp::SolveExitStatus LpClp::_solve() {
deba@482
   297
    return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
deba@482
   298
  }
deba@482
   299
deba@482
   300
  LpClp::SolveExitStatus LpClp::solvePrimal() {
deba@482
   301
    return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
deba@482
   302
  }
deba@482
   303
deba@482
   304
  LpClp::SolveExitStatus LpClp::solveDual() {
deba@482
   305
    return _prob->dual() >= 0 ? SOLVED : UNSOLVED;
deba@482
   306
  }
deba@482
   307
deba@482
   308
  LpClp::SolveExitStatus LpClp::solveBarrier() {
deba@482
   309
    return _prob->barrier() >= 0 ? SOLVED : UNSOLVED;
deba@482
   310
  }
deba@482
   311
deba@482
   312
  LpClp::Value LpClp::_getPrimal(int i) const {
deba@482
   313
    return _prob->primalColumnSolution()[i];
deba@482
   314
  }
deba@482
   315
  LpClp::Value LpClp::_getPrimalValue() const {
deba@482
   316
    return _prob->objectiveValue();
deba@482
   317
  }
deba@482
   318
deba@482
   319
  LpClp::Value LpClp::_getDual(int i) const {
deba@482
   320
    return _prob->dualRowSolution()[i];
deba@482
   321
  }
deba@482
   322
deba@482
   323
  LpClp::Value LpClp::_getPrimalRay(int i) const {
deba@482
   324
    if (!_primal_ray) {
deba@482
   325
      _primal_ray = _prob->unboundedRay();
deba@482
   326
      LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided");
deba@482
   327
    }
deba@482
   328
    return _primal_ray[i];
deba@482
   329
  }
deba@482
   330
deba@482
   331
  LpClp::Value LpClp::_getDualRay(int i) const {
deba@482
   332
    if (!_dual_ray) {
deba@482
   333
      _dual_ray = _prob->infeasibilityRay();
deba@482
   334
      LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided");
deba@482
   335
    }
deba@482
   336
    return _dual_ray[i];
deba@482
   337
  }
deba@482
   338
deba@482
   339
  LpClp::VarStatus LpClp::_getColStatus(int i) const {
deba@482
   340
    switch (_prob->getColumnStatus(i)) {
deba@482
   341
    case ClpSimplex::basic:
deba@482
   342
      return BASIC;
deba@482
   343
    case ClpSimplex::isFree:
deba@482
   344
      return FREE;
deba@482
   345
    case ClpSimplex::atUpperBound:
deba@482
   346
      return UPPER;
deba@482
   347
    case ClpSimplex::atLowerBound:
deba@482
   348
      return LOWER;
deba@482
   349
    case ClpSimplex::isFixed:
deba@482
   350
      return FIXED;
deba@482
   351
    case ClpSimplex::superBasic:
deba@482
   352
      return FREE;
deba@482
   353
    default:
deba@482
   354
      LEMON_ASSERT(false, "Wrong column status");
deba@482
   355
      return VarStatus();
deba@482
   356
    }
deba@482
   357
  }
deba@482
   358
deba@482
   359
  LpClp::VarStatus LpClp::_getRowStatus(int i) const {
deba@482
   360
    switch (_prob->getColumnStatus(i)) {
deba@482
   361
    case ClpSimplex::basic:
deba@482
   362
      return BASIC;
deba@482
   363
    case ClpSimplex::isFree:
deba@482
   364
      return FREE;
deba@482
   365
    case ClpSimplex::atUpperBound:
deba@482
   366
      return UPPER;
deba@482
   367
    case ClpSimplex::atLowerBound:
deba@482
   368
      return LOWER;
deba@482
   369
    case ClpSimplex::isFixed:
deba@482
   370
      return FIXED;
deba@482
   371
    case ClpSimplex::superBasic:
deba@482
   372
      return FREE;
deba@482
   373
    default:
deba@482
   374
      LEMON_ASSERT(false, "Wrong row status");
deba@482
   375
      return VarStatus();
deba@482
   376
    }
deba@482
   377
  }
deba@482
   378
deba@482
   379
deba@482
   380
  LpClp::ProblemType LpClp::_getPrimalType() const {
deba@482
   381
    if (_prob->isProvenOptimal()) {
deba@482
   382
      return OPTIMAL;
deba@482
   383
    } else if (_prob->isProvenPrimalInfeasible()) {
deba@482
   384
      return INFEASIBLE;
deba@482
   385
    } else if (_prob->isProvenDualInfeasible()) {
deba@482
   386
      return UNBOUNDED;
deba@482
   387
    } else {
deba@482
   388
      return UNDEFINED;
deba@482
   389
    }
deba@482
   390
  }
deba@482
   391
deba@482
   392
  LpClp::ProblemType LpClp::_getDualType() const {
deba@482
   393
    if (_prob->isProvenOptimal()) {
deba@482
   394
      return OPTIMAL;
deba@482
   395
    } else if (_prob->isProvenDualInfeasible()) {
deba@482
   396
      return INFEASIBLE;
deba@482
   397
    } else if (_prob->isProvenPrimalInfeasible()) {
deba@482
   398
      return INFEASIBLE;
deba@482
   399
    } else {
deba@482
   400
      return UNDEFINED;
deba@482
   401
    }
deba@482
   402
  }
deba@482
   403
deba@482
   404
  void LpClp::_setSense(LpClp::Sense sense) {
deba@482
   405
    switch (sense) {
deba@482
   406
    case MIN:
deba@482
   407
      _prob->setOptimizationDirection(1);
deba@482
   408
      break;
deba@482
   409
    case MAX:
deba@482
   410
      _prob->setOptimizationDirection(-1);
deba@482
   411
      break;
deba@482
   412
    }
deba@482
   413
  }
deba@482
   414
deba@482
   415
  LpClp::Sense LpClp::_getSense() const {
deba@482
   416
    double dir = _prob->optimizationDirection();
deba@482
   417
    if (dir > 0.0) {
deba@482
   418
      return MIN;
deba@482
   419
    } else {
deba@482
   420
      return MAX;
deba@482
   421
    }
deba@482
   422
  }
deba@482
   423
deba@482
   424
  void LpClp::_clear() {
deba@482
   425
    delete _prob;
deba@482
   426
    _prob = new ClpSimplex();
deba@482
   427
    rows.clear();
deba@482
   428
    cols.clear();
deba@482
   429
    _col_names_ref.clear();
deba@482
   430
    _clear_temporals();
deba@482
   431
  }
deba@482
   432
deba@482
   433
  void LpClp::messageLevel(MessageLevel m) {
deba@482
   434
    _prob->setLogLevel(static_cast<int>(m));
deba@482
   435
  }
deba@482
   436
deba@482
   437
} //END OF NAMESPACE LEMON