lemon/cplex.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 894 bb70ad62c95f
parent 551 9d0d7e20f76d
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
#include <iostream>
alpar@461
    20
#include <vector>
alpar@461
    21
#include <cstring>
alpar@461
    22
alpar@461
    23
#include <lemon/cplex.h>
alpar@461
    24
alpar@461
    25
extern "C" {
alpar@461
    26
#include <ilcplex/cplex.h>
alpar@461
    27
}
alpar@461
    28
alpar@461
    29
alpar@461
    30
///\file
alpar@461
    31
///\brief Implementation of the LEMON-CPLEX lp solver interface.
alpar@461
    32
namespace lemon {
alpar@461
    33
alpar@461
    34
  CplexEnv::LicenseError::LicenseError(int status) {
alpar@461
    35
    if (!CPXgeterrorstring(0, status, _message)) {
alpar@461
    36
      std::strcpy(_message, "Cplex unknown error");
alpar@461
    37
    }
alpar@461
    38
  }
alpar@461
    39
alpar@461
    40
  CplexEnv::CplexEnv() {
alpar@461
    41
    int status;
alpar@461
    42
    _cnt = new int;
alpar@461
    43
    _env = CPXopenCPLEX(&status);
alpar@461
    44
    if (_env == 0) {
alpar@461
    45
      delete _cnt;
alpar@461
    46
      _cnt = 0;
alpar@461
    47
      throw LicenseError(status);
alpar@461
    48
    }
alpar@461
    49
  }
alpar@461
    50
alpar@461
    51
  CplexEnv::CplexEnv(const CplexEnv& other) {
alpar@461
    52
    _env = other._env;
alpar@461
    53
    _cnt = other._cnt;
alpar@461
    54
    ++(*_cnt);
alpar@461
    55
  }
alpar@461
    56
alpar@461
    57
  CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
alpar@461
    58
    _env = other._env;
alpar@461
    59
    _cnt = other._cnt;
alpar@461
    60
    ++(*_cnt);
alpar@461
    61
    return *this;
alpar@461
    62
  }
alpar@461
    63
alpar@461
    64
  CplexEnv::~CplexEnv() {
alpar@461
    65
    --(*_cnt);
alpar@461
    66
    if (*_cnt == 0) {
alpar@461
    67
      delete _cnt;
alpar@461
    68
      CPXcloseCPLEX(&_env);
alpar@461
    69
    }
alpar@461
    70
  }
alpar@461
    71
alpar@461
    72
  CplexBase::CplexBase() : LpBase() {
alpar@461
    73
    int status;
alpar@461
    74
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
deba@576
    75
    messageLevel(MESSAGE_NOTHING);
alpar@461
    76
  }
alpar@461
    77
alpar@461
    78
  CplexBase::CplexBase(const CplexEnv& env)
alpar@461
    79
    : LpBase(), _env(env) {
alpar@461
    80
    int status;
alpar@461
    81
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
deba@576
    82
    messageLevel(MESSAGE_NOTHING);
alpar@461
    83
  }
alpar@461
    84
alpar@461
    85
  CplexBase::CplexBase(const CplexBase& cplex)
alpar@461
    86
    : LpBase() {
alpar@461
    87
    int status;
alpar@461
    88
    _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
alpar@461
    89
    rows = cplex.rows;
alpar@461
    90
    cols = cplex.cols;
deba@576
    91
    messageLevel(MESSAGE_NOTHING);
alpar@461
    92
  }
alpar@461
    93
alpar@461
    94
  CplexBase::~CplexBase() {
alpar@461
    95
    CPXfreeprob(cplexEnv(),&_prob);
alpar@461
    96
  }
alpar@461
    97
alpar@461
    98
  int CplexBase::_addCol() {
alpar@461
    99
    int i = CPXgetnumcols(cplexEnv(), _prob);
alpar@461
   100
    double lb = -INF, ub = INF;
alpar@461
   101
    CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
alpar@461
   102
    return i;
alpar@461
   103
  }
alpar@461
   104
alpar@461
   105
alpar@461
   106
  int CplexBase::_addRow() {
alpar@461
   107
    int i = CPXgetnumrows(cplexEnv(), _prob);
alpar@461
   108
    const double ub = INF;
alpar@461
   109
    const char s = 'L';
alpar@461
   110
    CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
alpar@461
   111
    return i;
alpar@461
   112
  }
alpar@461
   113
alpar@461
   114
alpar@461
   115
  void CplexBase::_eraseCol(int i) {
alpar@461
   116
    CPXdelcols(cplexEnv(), _prob, i, i);
alpar@461
   117
  }
alpar@461
   118
alpar@461
   119
  void CplexBase::_eraseRow(int i) {
alpar@461
   120
    CPXdelrows(cplexEnv(), _prob, i, i);
alpar@461
   121
  }
alpar@461
   122
alpar@461
   123
  void CplexBase::_eraseColId(int i) {
alpar@461
   124
    cols.eraseIndex(i);
alpar@461
   125
    cols.shiftIndices(i);
alpar@461
   126
  }
alpar@461
   127
  void CplexBase::_eraseRowId(int i) {
alpar@461
   128
    rows.eraseIndex(i);
alpar@461
   129
    rows.shiftIndices(i);
alpar@461
   130
  }
alpar@461
   131
alpar@461
   132
  void CplexBase::_getColName(int col, std::string &name) const {
alpar@461
   133
    int size;
alpar@461
   134
    CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
alpar@461
   135
    if (size == 0) {
alpar@461
   136
      name.clear();
alpar@461
   137
      return;
alpar@461
   138
    }
alpar@461
   139
alpar@461
   140
    size *= -1;
alpar@461
   141
    std::vector<char> buf(size);
alpar@461
   142
    char *cname;
alpar@461
   143
    int tmp;
alpar@461
   144
    CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
alpar@461
   145
                  &tmp, col, col);
alpar@461
   146
    name = cname;
alpar@461
   147
  }
alpar@461
   148
alpar@461
   149
  void CplexBase::_setColName(int col, const std::string &name) {
alpar@461
   150
    char *cname;
alpar@461
   151
    cname = const_cast<char*>(name.c_str());
alpar@461
   152
    CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
alpar@461
   153
  }
alpar@461
   154
alpar@461
   155
  int CplexBase::_colByName(const std::string& name) const {
alpar@461
   156
    int index;
alpar@461
   157
    if (CPXgetcolindex(cplexEnv(), _prob,
alpar@461
   158
                       const_cast<char*>(name.c_str()), &index) == 0) {
alpar@461
   159
      return index;
alpar@461
   160
    }
alpar@461
   161
    return -1;
alpar@461
   162
  }
alpar@461
   163
alpar@461
   164
  void CplexBase::_getRowName(int row, std::string &name) const {
alpar@461
   165
    int size;
alpar@461
   166
    CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
alpar@461
   167
    if (size == 0) {
alpar@461
   168
      name.clear();
alpar@461
   169
      return;
alpar@461
   170
    }
alpar@461
   171
alpar@461
   172
    size *= -1;
alpar@461
   173
    std::vector<char> buf(size);
alpar@461
   174
    char *cname;
alpar@461
   175
    int tmp;
alpar@461
   176
    CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
alpar@461
   177
                  &tmp, row, row);
alpar@461
   178
    name = cname;
alpar@461
   179
  }
alpar@461
   180
alpar@461
   181
  void CplexBase::_setRowName(int row, const std::string &name) {
alpar@461
   182
    char *cname;
alpar@461
   183
    cname = const_cast<char*>(name.c_str());
alpar@461
   184
    CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
alpar@461
   185
  }
alpar@461
   186
alpar@461
   187
  int CplexBase::_rowByName(const std::string& name) const {
alpar@461
   188
    int index;
alpar@461
   189
    if (CPXgetrowindex(cplexEnv(), _prob,
alpar@461
   190
                       const_cast<char*>(name.c_str()), &index) == 0) {
alpar@461
   191
      return index;
alpar@461
   192
    }
alpar@461
   193
    return -1;
alpar@461
   194
  }
alpar@461
   195
alpar@461
   196
  void CplexBase::_setRowCoeffs(int i, ExprIterator b,
alpar@461
   197
                                      ExprIterator e)
alpar@461
   198
  {
alpar@461
   199
    std::vector<int> indices;
alpar@461
   200
    std::vector<int> rowlist;
alpar@461
   201
    std::vector<Value> values;
alpar@461
   202
alpar@461
   203
    for(ExprIterator it=b; it!=e; ++it) {
alpar@461
   204
      indices.push_back(it->first);
alpar@461
   205
      values.push_back(it->second);
alpar@461
   206
      rowlist.push_back(i);
alpar@461
   207
    }
alpar@461
   208
alpar@461
   209
    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
alpar@461
   210
                   &rowlist.front(), &indices.front(), &values.front());
alpar@461
   211
  }
alpar@461
   212
alpar@461
   213
  void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
alpar@461
   214
    int tmp1, tmp2, tmp3, length;
alpar@461
   215
    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
alpar@461
   216
alpar@461
   217
    length = -length;
alpar@461
   218
    std::vector<int> indices(length);
alpar@461
   219
    std::vector<double> values(length);
alpar@461
   220
alpar@461
   221
    CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
alpar@461
   222
               &indices.front(), &values.front(),
alpar@461
   223
               length, &tmp3, i, i);
alpar@461
   224
alpar@461
   225
    for (int i = 0; i < length; ++i) {
alpar@461
   226
      *b = std::make_pair(indices[i], values[i]);
alpar@461
   227
      ++b;
alpar@461
   228
    }
alpar@461
   229
  }
alpar@461
   230
alpar@461
   231
  void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
alpar@461
   232
    std::vector<int> indices;
alpar@461
   233
    std::vector<int> collist;
alpar@461
   234
    std::vector<Value> values;
alpar@461
   235
alpar@461
   236
    for(ExprIterator it=b; it!=e; ++it) {
alpar@461
   237
      indices.push_back(it->first);
alpar@461
   238
      values.push_back(it->second);
alpar@461
   239
      collist.push_back(i);
alpar@461
   240
    }
alpar@461
   241
alpar@461
   242
    CPXchgcoeflist(cplexEnv(), _prob, values.size(),
alpar@461
   243
                   &indices.front(), &collist.front(), &values.front());
alpar@461
   244
  }
alpar@461
   245
alpar@461
   246
  void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
alpar@461
   247
alpar@461
   248
    int tmp1, tmp2, tmp3, length;
alpar@461
   249
    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
alpar@461
   250
alpar@461
   251
    length = -length;
alpar@461
   252
    std::vector<int> indices(length);
alpar@461
   253
    std::vector<double> values(length);
alpar@461
   254
alpar@461
   255
    CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
alpar@461
   256
               &indices.front(), &values.front(),
alpar@461
   257
               length, &tmp3, i, i);
alpar@461
   258
alpar@461
   259
    for (int i = 0; i < length; ++i) {
alpar@461
   260
      *b = std::make_pair(indices[i], values[i]);
alpar@461
   261
      ++b;
alpar@461
   262
    }
alpar@461
   263
alpar@461
   264
  }
alpar@461
   265
alpar@461
   266
  void CplexBase::_setCoeff(int row, int col, Value value) {
alpar@461
   267
    CPXchgcoef(cplexEnv(), _prob, row, col, value);
alpar@461
   268
  }
alpar@461
   269
alpar@461
   270
  CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
alpar@461
   271
    CplexBase::Value value;
alpar@461
   272
    CPXgetcoef(cplexEnv(), _prob, row, col, &value);
alpar@461
   273
    return value;
alpar@461
   274
  }
alpar@461
   275
alpar@461
   276
  void CplexBase::_setColLowerBound(int i, Value value) {
alpar@461
   277
    const char s = 'L';
alpar@461
   278
    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
alpar@461
   279
  }
alpar@461
   280
alpar@461
   281
  CplexBase::Value CplexBase::_getColLowerBound(int i) const {
alpar@461
   282
    CplexBase::Value res;
alpar@461
   283
    CPXgetlb(cplexEnv(), _prob, &res, i, i);
alpar@461
   284
    return res <= -CPX_INFBOUND ? -INF : res;
alpar@461
   285
  }
alpar@461
   286
alpar@461
   287
  void CplexBase::_setColUpperBound(int i, Value value)
alpar@461
   288
  {
alpar@461
   289
    const char s = 'U';
alpar@461
   290
    CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
alpar@461
   291
  }
alpar@461
   292
alpar@461
   293
  CplexBase::Value CplexBase::_getColUpperBound(int i) const {
alpar@461
   294
    CplexBase::Value res;
alpar@461
   295
    CPXgetub(cplexEnv(), _prob, &res, i, i);
alpar@461
   296
    return res >= CPX_INFBOUND ? INF : res;
alpar@461
   297
  }
alpar@461
   298
alpar@461
   299
  CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
alpar@461
   300
    char s;
alpar@461
   301
    CPXgetsense(cplexEnv(), _prob, &s, i, i);
alpar@461
   302
    CplexBase::Value res;
alpar@461
   303
alpar@461
   304
    switch (s) {
alpar@461
   305
    case 'G':
alpar@461
   306
    case 'R':
alpar@461
   307
    case 'E':
alpar@461
   308
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
alpar@461
   309
      return res <= -CPX_INFBOUND ? -INF : res;
alpar@461
   310
    default:
alpar@461
   311
      return -INF;
alpar@461
   312
    }
alpar@461
   313
  }
alpar@461
   314
alpar@461
   315
  CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
alpar@461
   316
    char s;
alpar@461
   317
    CPXgetsense(cplexEnv(), _prob, &s, i, i);
alpar@461
   318
    CplexBase::Value res;
alpar@461
   319
alpar@461
   320
    switch (s) {
alpar@461
   321
    case 'L':
alpar@461
   322
    case 'E':
alpar@461
   323
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
alpar@461
   324
      return res >= CPX_INFBOUND ? INF : res;
alpar@461
   325
    case 'R':
alpar@461
   326
      CPXgetrhs(cplexEnv(), _prob, &res, i, i);
alpar@461
   327
      {
alpar@461
   328
        double rng;
alpar@461
   329
        CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
alpar@461
   330
        res += rng;
alpar@461
   331
      }
alpar@461
   332
      return res >= CPX_INFBOUND ? INF : res;
alpar@461
   333
    default:
alpar@461
   334
      return INF;
alpar@461
   335
    }
alpar@461
   336
  }
alpar@461
   337
alpar@461
   338
  //This is easier to implement
alpar@461
   339
  void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
alpar@461
   340
    if (lb == -INF) {
alpar@461
   341
      const char s = 'L';
alpar@461
   342
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
alpar@461
   343
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
alpar@461
   344
    } else if (ub == INF) {
alpar@461
   345
      const char s = 'G';
alpar@461
   346
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
alpar@461
   347
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
alpar@461
   348
    } else if (lb == ub){
alpar@461
   349
      const char s = 'E';
alpar@461
   350
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
alpar@461
   351
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
alpar@461
   352
    } else {
alpar@461
   353
      const char s = 'R';
alpar@461
   354
      CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
alpar@461
   355
      CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
alpar@461
   356
      double len = ub - lb;
alpar@461
   357
      CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
alpar@461
   358
    }
alpar@461
   359
  }
alpar@461
   360
alpar@461
   361
  void CplexBase::_setRowLowerBound(int i, Value lb)
alpar@461
   362
  {
alpar@461
   363
    LEMON_ASSERT(lb != INF, "Invalid bound");
alpar@461
   364
    _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
alpar@461
   365
  }
alpar@461
   366
alpar@461
   367
  void CplexBase::_setRowUpperBound(int i, Value ub)
alpar@461
   368
  {
alpar@461
   369
alpar@461
   370
    LEMON_ASSERT(ub != -INF, "Invalid bound");
alpar@461
   371
    _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
alpar@461
   372
  }
alpar@461
   373
alpar@461
   374
  void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
alpar@461
   375
  {
alpar@461
   376
    std::vector<int> indices;
alpar@461
   377
    std::vector<Value> values;
alpar@461
   378
    for(ExprIterator it=b; it!=e; ++it) {
alpar@461
   379
      indices.push_back(it->first);
alpar@461
   380
      values.push_back(it->second);
alpar@461
   381
    }
alpar@461
   382
    CPXchgobj(cplexEnv(), _prob, values.size(),
alpar@461
   383
              &indices.front(), &values.front());
alpar@461
   384
alpar@461
   385
  }
alpar@461
   386
alpar@461
   387
  void CplexBase::_getObjCoeffs(InsertIterator b) const
alpar@461
   388
  {
alpar@461
   389
    int num = CPXgetnumcols(cplexEnv(), _prob);
alpar@461
   390
    std::vector<Value> x(num);
alpar@461
   391
alpar@461
   392
    CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
alpar@461
   393
    for (int i = 0; i < num; ++i) {
alpar@461
   394
      if (x[i] != 0.0) {
alpar@461
   395
        *b = std::make_pair(i, x[i]);
alpar@461
   396
        ++b;
alpar@461
   397
      }
alpar@461
   398
    }
alpar@461
   399
  }
alpar@461
   400
alpar@461
   401
  void CplexBase::_setObjCoeff(int i, Value obj_coef)
alpar@461
   402
  {
alpar@461
   403
    CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
alpar@461
   404
  }
alpar@461
   405
alpar@461
   406
  CplexBase::Value CplexBase::_getObjCoeff(int i) const
alpar@461
   407
  {
alpar@461
   408
    Value x;
alpar@461
   409
    CPXgetobj(cplexEnv(), _prob, &x, i, i);
alpar@461
   410
    return x;
alpar@461
   411
  }
alpar@461
   412
alpar@461
   413
  void CplexBase::_setSense(CplexBase::Sense sense) {
alpar@461
   414
    switch (sense) {
alpar@461
   415
    case MIN:
alpar@461
   416
      CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
alpar@461
   417
      break;
alpar@461
   418
    case MAX:
alpar@461
   419
      CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
alpar@461
   420
      break;
alpar@461
   421
    }
alpar@461
   422
  }
alpar@461
   423
alpar@461
   424
  CplexBase::Sense CplexBase::_getSense() const {
alpar@461
   425
    switch (CPXgetobjsen(cplexEnv(), _prob)) {
alpar@461
   426
    case CPX_MIN:
alpar@461
   427
      return MIN;
alpar@461
   428
    case CPX_MAX:
alpar@461
   429
      return MAX;
alpar@461
   430
    default:
alpar@461
   431
      LEMON_ASSERT(false, "Invalid sense");
alpar@461
   432
      return CplexBase::Sense();
alpar@461
   433
    }
alpar@461
   434
  }
alpar@461
   435
alpar@461
   436
  void CplexBase::_clear() {
alpar@461
   437
    CPXfreeprob(cplexEnv(),&_prob);
alpar@461
   438
    int status;
alpar@461
   439
    _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
alpar@461
   440
    rows.clear();
alpar@461
   441
    cols.clear();
alpar@461
   442
  }
alpar@461
   443
deba@576
   444
  void CplexBase::_messageLevel(MessageLevel level) {
deba@576
   445
    switch (level) {
deba@576
   446
    case MESSAGE_NOTHING:
deba@576
   447
      _message_enabled = false;
deba@576
   448
      break;
deba@576
   449
    case MESSAGE_ERROR:
deba@576
   450
    case MESSAGE_WARNING:
deba@576
   451
    case MESSAGE_NORMAL:
deba@576
   452
    case MESSAGE_VERBOSE:
deba@576
   453
      _message_enabled = true;
deba@576
   454
      break;
deba@576
   455
    }
deba@576
   456
  }
deba@576
   457
deba@576
   458
  void CplexBase::_applyMessageLevel() {
deba@576
   459
    CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, 
deba@576
   460
                   _message_enabled ? CPX_ON : CPX_OFF);
deba@576
   461
  }
deba@576
   462
alpar@462
   463
  // CplexLp members
alpar@461
   464
alpar@462
   465
  CplexLp::CplexLp()
deba@551
   466
    : LpBase(), LpSolver(), CplexBase() {}
alpar@461
   467
alpar@462
   468
  CplexLp::CplexLp(const CplexEnv& env)
deba@551
   469
    : LpBase(), LpSolver(), CplexBase(env) {}
alpar@461
   470
alpar@462
   471
  CplexLp::CplexLp(const CplexLp& other)
deba@551
   472
    : LpBase(), LpSolver(), CplexBase(other) {}
alpar@461
   473
alpar@462
   474
  CplexLp::~CplexLp() {}
alpar@461
   475
alpar@540
   476
  CplexLp* CplexLp::newSolver() const { return new CplexLp; }
alpar@540
   477
  CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
alpar@461
   478
alpar@462
   479
  const char* CplexLp::_solverName() const { return "CplexLp"; }
alpar@461
   480
alpar@462
   481
  void CplexLp::_clear_temporals() {
alpar@461
   482
    _col_status.clear();
alpar@461
   483
    _row_status.clear();
alpar@461
   484
    _primal_ray.clear();
alpar@461
   485
    _dual_ray.clear();
alpar@461
   486
  }
alpar@461
   487
alpar@461
   488
  // The routine returns zero unless an error occurred during the
alpar@461
   489
  // optimization. Examples of errors include exhausting available
alpar@461
   490
  // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
alpar@461
   491
  // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
alpar@461
   492
  // user-specified CPLEX limit, or proving the model infeasible or
alpar@461
   493
  // unbounded, are not considered errors. Note that a zero return
alpar@461
   494
  // value does not necessarily mean that a solution exists. Use query
alpar@461
   495
  // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
alpar@461
   496
  // further information about the status of the optimization.
alpar@462
   497
  CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
alpar@461
   498
#if CPX_VERSION >= 800
alpar@461
   499
    if (status == 0) {
alpar@461
   500
      switch (CPXgetstat(cplexEnv(), _prob)) {
alpar@461
   501
      case CPX_STAT_OPTIMAL:
alpar@461
   502
      case CPX_STAT_INFEASIBLE:
alpar@461
   503
      case CPX_STAT_UNBOUNDED:
alpar@461
   504
        return SOLVED;
alpar@461
   505
      default:
alpar@461
   506
        return UNSOLVED;
alpar@461
   507
      }
alpar@461
   508
    } else {
alpar@461
   509
      return UNSOLVED;
alpar@461
   510
    }
alpar@461
   511
#else
alpar@461
   512
    if (status == 0) {
alpar@461
   513
      //We want to exclude some cases
alpar@461
   514
      switch (CPXgetstat(cplexEnv(), _prob)) {
alpar@461
   515
      case CPX_OBJ_LIM:
alpar@461
   516
      case CPX_IT_LIM_FEAS:
alpar@461
   517
      case CPX_IT_LIM_INFEAS:
alpar@461
   518
      case CPX_TIME_LIM_FEAS:
alpar@461
   519
      case CPX_TIME_LIM_INFEAS:
alpar@461
   520
        return UNSOLVED;
alpar@461
   521
      default:
alpar@461
   522
        return SOLVED;
alpar@461
   523
      }
alpar@461
   524
    } else {
alpar@461
   525
      return UNSOLVED;
alpar@461
   526
    }
alpar@461
   527
#endif
alpar@461
   528
  }
alpar@461
   529
alpar@462
   530
  CplexLp::SolveExitStatus CplexLp::_solve() {
alpar@461
   531
    _clear_temporals();
deba@576
   532
    _applyMessageLevel();
alpar@461
   533
    return convertStatus(CPXlpopt(cplexEnv(), _prob));
alpar@461
   534
  }
alpar@461
   535
alpar@462
   536
  CplexLp::SolveExitStatus CplexLp::solvePrimal() {
alpar@461
   537
    _clear_temporals();
deba@576
   538
    _applyMessageLevel();
alpar@461
   539
    return convertStatus(CPXprimopt(cplexEnv(), _prob));
alpar@461
   540
  }
alpar@461
   541
alpar@462
   542
  CplexLp::SolveExitStatus CplexLp::solveDual() {
alpar@461
   543
    _clear_temporals();
deba@576
   544
    _applyMessageLevel();
alpar@461
   545
    return convertStatus(CPXdualopt(cplexEnv(), _prob));
alpar@461
   546
  }
alpar@461
   547
alpar@462
   548
  CplexLp::SolveExitStatus CplexLp::solveBarrier() {
alpar@461
   549
    _clear_temporals();
deba@576
   550
    _applyMessageLevel();
alpar@461
   551
    return convertStatus(CPXbaropt(cplexEnv(), _prob));
alpar@461
   552
  }
alpar@461
   553
alpar@462
   554
  CplexLp::Value CplexLp::_getPrimal(int i) const {
alpar@461
   555
    Value x;
alpar@461
   556
    CPXgetx(cplexEnv(), _prob, &x, i, i);
alpar@461
   557
    return x;
alpar@461
   558
  }
alpar@461
   559
alpar@462
   560
  CplexLp::Value CplexLp::_getDual(int i) const {
alpar@461
   561
    Value y;
alpar@461
   562
    CPXgetpi(cplexEnv(), _prob, &y, i, i);
alpar@461
   563
    return y;
alpar@461
   564
  }
alpar@461
   565
alpar@462
   566
  CplexLp::Value CplexLp::_getPrimalValue() const {
alpar@461
   567
    Value objval;
alpar@461
   568
    CPXgetobjval(cplexEnv(), _prob, &objval);
alpar@461
   569
    return objval;
alpar@461
   570
  }
alpar@461
   571
alpar@462
   572
  CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
alpar@461
   573
    if (_col_status.empty()) {
alpar@461
   574
      _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
alpar@461
   575
      CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
alpar@461
   576
    }
alpar@461
   577
    switch (_col_status[i]) {
alpar@461
   578
    case CPX_BASIC:
alpar@461
   579
      return BASIC;
alpar@461
   580
    case CPX_FREE_SUPER:
alpar@461
   581
      return FREE;
alpar@461
   582
    case CPX_AT_LOWER:
alpar@461
   583
      return LOWER;
alpar@461
   584
    case CPX_AT_UPPER:
alpar@461
   585
      return UPPER;
alpar@461
   586
    default:
alpar@461
   587
      LEMON_ASSERT(false, "Wrong column status");
alpar@462
   588
      return CplexLp::VarStatus();
alpar@461
   589
    }
alpar@461
   590
  }
alpar@461
   591
alpar@462
   592
  CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
alpar@461
   593
    if (_row_status.empty()) {
alpar@461
   594
      _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
alpar@461
   595
      CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
alpar@461
   596
    }
alpar@461
   597
    switch (_row_status[i]) {
alpar@461
   598
    case CPX_BASIC:
alpar@461
   599
      return BASIC;
alpar@461
   600
    case CPX_AT_LOWER:
alpar@461
   601
      {
alpar@461
   602
        char s;
alpar@461
   603
        CPXgetsense(cplexEnv(), _prob, &s, i, i);
alpar@461
   604
        return s != 'L' ? LOWER : UPPER;
alpar@461
   605
      }
alpar@461
   606
    case CPX_AT_UPPER:
alpar@461
   607
      return UPPER;
alpar@461
   608
    default:
alpar@461
   609
      LEMON_ASSERT(false, "Wrong row status");
alpar@462
   610
      return CplexLp::VarStatus();
alpar@461
   611
    }
alpar@461
   612
  }
alpar@461
   613
alpar@462
   614
  CplexLp::Value CplexLp::_getPrimalRay(int i) const {
alpar@461
   615
    if (_primal_ray.empty()) {
alpar@461
   616
      _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
alpar@461
   617
      CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
alpar@461
   618
    }
alpar@461
   619
    return _primal_ray[i];
alpar@461
   620
  }
alpar@461
   621
alpar@462
   622
  CplexLp::Value CplexLp::_getDualRay(int i) const {
alpar@461
   623
    if (_dual_ray.empty()) {
alpar@461
   624
alpar@461
   625
    }
alpar@461
   626
    return _dual_ray[i];
alpar@461
   627
  }
alpar@461
   628
deba@576
   629
  // Cplex 7.0 status values
alpar@461
   630
  // This table lists the statuses, returned by the CPXgetstat()
alpar@461
   631
  // routine, for solutions to LP problems or mixed integer problems. If
alpar@461
   632
  // no solution exists, the return value is zero.
alpar@461
   633
alpar@461
   634
  // For Simplex, Barrier
alpar@461
   635
  // 1          CPX_OPTIMAL
alpar@461
   636
  //          Optimal solution found
alpar@461
   637
  // 2          CPX_INFEASIBLE
alpar@461
   638
  //          Problem infeasible
alpar@461
   639
  // 3    CPX_UNBOUNDED
alpar@461
   640
  //          Problem unbounded
alpar@461
   641
  // 4          CPX_OBJ_LIM
alpar@461
   642
  //          Objective limit exceeded in Phase II
alpar@461
   643
  // 5          CPX_IT_LIM_FEAS
alpar@461
   644
  //          Iteration limit exceeded in Phase II
alpar@461
   645
  // 6          CPX_IT_LIM_INFEAS
alpar@461
   646
  //          Iteration limit exceeded in Phase I
alpar@461
   647
  // 7          CPX_TIME_LIM_FEAS
alpar@461
   648
  //          Time limit exceeded in Phase II
alpar@461
   649
  // 8          CPX_TIME_LIM_INFEAS
alpar@461
   650
  //          Time limit exceeded in Phase I
alpar@461
   651
  // 9          CPX_NUM_BEST_FEAS
alpar@461
   652
  //          Problem non-optimal, singularities in Phase II
alpar@461
   653
  // 10         CPX_NUM_BEST_INFEAS
alpar@461
   654
  //          Problem non-optimal, singularities in Phase I
alpar@461
   655
  // 11         CPX_OPTIMAL_INFEAS
alpar@461
   656
  //          Optimal solution found, unscaled infeasibilities
alpar@461
   657
  // 12         CPX_ABORT_FEAS
alpar@461
   658
  //          Aborted in Phase II
alpar@461
   659
  // 13         CPX_ABORT_INFEAS
alpar@461
   660
  //          Aborted in Phase I
alpar@461
   661
  // 14          CPX_ABORT_DUAL_INFEAS
alpar@461
   662
  //          Aborted in barrier, dual infeasible
alpar@461
   663
  // 15          CPX_ABORT_PRIM_INFEAS
alpar@461
   664
  //          Aborted in barrier, primal infeasible
alpar@461
   665
  // 16          CPX_ABORT_PRIM_DUAL_INFEAS
alpar@461
   666
  //          Aborted in barrier, primal and dual infeasible
alpar@461
   667
  // 17          CPX_ABORT_PRIM_DUAL_FEAS
alpar@461
   668
  //          Aborted in barrier, primal and dual feasible
alpar@461
   669
  // 18          CPX_ABORT_CROSSOVER
alpar@461
   670
  //          Aborted in crossover
alpar@461
   671
  // 19          CPX_INForUNBD
alpar@461
   672
  //          Infeasible or unbounded
alpar@461
   673
  // 20   CPX_PIVOT
alpar@461
   674
  //       User pivot used
alpar@461
   675
  //
deba@576
   676
  // Pending return values
alpar@461
   677
  // ??case CPX_ABORT_DUAL_INFEAS
alpar@461
   678
  // ??case CPX_ABORT_CROSSOVER
alpar@461
   679
  // ??case CPX_INForUNBD
alpar@461
   680
  // ??case CPX_PIVOT
alpar@461
   681
alpar@461
   682
  //Some more interesting stuff:
alpar@461
   683
alpar@461
   684
  // CPX_PARAM_PROBMETHOD  1062  int  LPMETHOD
alpar@461
   685
  // 0 Automatic
alpar@461
   686
  // 1 Primal Simplex
alpar@461
   687
  // 2 Dual Simplex
alpar@461
   688
  // 3 Network Simplex
alpar@461
   689
  // 4 Standard Barrier
alpar@461
   690
  // Default: 0
alpar@461
   691
  // Description: Method for linear optimization.
alpar@461
   692
  // Determines which algorithm is used when CPXlpopt() (or "optimize"
alpar@461
   693
  // in the Interactive Optimizer) is called. Currently the behavior of
alpar@461
   694
  // the "Automatic" setting is that CPLEX simply invokes the dual
alpar@461
   695
  // simplex method, but this capability may be expanded in the future
alpar@461
   696
  // so that CPLEX chooses the method based on problem characteristics
alpar@461
   697
#if CPX_VERSION < 900
alpar@461
   698
  void statusSwitch(CPXENVptr cplexEnv(),int& stat){
alpar@461
   699
    int lpmethod;
alpar@461
   700
    CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
alpar@461
   701
    if (lpmethod==2){
alpar@461
   702
      if (stat==CPX_UNBOUNDED){
alpar@461
   703
        stat=CPX_INFEASIBLE;
alpar@461
   704
      }
alpar@461
   705
      else{
alpar@461
   706
        if (stat==CPX_INFEASIBLE)
alpar@461
   707
          stat=CPX_UNBOUNDED;
alpar@461
   708
      }
alpar@461
   709
    }
alpar@461
   710
  }
alpar@461
   711
#else
alpar@461
   712
  void statusSwitch(CPXENVptr,int&){}
alpar@461
   713
#endif
alpar@461
   714
alpar@462
   715
  CplexLp::ProblemType CplexLp::_getPrimalType() const {
alpar@461
   716
    // Unboundedness not treated well: the following is from cplex 9.0 doc
alpar@461
   717
    // About Unboundedness
alpar@461
   718
alpar@461
   719
    // The treatment of models that are unbounded involves a few
alpar@461
   720
    // subtleties. Specifically, a declaration of unboundedness means that
alpar@461
   721
    // ILOG CPLEX has determined that the model has an unbounded
alpar@461
   722
    // ray. Given any feasible solution x with objective z, a multiple of
alpar@461
   723
    // the unbounded ray can be added to x to give a feasible solution
alpar@461
   724
    // with objective z-1 (or z+1 for maximization models). Thus, if a
alpar@461
   725
    // feasible solution exists, then the optimal objective is
alpar@461
   726
    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
alpar@461
   727
    // a feasible solution exists. Users can call the routine CPXsolninfo
alpar@461
   728
    // to determine whether ILOG CPLEX has also concluded that the model
alpar@461
   729
    // has a feasible solution.
alpar@461
   730
alpar@461
   731
    int stat = CPXgetstat(cplexEnv(), _prob);
alpar@461
   732
#if CPX_VERSION >= 800
alpar@461
   733
    switch (stat)
alpar@461
   734
      {
alpar@461
   735
      case CPX_STAT_OPTIMAL:
alpar@461
   736
        return OPTIMAL;
alpar@461
   737
      case CPX_STAT_UNBOUNDED:
alpar@461
   738
        return UNBOUNDED;
alpar@461
   739
      case CPX_STAT_INFEASIBLE:
alpar@461
   740
        return INFEASIBLE;
alpar@461
   741
      default:
alpar@461
   742
        return UNDEFINED;
alpar@461
   743
      }
alpar@461
   744
#else
alpar@461
   745
    statusSwitch(cplexEnv(),stat);
alpar@461
   746
    //CPXgetstat(cplexEnv(), _prob);
alpar@461
   747
    switch (stat) {
alpar@461
   748
    case 0:
alpar@461
   749
      return UNDEFINED; //Undefined
alpar@461
   750
    case CPX_OPTIMAL://Optimal
alpar@461
   751
      return OPTIMAL;
alpar@461
   752
    case CPX_UNBOUNDED://Unbounded
alpar@461
   753
      return INFEASIBLE;//In case of dual simplex
alpar@461
   754
      //return UNBOUNDED;
alpar@461
   755
    case CPX_INFEASIBLE://Infeasible
alpar@461
   756
      //    case CPX_IT_LIM_INFEAS:
alpar@461
   757
      //     case CPX_TIME_LIM_INFEAS:
alpar@461
   758
      //     case CPX_NUM_BEST_INFEAS:
alpar@461
   759
      //     case CPX_OPTIMAL_INFEAS:
alpar@461
   760
      //     case CPX_ABORT_INFEAS:
alpar@461
   761
      //     case CPX_ABORT_PRIM_INFEAS:
alpar@461
   762
      //     case CPX_ABORT_PRIM_DUAL_INFEAS:
alpar@461
   763
      return UNBOUNDED;//In case of dual simplex
alpar@461
   764
      //return INFEASIBLE;
alpar@461
   765
      //     case CPX_OBJ_LIM:
alpar@461
   766
      //     case CPX_IT_LIM_FEAS:
alpar@461
   767
      //     case CPX_TIME_LIM_FEAS:
alpar@461
   768
      //     case CPX_NUM_BEST_FEAS:
alpar@461
   769
      //     case CPX_ABORT_FEAS:
alpar@461
   770
      //     case CPX_ABORT_PRIM_DUAL_FEAS:
alpar@461
   771
      //       return FEASIBLE;
alpar@461
   772
    default:
alpar@461
   773
      return UNDEFINED; //Everything else comes here
alpar@461
   774
      //FIXME error
alpar@461
   775
    }
alpar@461
   776
#endif
alpar@461
   777
  }
alpar@461
   778
deba@576
   779
  // Cplex 9.0 status values
alpar@461
   780
  // CPX_STAT_ABORT_DUAL_OBJ_LIM
alpar@461
   781
  // CPX_STAT_ABORT_IT_LIM
alpar@461
   782
  // CPX_STAT_ABORT_OBJ_LIM
alpar@461
   783
  // CPX_STAT_ABORT_PRIM_OBJ_LIM
alpar@461
   784
  // CPX_STAT_ABORT_TIME_LIM
alpar@461
   785
  // CPX_STAT_ABORT_USER
alpar@461
   786
  // CPX_STAT_FEASIBLE_RELAXED
alpar@461
   787
  // CPX_STAT_INFEASIBLE
alpar@461
   788
  // CPX_STAT_INForUNBD
alpar@461
   789
  // CPX_STAT_NUM_BEST
alpar@461
   790
  // CPX_STAT_OPTIMAL
alpar@461
   791
  // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
alpar@461
   792
  // CPX_STAT_OPTIMAL_INFEAS
alpar@461
   793
  // CPX_STAT_OPTIMAL_RELAXED
alpar@461
   794
  // CPX_STAT_UNBOUNDED
alpar@461
   795
alpar@462
   796
  CplexLp::ProblemType CplexLp::_getDualType() const {
alpar@461
   797
    int stat = CPXgetstat(cplexEnv(), _prob);
alpar@461
   798
#if CPX_VERSION >= 800
alpar@461
   799
    switch (stat) {
alpar@461
   800
    case CPX_STAT_OPTIMAL:
alpar@461
   801
      return OPTIMAL;
alpar@461
   802
    case CPX_STAT_UNBOUNDED:
alpar@461
   803
      return INFEASIBLE;
alpar@461
   804
    default:
alpar@461
   805
      return UNDEFINED;
alpar@461
   806
    }
alpar@461
   807
#else
alpar@461
   808
    statusSwitch(cplexEnv(),stat);
alpar@461
   809
    switch (stat) {
alpar@461
   810
    case 0:
alpar@461
   811
      return UNDEFINED; //Undefined
alpar@461
   812
    case CPX_OPTIMAL://Optimal
alpar@461
   813
      return OPTIMAL;
alpar@461
   814
    case CPX_UNBOUNDED:
alpar@461
   815
      return INFEASIBLE;
alpar@461
   816
    default:
alpar@461
   817
      return UNDEFINED; //Everything else comes here
alpar@461
   818
      //FIXME error
alpar@461
   819
    }
alpar@461
   820
#endif
alpar@461
   821
  }
alpar@461
   822
alpar@462
   823
  // CplexMip members
alpar@461
   824
alpar@462
   825
  CplexMip::CplexMip()
deba@551
   826
    : LpBase(), MipSolver(), CplexBase() {
alpar@461
   827
alpar@461
   828
#if CPX_VERSION < 800
alpar@461
   829
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
alpar@461
   830
#else
alpar@461
   831
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
alpar@461
   832
#endif
alpar@461
   833
  }
alpar@461
   834
alpar@462
   835
  CplexMip::CplexMip(const CplexEnv& env)
deba@551
   836
    : LpBase(), MipSolver(), CplexBase(env) {
alpar@461
   837
alpar@461
   838
#if CPX_VERSION < 800
alpar@461
   839
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
alpar@461
   840
#else
alpar@461
   841
    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
alpar@461
   842
#endif
alpar@461
   843
alpar@461
   844
  }
alpar@461
   845
alpar@462
   846
  CplexMip::CplexMip(const CplexMip& other)
deba@551
   847
    : LpBase(), MipSolver(), CplexBase(other) {}
alpar@461
   848
alpar@462
   849
  CplexMip::~CplexMip() {}
alpar@461
   850
alpar@540
   851
  CplexMip* CplexMip::newSolver() const { return new CplexMip; }
alpar@540
   852
  CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
alpar@461
   853
alpar@462
   854
  const char* CplexMip::_solverName() const { return "CplexMip"; }
alpar@461
   855
alpar@462
   856
  void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
alpar@461
   857
alpar@461
   858
    // Note If a variable is to be changed to binary, a call to CPXchgbds
alpar@461
   859
    // should also be made to change the bounds to 0 and 1.
alpar@461
   860
alpar@461
   861
    switch (col_type){
alpar@461
   862
    case INTEGER: {
alpar@461
   863
      const char t = 'I';
alpar@461
   864
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
alpar@461
   865
    } break;
alpar@461
   866
    case REAL: {
alpar@461
   867
      const char t = 'C';
alpar@461
   868
      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
alpar@461
   869
    } break;
alpar@461
   870
    default:
alpar@461
   871
      break;
alpar@461
   872
    }
alpar@461
   873
  }
alpar@461
   874
alpar@462
   875
  CplexMip::ColTypes CplexMip::_getColType(int i) const {
alpar@461
   876
    char t;
alpar@461
   877
    CPXgetctype (cplexEnv(), _prob, &t, i, i);
alpar@461
   878
    switch (t) {
alpar@461
   879
    case 'I':
alpar@461
   880
      return INTEGER;
alpar@461
   881
    case 'C':
alpar@461
   882
      return REAL;
alpar@461
   883
    default:
alpar@461
   884
      LEMON_ASSERT(false, "Invalid column type");
alpar@461
   885
      return ColTypes();
alpar@461
   886
    }
alpar@461
   887
alpar@461
   888
  }
alpar@461
   889
alpar@462
   890
  CplexMip::SolveExitStatus CplexMip::_solve() {
alpar@461
   891
    int status;
deba@576
   892
    _applyMessageLevel();
alpar@461
   893
    status = CPXmipopt (cplexEnv(), _prob);
alpar@461
   894
    if (status==0)
alpar@461
   895
      return SOLVED;
alpar@461
   896
    else
alpar@461
   897
      return UNSOLVED;
alpar@461
   898
alpar@461
   899
  }
alpar@461
   900
alpar@461
   901
alpar@462
   902
  CplexMip::ProblemType CplexMip::_getType() const {
alpar@461
   903
alpar@461
   904
    int stat = CPXgetstat(cplexEnv(), _prob);
alpar@461
   905
alpar@461
   906
    //Fortunately, MIP statuses did not change for cplex 8.0
alpar@461
   907
    switch (stat) {
alpar@461
   908
    case CPXMIP_OPTIMAL:
alpar@461
   909
      // Optimal integer solution has been found.
alpar@461
   910
    case CPXMIP_OPTIMAL_TOL:
alpar@461
   911
      // Optimal soluton with the tolerance defined by epgap or epagap has
alpar@461
   912
      // been found.
alpar@461
   913
      return OPTIMAL;
alpar@461
   914
      //This also exists in later issues
alpar@461
   915
      //    case CPXMIP_UNBOUNDED:
alpar@461
   916
      //return UNBOUNDED;
alpar@461
   917
      case CPXMIP_INFEASIBLE:
alpar@461
   918
        return INFEASIBLE;
alpar@461
   919
    default:
alpar@461
   920
      return UNDEFINED;
alpar@461
   921
    }
alpar@461
   922
    //Unboundedness not treated well: the following is from cplex 9.0 doc
alpar@461
   923
    // About Unboundedness
alpar@461
   924
alpar@461
   925
    // The treatment of models that are unbounded involves a few
alpar@461
   926
    // subtleties. Specifically, a declaration of unboundedness means that
alpar@461
   927
    // ILOG CPLEX has determined that the model has an unbounded
alpar@461
   928
    // ray. Given any feasible solution x with objective z, a multiple of
alpar@461
   929
    // the unbounded ray can be added to x to give a feasible solution
alpar@461
   930
    // with objective z-1 (or z+1 for maximization models). Thus, if a
alpar@461
   931
    // feasible solution exists, then the optimal objective is
alpar@461
   932
    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
alpar@461
   933
    // a feasible solution exists. Users can call the routine CPXsolninfo
alpar@461
   934
    // to determine whether ILOG CPLEX has also concluded that the model
alpar@461
   935
    // has a feasible solution.
alpar@461
   936
  }
alpar@461
   937
alpar@462
   938
  CplexMip::Value CplexMip::_getSol(int i) const {
alpar@461
   939
    Value x;
alpar@461
   940
    CPXgetmipx(cplexEnv(), _prob, &x, i, i);
alpar@461
   941
    return x;
alpar@461
   942
  }
alpar@461
   943
alpar@462
   944
  CplexMip::Value CplexMip::_getSolValue() const {
alpar@461
   945
    Value objval;
alpar@461
   946
    CPXgetmipobjval(cplexEnv(), _prob, &objval);
alpar@461
   947
    return objval;
alpar@461
   948
  }
alpar@461
   949
alpar@461
   950
} //namespace lemon
alpar@461
   951