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