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