lemon/cplex.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 894 bb70ad62c95f
parent 551 9d0d7e20f76d
child 746 e4554cd6b2bf
child 955 8d281761dea4
permissions -rw-r--r--
Fix critical bug in preflow (#372)

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