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