lemon/cplex.cc
author Alpar Juttner <alpar@cs.elte.hu>
Fri, 09 Aug 2013 18:56:00 +0200
branch1.3
changeset 1280 fbdde70389da
parent 1231 1782aa72495a
child 1330 1ad592289f93
child 1347 0900cfe4a84d
permissions -rw-r--r--
Trim the documentation
     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-2013
     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   void CplexBase::_write(std::string file, std::string format) const
   496   {
   497     if(format == "MPS" || format == "LP")
   498       CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str());
   499     else if(format == "SOL")
   500       CPXsolwrite(cplexEnv(), cplexLp(), file.c_str());
   501     else throw UnsupportedFormatError(format);
   502   }
   503 
   504 
   505 
   506   // CplexLp members
   507 
   508   CplexLp::CplexLp()
   509     : LpBase(), LpSolver(), CplexBase() {}
   510 
   511   CplexLp::CplexLp(const CplexEnv& env)
   512     : LpBase(), LpSolver(), CplexBase(env) {}
   513 
   514   CplexLp::CplexLp(const CplexLp& other)
   515     : LpBase(), LpSolver(), CplexBase(other) {}
   516 
   517   CplexLp::~CplexLp() {}
   518 
   519   CplexLp* CplexLp::newSolver() const { return new CplexLp; }
   520   CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
   521 
   522   const char* CplexLp::_solverName() const { return "CplexLp"; }
   523 
   524   void CplexLp::_clear_temporals() {
   525     _col_status.clear();
   526     _row_status.clear();
   527     _primal_ray.clear();
   528     _dual_ray.clear();
   529   }
   530 
   531   // The routine returns zero unless an error occurred during the
   532   // optimization. Examples of errors include exhausting available
   533   // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
   534   // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
   535   // user-specified CPLEX limit, or proving the model infeasible or
   536   // unbounded, are not considered errors. Note that a zero return
   537   // value does not necessarily mean that a solution exists. Use query
   538   // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
   539   // further information about the status of the optimization.
   540   CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
   541 #if CPX_VERSION >= 800
   542     if (status == 0) {
   543       switch (CPXgetstat(cplexEnv(), _prob)) {
   544       case CPX_STAT_OPTIMAL:
   545       case CPX_STAT_INFEASIBLE:
   546       case CPX_STAT_UNBOUNDED:
   547         return SOLVED;
   548       default:
   549         return UNSOLVED;
   550       }
   551     } else {
   552       return UNSOLVED;
   553     }
   554 #else
   555     if (status == 0) {
   556       //We want to exclude some cases
   557       switch (CPXgetstat(cplexEnv(), _prob)) {
   558       case CPX_OBJ_LIM:
   559       case CPX_IT_LIM_FEAS:
   560       case CPX_IT_LIM_INFEAS:
   561       case CPX_TIME_LIM_FEAS:
   562       case CPX_TIME_LIM_INFEAS:
   563         return UNSOLVED;
   564       default:
   565         return SOLVED;
   566       }
   567     } else {
   568       return UNSOLVED;
   569     }
   570 #endif
   571   }
   572 
   573   CplexLp::SolveExitStatus CplexLp::_solve() {
   574     _clear_temporals();
   575     _applyMessageLevel();
   576     return convertStatus(CPXlpopt(cplexEnv(), _prob));
   577   }
   578 
   579   CplexLp::SolveExitStatus CplexLp::solvePrimal() {
   580     _clear_temporals();
   581     _applyMessageLevel();
   582     return convertStatus(CPXprimopt(cplexEnv(), _prob));
   583   }
   584 
   585   CplexLp::SolveExitStatus CplexLp::solveDual() {
   586     _clear_temporals();
   587     _applyMessageLevel();
   588     return convertStatus(CPXdualopt(cplexEnv(), _prob));
   589   }
   590 
   591   CplexLp::SolveExitStatus CplexLp::solveBarrier() {
   592     _clear_temporals();
   593     _applyMessageLevel();
   594     return convertStatus(CPXbaropt(cplexEnv(), _prob));
   595   }
   596 
   597   CplexLp::Value CplexLp::_getPrimal(int i) const {
   598     Value x;
   599     CPXgetx(cplexEnv(), _prob, &x, i, i);
   600     return x;
   601   }
   602 
   603   CplexLp::Value CplexLp::_getDual(int i) const {
   604     Value y;
   605     CPXgetpi(cplexEnv(), _prob, &y, i, i);
   606     return y;
   607   }
   608 
   609   CplexLp::Value CplexLp::_getPrimalValue() const {
   610     Value objval;
   611     CPXgetobjval(cplexEnv(), _prob, &objval);
   612     return objval;
   613   }
   614 
   615   CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
   616     if (_col_status.empty()) {
   617       _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
   618       CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
   619     }
   620     switch (_col_status[i]) {
   621     case CPX_BASIC:
   622       return BASIC;
   623     case CPX_FREE_SUPER:
   624       return FREE;
   625     case CPX_AT_LOWER:
   626       return LOWER;
   627     case CPX_AT_UPPER:
   628       return UPPER;
   629     default:
   630       LEMON_ASSERT(false, "Wrong column status");
   631       return CplexLp::VarStatus();
   632     }
   633   }
   634 
   635   CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
   636     if (_row_status.empty()) {
   637       _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
   638       CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
   639     }
   640     switch (_row_status[i]) {
   641     case CPX_BASIC:
   642       return BASIC;
   643     case CPX_AT_LOWER:
   644       {
   645         char s;
   646         CPXgetsense(cplexEnv(), _prob, &s, i, i);
   647         return s != 'L' ? LOWER : UPPER;
   648       }
   649     case CPX_AT_UPPER:
   650       return UPPER;
   651     default:
   652       LEMON_ASSERT(false, "Wrong row status");
   653       return CplexLp::VarStatus();
   654     }
   655   }
   656 
   657   CplexLp::Value CplexLp::_getPrimalRay(int i) const {
   658     if (_primal_ray.empty()) {
   659       _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
   660       CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
   661     }
   662     return _primal_ray[i];
   663   }
   664 
   665   CplexLp::Value CplexLp::_getDualRay(int i) const {
   666     if (_dual_ray.empty()) {
   667 
   668     }
   669     return _dual_ray[i];
   670   }
   671 
   672   // Cplex 7.0 status values
   673   // This table lists the statuses, returned by the CPXgetstat()
   674   // routine, for solutions to LP problems or mixed integer problems. If
   675   // no solution exists, the return value is zero.
   676 
   677   // For Simplex, Barrier
   678   // 1          CPX_OPTIMAL
   679   //          Optimal solution found
   680   // 2          CPX_INFEASIBLE
   681   //          Problem infeasible
   682   // 3    CPX_UNBOUNDED
   683   //          Problem unbounded
   684   // 4          CPX_OBJ_LIM
   685   //          Objective limit exceeded in Phase II
   686   // 5          CPX_IT_LIM_FEAS
   687   //          Iteration limit exceeded in Phase II
   688   // 6          CPX_IT_LIM_INFEAS
   689   //          Iteration limit exceeded in Phase I
   690   // 7          CPX_TIME_LIM_FEAS
   691   //          Time limit exceeded in Phase II
   692   // 8          CPX_TIME_LIM_INFEAS
   693   //          Time limit exceeded in Phase I
   694   // 9          CPX_NUM_BEST_FEAS
   695   //          Problem non-optimal, singularities in Phase II
   696   // 10         CPX_NUM_BEST_INFEAS
   697   //          Problem non-optimal, singularities in Phase I
   698   // 11         CPX_OPTIMAL_INFEAS
   699   //          Optimal solution found, unscaled infeasibilities
   700   // 12         CPX_ABORT_FEAS
   701   //          Aborted in Phase II
   702   // 13         CPX_ABORT_INFEAS
   703   //          Aborted in Phase I
   704   // 14          CPX_ABORT_DUAL_INFEAS
   705   //          Aborted in barrier, dual infeasible
   706   // 15          CPX_ABORT_PRIM_INFEAS
   707   //          Aborted in barrier, primal infeasible
   708   // 16          CPX_ABORT_PRIM_DUAL_INFEAS
   709   //          Aborted in barrier, primal and dual infeasible
   710   // 17          CPX_ABORT_PRIM_DUAL_FEAS
   711   //          Aborted in barrier, primal and dual feasible
   712   // 18          CPX_ABORT_CROSSOVER
   713   //          Aborted in crossover
   714   // 19          CPX_INForUNBD
   715   //          Infeasible or unbounded
   716   // 20   CPX_PIVOT
   717   //       User pivot used
   718   //
   719   // Pending return values
   720   // ??case CPX_ABORT_DUAL_INFEAS
   721   // ??case CPX_ABORT_CROSSOVER
   722   // ??case CPX_INForUNBD
   723   // ??case CPX_PIVOT
   724 
   725   //Some more interesting stuff:
   726 
   727   // CPX_PARAM_PROBMETHOD  1062  int  LPMETHOD
   728   // 0 Automatic
   729   // 1 Primal Simplex
   730   // 2 Dual Simplex
   731   // 3 Network Simplex
   732   // 4 Standard Barrier
   733   // Default: 0
   734   // Description: Method for linear optimization.
   735   // Determines which algorithm is used when CPXlpopt() (or "optimize"
   736   // in the Interactive Optimizer) is called. Currently the behavior of
   737   // the "Automatic" setting is that CPLEX simply invokes the dual
   738   // simplex method, but this capability may be expanded in the future
   739   // so that CPLEX chooses the method based on problem characteristics
   740 #if CPX_VERSION < 900
   741   void statusSwitch(CPXENVptr cplexEnv(),int& stat){
   742     int lpmethod;
   743     CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
   744     if (lpmethod==2){
   745       if (stat==CPX_UNBOUNDED){
   746         stat=CPX_INFEASIBLE;
   747       }
   748       else{
   749         if (stat==CPX_INFEASIBLE)
   750           stat=CPX_UNBOUNDED;
   751       }
   752     }
   753   }
   754 #else
   755   void statusSwitch(CPXENVptr,int&){}
   756 #endif
   757 
   758   CplexLp::ProblemType CplexLp::_getPrimalType() const {
   759     // Unboundedness not treated well: the following is from cplex 9.0 doc
   760     // About Unboundedness
   761 
   762     // The treatment of models that are unbounded involves a few
   763     // subtleties. Specifically, a declaration of unboundedness means that
   764     // ILOG CPLEX has determined that the model has an unbounded
   765     // ray. Given any feasible solution x with objective z, a multiple of
   766     // the unbounded ray can be added to x to give a feasible solution
   767     // with objective z-1 (or z+1 for maximization models). Thus, if a
   768     // feasible solution exists, then the optimal objective is
   769     // unbounded. Note that ILOG CPLEX has not necessarily concluded that
   770     // a feasible solution exists. Users can call the routine CPXsolninfo
   771     // to determine whether ILOG CPLEX has also concluded that the model
   772     // has a feasible solution.
   773 
   774     int stat = CPXgetstat(cplexEnv(), _prob);
   775 #if CPX_VERSION >= 800
   776     switch (stat)
   777       {
   778       case CPX_STAT_OPTIMAL:
   779         return OPTIMAL;
   780       case CPX_STAT_UNBOUNDED:
   781         return UNBOUNDED;
   782       case CPX_STAT_INFEASIBLE:
   783         return INFEASIBLE;
   784       default:
   785         return UNDEFINED;
   786       }
   787 #else
   788     statusSwitch(cplexEnv(),stat);
   789     //CPXgetstat(cplexEnv(), _prob);
   790     switch (stat) {
   791     case 0:
   792       return UNDEFINED; //Undefined
   793     case CPX_OPTIMAL://Optimal
   794       return OPTIMAL;
   795     case CPX_UNBOUNDED://Unbounded
   796       return INFEASIBLE;//In case of dual simplex
   797       //return UNBOUNDED;
   798     case CPX_INFEASIBLE://Infeasible
   799       //    case CPX_IT_LIM_INFEAS:
   800       //     case CPX_TIME_LIM_INFEAS:
   801       //     case CPX_NUM_BEST_INFEAS:
   802       //     case CPX_OPTIMAL_INFEAS:
   803       //     case CPX_ABORT_INFEAS:
   804       //     case CPX_ABORT_PRIM_INFEAS:
   805       //     case CPX_ABORT_PRIM_DUAL_INFEAS:
   806       return UNBOUNDED;//In case of dual simplex
   807       //return INFEASIBLE;
   808       //     case CPX_OBJ_LIM:
   809       //     case CPX_IT_LIM_FEAS:
   810       //     case CPX_TIME_LIM_FEAS:
   811       //     case CPX_NUM_BEST_FEAS:
   812       //     case CPX_ABORT_FEAS:
   813       //     case CPX_ABORT_PRIM_DUAL_FEAS:
   814       //       return FEASIBLE;
   815     default:
   816       return UNDEFINED; //Everything else comes here
   817       //FIXME error
   818     }
   819 #endif
   820   }
   821 
   822   // Cplex 9.0 status values
   823   // CPX_STAT_ABORT_DUAL_OBJ_LIM
   824   // CPX_STAT_ABORT_IT_LIM
   825   // CPX_STAT_ABORT_OBJ_LIM
   826   // CPX_STAT_ABORT_PRIM_OBJ_LIM
   827   // CPX_STAT_ABORT_TIME_LIM
   828   // CPX_STAT_ABORT_USER
   829   // CPX_STAT_FEASIBLE_RELAXED
   830   // CPX_STAT_INFEASIBLE
   831   // CPX_STAT_INForUNBD
   832   // CPX_STAT_NUM_BEST
   833   // CPX_STAT_OPTIMAL
   834   // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
   835   // CPX_STAT_OPTIMAL_INFEAS
   836   // CPX_STAT_OPTIMAL_RELAXED
   837   // CPX_STAT_UNBOUNDED
   838 
   839   CplexLp::ProblemType CplexLp::_getDualType() const {
   840     int stat = CPXgetstat(cplexEnv(), _prob);
   841 #if CPX_VERSION >= 800
   842     switch (stat) {
   843     case CPX_STAT_OPTIMAL:
   844       return OPTIMAL;
   845     case CPX_STAT_UNBOUNDED:
   846       return INFEASIBLE;
   847     default:
   848       return UNDEFINED;
   849     }
   850 #else
   851     statusSwitch(cplexEnv(),stat);
   852     switch (stat) {
   853     case 0:
   854       return UNDEFINED; //Undefined
   855     case CPX_OPTIMAL://Optimal
   856       return OPTIMAL;
   857     case CPX_UNBOUNDED:
   858       return INFEASIBLE;
   859     default:
   860       return UNDEFINED; //Everything else comes here
   861       //FIXME error
   862     }
   863 #endif
   864   }
   865 
   866   // CplexMip members
   867 
   868   CplexMip::CplexMip()
   869     : LpBase(), MipSolver(), CplexBase() {
   870 
   871 #if CPX_VERSION < 800
   872     CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
   873 #else
   874     CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
   875 #endif
   876   }
   877 
   878   CplexMip::CplexMip(const CplexEnv& env)
   879     : LpBase(), MipSolver(), CplexBase(env) {
   880 
   881 #if CPX_VERSION < 800
   882     CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
   883 #else
   884     CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
   885 #endif
   886 
   887   }
   888 
   889   CplexMip::CplexMip(const CplexMip& other)
   890     : LpBase(), MipSolver(), CplexBase(other) {}
   891 
   892   CplexMip::~CplexMip() {}
   893 
   894   CplexMip* CplexMip::newSolver() const { return new CplexMip; }
   895   CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
   896 
   897   const char* CplexMip::_solverName() const { return "CplexMip"; }
   898 
   899   void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
   900 
   901     // Note If a variable is to be changed to binary, a call to CPXchgbds
   902     // should also be made to change the bounds to 0 and 1.
   903 
   904     switch (col_type){
   905     case INTEGER: {
   906       const char t = 'I';
   907       CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
   908     } break;
   909     case REAL: {
   910       const char t = 'C';
   911       CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
   912     } break;
   913     default:
   914       break;
   915     }
   916   }
   917 
   918   CplexMip::ColTypes CplexMip::_getColType(int i) const {
   919     char t;
   920     CPXgetctype (cplexEnv(), _prob, &t, i, i);
   921     switch (t) {
   922     case 'I':
   923       return INTEGER;
   924     case 'C':
   925       return REAL;
   926     default:
   927       LEMON_ASSERT(false, "Invalid column type");
   928       return ColTypes();
   929     }
   930 
   931   }
   932 
   933   CplexMip::SolveExitStatus CplexMip::_solve() {
   934     int status;
   935     _applyMessageLevel();
   936     status = CPXmipopt (cplexEnv(), _prob);
   937     if (status==0)
   938       return SOLVED;
   939     else
   940       return UNSOLVED;
   941 
   942   }
   943 
   944 
   945   CplexMip::ProblemType CplexMip::_getType() const {
   946 
   947     int stat = CPXgetstat(cplexEnv(), _prob);
   948 
   949     //Fortunately, MIP statuses did not change for cplex 8.0
   950     switch (stat) {
   951     case CPXMIP_OPTIMAL:
   952       // Optimal integer solution has been found.
   953     case CPXMIP_OPTIMAL_TOL:
   954       // Optimal soluton with the tolerance defined by epgap or epagap has
   955       // been found.
   956       return OPTIMAL;
   957       //This also exists in later issues
   958       //    case CPXMIP_UNBOUNDED:
   959       //return UNBOUNDED;
   960       case CPXMIP_INFEASIBLE:
   961         return INFEASIBLE;
   962     default:
   963       return UNDEFINED;
   964     }
   965     //Unboundedness not treated well: the following is from cplex 9.0 doc
   966     // About Unboundedness
   967 
   968     // The treatment of models that are unbounded involves a few
   969     // subtleties. Specifically, a declaration of unboundedness means that
   970     // ILOG CPLEX has determined that the model has an unbounded
   971     // ray. Given any feasible solution x with objective z, a multiple of
   972     // the unbounded ray can be added to x to give a feasible solution
   973     // with objective z-1 (or z+1 for maximization models). Thus, if a
   974     // feasible solution exists, then the optimal objective is
   975     // unbounded. Note that ILOG CPLEX has not necessarily concluded that
   976     // a feasible solution exists. Users can call the routine CPXsolninfo
   977     // to determine whether ILOG CPLEX has also concluded that the model
   978     // has a feasible solution.
   979   }
   980 
   981   CplexMip::Value CplexMip::_getSol(int i) const {
   982     Value x;
   983     CPXgetmipx(cplexEnv(), _prob, &x, i, i);
   984     return x;
   985   }
   986 
   987   CplexMip::Value CplexMip::_getSolValue() const {
   988     Value objval;
   989     CPXgetmipobjval(cplexEnv(), _prob, &objval);
   990     return objval;
   991   }
   992 
   993 } //namespace lemon
   994