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