lemon/cplex.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 12 Nov 2009 23:26:13 +0100
changeset 806 fa6f37d7a25b
parent 576 745e182d0139
child 877 141f9c0db4a3
permissions -rw-r--r--
Entirely rework CapacityScaling (#180)

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