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