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