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