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