1.1 --- a/lemon/lp_cplex.cc Tue Dec 02 21:40:33 2008 +0100
1.2 +++ b/lemon/lp_cplex.cc Tue Dec 02 22:48:28 2008 +0100
1.3 @@ -18,6 +18,8 @@
1.4
1.5 #include <iostream>
1.6 #include <vector>
1.7 +#include <cstring>
1.8 +
1.9 #include <lemon/lp_cplex.h>
1.10
1.11 extern "C" {
1.12 @@ -29,167 +31,226 @@
1.13 ///\brief Implementation of the LEMON-CPLEX lp solver interface.
1.14 namespace lemon {
1.15
1.16 - LpCplex::LpCplex() {
1.17 - // env = CPXopenCPLEXdevelop(&status);
1.18 - env = CPXopenCPLEX(&status);
1.19 - lp = CPXcreateprob(env, &status, "LP problem");
1.20 + CplexEnv::LicenseError::LicenseError(int status) {
1.21 + if (!CPXgeterrorstring(0, status, _message)) {
1.22 + std::strcpy(_message, "Cplex unknown error");
1.23 + }
1.24 }
1.25
1.26 - LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() {
1.27 - env = CPXopenCPLEX(&status);
1.28 - lp = CPXcloneprob(env, cplex.lp, &status);
1.29 + CplexEnv::CplexEnv() {
1.30 + int status;
1.31 + _cnt = new int;
1.32 + _env = CPXopenCPLEX(&status);
1.33 + if (_env == 0) {
1.34 + delete _cnt;
1.35 + _cnt = 0;
1.36 + throw LicenseError(status);
1.37 + }
1.38 + }
1.39 +
1.40 + CplexEnv::CplexEnv(const CplexEnv& other) {
1.41 + _env = other._env;
1.42 + _cnt = other._cnt;
1.43 + ++(*_cnt);
1.44 + }
1.45 +
1.46 + CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
1.47 + _env = other._env;
1.48 + _cnt = other._cnt;
1.49 + ++(*_cnt);
1.50 + return *this;
1.51 + }
1.52 +
1.53 + CplexEnv::~CplexEnv() {
1.54 + --(*_cnt);
1.55 + if (*_cnt == 0) {
1.56 + delete _cnt;
1.57 + CPXcloseCPLEX(&_env);
1.58 + }
1.59 + }
1.60 +
1.61 + CplexBase::CplexBase() : LpBase() {
1.62 + int status;
1.63 + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
1.64 + }
1.65 +
1.66 + CplexBase::CplexBase(const CplexEnv& env)
1.67 + : LpBase(), _env(env) {
1.68 + int status;
1.69 + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
1.70 + }
1.71 +
1.72 + CplexBase::CplexBase(const CplexBase& cplex)
1.73 + : LpBase() {
1.74 + int status;
1.75 + _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
1.76 rows = cplex.rows;
1.77 cols = cplex.cols;
1.78 }
1.79
1.80 - LpCplex::~LpCplex() {
1.81 - CPXfreeprob(env,&lp);
1.82 - CPXcloseCPLEX(&env);
1.83 + CplexBase::~CplexBase() {
1.84 + CPXfreeprob(cplexEnv(),&_prob);
1.85 }
1.86
1.87 - LpSolverBase* LpCplex::_newLp()
1.88 - {
1.89 - //The first approach opens a new environment
1.90 - return new LpCplex();
1.91 - }
1.92 -
1.93 - LpSolverBase* LpCplex::_copyLp() {
1.94 - return new LpCplex(*this);
1.95 - }
1.96 -
1.97 - int LpCplex::_addCol()
1.98 - {
1.99 - int i = CPXgetnumcols(env, lp);
1.100 - Value lb[1],ub[1];
1.101 - lb[0]=-INF;
1.102 - ub[0]=INF;
1.103 - status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL);
1.104 + int CplexBase::_addCol() {
1.105 + int i = CPXgetnumcols(cplexEnv(), _prob);
1.106 + double lb = -INF, ub = INF;
1.107 + CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
1.108 return i;
1.109 }
1.110
1.111
1.112 - int LpCplex::_addRow()
1.113 - {
1.114 - //We want a row that is not constrained
1.115 - char sense[1];
1.116 - sense[0]='L';//<= constraint
1.117 - Value rhs[1];
1.118 - rhs[0]=INF;
1.119 - int i = CPXgetnumrows(env, lp);
1.120 - status = CPXnewrows(env, lp, 1, rhs, sense, NULL, NULL);
1.121 + int CplexBase::_addRow() {
1.122 + int i = CPXgetnumrows(cplexEnv(), _prob);
1.123 + const double ub = INF;
1.124 + const char s = 'L';
1.125 + CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
1.126 return i;
1.127 }
1.128
1.129
1.130 - void LpCplex::_eraseCol(int i) {
1.131 - CPXdelcols(env, lp, i, i);
1.132 + void CplexBase::_eraseCol(int i) {
1.133 + CPXdelcols(cplexEnv(), _prob, i, i);
1.134 }
1.135
1.136 - void LpCplex::_eraseRow(int i) {
1.137 - CPXdelrows(env, lp, i, i);
1.138 + void CplexBase::_eraseRow(int i) {
1.139 + CPXdelrows(cplexEnv(), _prob, i, i);
1.140 }
1.141
1.142 - void LpCplex::_getColName(int col, std::string &name) const
1.143 - {
1.144 - ///\bug Untested
1.145 - int storespace;
1.146 - CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col);
1.147 - if (storespace == 0) {
1.148 + void CplexBase::_eraseColId(int i) {
1.149 + cols.eraseIndex(i);
1.150 + cols.shiftIndices(i);
1.151 + }
1.152 + void CplexBase::_eraseRowId(int i) {
1.153 + rows.eraseIndex(i);
1.154 + rows.shiftIndices(i);
1.155 + }
1.156 +
1.157 + void CplexBase::_getColName(int col, std::string &name) const {
1.158 + int size;
1.159 + CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
1.160 + if (size == 0) {
1.161 name.clear();
1.162 return;
1.163 }
1.164
1.165 - storespace *= -1;
1.166 - std::vector<char> buf(storespace);
1.167 - char *names[1];
1.168 - int dontcare;
1.169 - ///\bug return code unchecked for error
1.170 - CPXgetcolname(env, lp, names, &*buf.begin(), storespace,
1.171 - &dontcare, col, col);
1.172 - name = names[0];
1.173 + size *= -1;
1.174 + std::vector<char> buf(size);
1.175 + char *cname;
1.176 + int tmp;
1.177 + CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
1.178 + &tmp, col, col);
1.179 + name = cname;
1.180 }
1.181
1.182 - void LpCplex::_setColName(int col, const std::string &name)
1.183 - {
1.184 - ///\bug Untested
1.185 - char *names[1];
1.186 - names[0] = const_cast<char*>(name.c_str());
1.187 - ///\bug return code unchecked for error
1.188 - CPXchgcolname(env, lp, 1, &col, names);
1.189 + void CplexBase::_setColName(int col, const std::string &name) {
1.190 + char *cname;
1.191 + cname = const_cast<char*>(name.c_str());
1.192 + CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
1.193 }
1.194
1.195 - int LpCplex::_colByName(const std::string& name) const
1.196 - {
1.197 + int CplexBase::_colByName(const std::string& name) const {
1.198 int index;
1.199 - if (CPXgetcolindex(env, lp,
1.200 + if (CPXgetcolindex(cplexEnv(), _prob,
1.201 const_cast<char*>(name.c_str()), &index) == 0) {
1.202 return index;
1.203 }
1.204 return -1;
1.205 }
1.206
1.207 - ///\warning Data at index 0 is ignored in the arrays.
1.208 - void LpCplex::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e)
1.209 + void CplexBase::_getRowName(int row, std::string &name) const {
1.210 + int size;
1.211 + CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
1.212 + if (size == 0) {
1.213 + name.clear();
1.214 + return;
1.215 + }
1.216 +
1.217 + size *= -1;
1.218 + std::vector<char> buf(size);
1.219 + char *cname;
1.220 + int tmp;
1.221 + CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
1.222 + &tmp, row, row);
1.223 + name = cname;
1.224 + }
1.225 +
1.226 + void CplexBase::_setRowName(int row, const std::string &name) {
1.227 + char *cname;
1.228 + cname = const_cast<char*>(name.c_str());
1.229 + CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
1.230 + }
1.231 +
1.232 + int CplexBase::_rowByName(const std::string& name) const {
1.233 + int index;
1.234 + if (CPXgetrowindex(cplexEnv(), _prob,
1.235 + const_cast<char*>(name.c_str()), &index) == 0) {
1.236 + return index;
1.237 + }
1.238 + return -1;
1.239 + }
1.240 +
1.241 + void CplexBase::_setRowCoeffs(int i, ExprIterator b,
1.242 + ExprIterator e)
1.243 {
1.244 std::vector<int> indices;
1.245 std::vector<int> rowlist;
1.246 std::vector<Value> values;
1.247
1.248 - for(ConstRowIterator it=b; it!=e; ++it) {
1.249 + for(ExprIterator it=b; it!=e; ++it) {
1.250 indices.push_back(it->first);
1.251 values.push_back(it->second);
1.252 rowlist.push_back(i);
1.253 }
1.254
1.255 - status = CPXchgcoeflist(env, lp, values.size(),
1.256 - &rowlist[0], &indices[0], &values[0]);
1.257 + CPXchgcoeflist(cplexEnv(), _prob, values.size(),
1.258 + &rowlist.front(), &indices.front(), &values.front());
1.259 }
1.260
1.261 - void LpCplex::_getRowCoeffs(int i, RowIterator b) const {
1.262 + void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
1.263 int tmp1, tmp2, tmp3, length;
1.264 - CPXgetrows(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
1.265 + CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
1.266
1.267 length = -length;
1.268 std::vector<int> indices(length);
1.269 std::vector<double> values(length);
1.270
1.271 - CPXgetrows(env, lp, &tmp1, &tmp2, &indices[0], &values[0],
1.272 + CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
1.273 + &indices.front(), &values.front(),
1.274 length, &tmp3, i, i);
1.275
1.276 for (int i = 0; i < length; ++i) {
1.277 *b = std::make_pair(indices[i], values[i]);
1.278 ++b;
1.279 }
1.280 -
1.281 - /// \todo implement
1.282 }
1.283
1.284 - void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e)
1.285 - {
1.286 + void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
1.287 std::vector<int> indices;
1.288 std::vector<int> collist;
1.289 std::vector<Value> values;
1.290
1.291 - for(ConstColIterator it=b; it!=e; ++it) {
1.292 + for(ExprIterator it=b; it!=e; ++it) {
1.293 indices.push_back(it->first);
1.294 values.push_back(it->second);
1.295 collist.push_back(i);
1.296 }
1.297
1.298 - status = CPXchgcoeflist(env, lp, values.size(),
1.299 - &indices[0], &collist[0], &values[0]);
1.300 + CPXchgcoeflist(cplexEnv(), _prob, values.size(),
1.301 + &indices.front(), &collist.front(), &values.front());
1.302 }
1.303
1.304 - void LpCplex::_getColCoeffs(int i, ColIterator b) const {
1.305 + void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
1.306
1.307 int tmp1, tmp2, tmp3, length;
1.308 - CPXgetcols(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
1.309 + CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
1.310
1.311 length = -length;
1.312 std::vector<int> indices(length);
1.313 std::vector<double> values(length);
1.314
1.315 - CPXgetcols(env, lp, &tmp1, &tmp2, &indices[0], &values[0],
1.316 + CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
1.317 + &indices.front(), &values.front(),
1.318 length, &tmp3, i, i);
1.319
1.320 for (int i = 0; i < length; ++i) {
1.321 @@ -199,175 +260,209 @@
1.322
1.323 }
1.324
1.325 - void LpCplex::_setCoeff(int row, int col, Value value)
1.326 - {
1.327 - CPXchgcoef(env, lp, row, col, value);
1.328 + void CplexBase::_setCoeff(int row, int col, Value value) {
1.329 + CPXchgcoef(cplexEnv(), _prob, row, col, value);
1.330 }
1.331
1.332 - LpCplex::Value LpCplex::_getCoeff(int row, int col) const
1.333 - {
1.334 - LpCplex::Value value;
1.335 - CPXgetcoef(env, lp, row, col, &value);
1.336 + CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
1.337 + CplexBase::Value value;
1.338 + CPXgetcoef(cplexEnv(), _prob, row, col, &value);
1.339 return value;
1.340 }
1.341
1.342 - void LpCplex::_setColLowerBound(int i, Value value)
1.343 + void CplexBase::_setColLowerBound(int i, Value value) {
1.344 + const char s = 'L';
1.345 + CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
1.346 + }
1.347 +
1.348 + CplexBase::Value CplexBase::_getColLowerBound(int i) const {
1.349 + CplexBase::Value res;
1.350 + CPXgetlb(cplexEnv(), _prob, &res, i, i);
1.351 + return res <= -CPX_INFBOUND ? -INF : res;
1.352 + }
1.353 +
1.354 + void CplexBase::_setColUpperBound(int i, Value value)
1.355 {
1.356 - int indices[1];
1.357 - indices[0]=i;
1.358 - char lu[1];
1.359 - lu[0]='L';
1.360 - Value bd[1];
1.361 - bd[0]=value;
1.362 - status = CPXchgbds(env, lp, 1, indices, lu, bd);
1.363 + const char s = 'U';
1.364 + CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
1.365 + }
1.366 +
1.367 + CplexBase::Value CplexBase::_getColUpperBound(int i) const {
1.368 + CplexBase::Value res;
1.369 + CPXgetub(cplexEnv(), _prob, &res, i, i);
1.370 + return res >= CPX_INFBOUND ? INF : res;
1.371 + }
1.372 +
1.373 + CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
1.374 + char s;
1.375 + CPXgetsense(cplexEnv(), _prob, &s, i, i);
1.376 + CplexBase::Value res;
1.377 +
1.378 + switch (s) {
1.379 + case 'G':
1.380 + case 'R':
1.381 + case 'E':
1.382 + CPXgetrhs(cplexEnv(), _prob, &res, i, i);
1.383 + return res <= -CPX_INFBOUND ? -INF : res;
1.384 + default:
1.385 + return -INF;
1.386 + }
1.387 + }
1.388 +
1.389 + CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
1.390 + char s;
1.391 + CPXgetsense(cplexEnv(), _prob, &s, i, i);
1.392 + CplexBase::Value res;
1.393 +
1.394 + switch (s) {
1.395 + case 'L':
1.396 + case 'E':
1.397 + CPXgetrhs(cplexEnv(), _prob, &res, i, i);
1.398 + return res >= CPX_INFBOUND ? INF : res;
1.399 + case 'R':
1.400 + CPXgetrhs(cplexEnv(), _prob, &res, i, i);
1.401 + {
1.402 + double rng;
1.403 + CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
1.404 + res += rng;
1.405 + }
1.406 + return res >= CPX_INFBOUND ? INF : res;
1.407 + default:
1.408 + return INF;
1.409 + }
1.410 + }
1.411 +
1.412 + //This is easier to implement
1.413 + void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
1.414 + if (lb == -INF) {
1.415 + const char s = 'L';
1.416 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.417 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
1.418 + } else if (ub == INF) {
1.419 + const char s = 'G';
1.420 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.421 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
1.422 + } else if (lb == ub){
1.423 + const char s = 'E';
1.424 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.425 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
1.426 + } else {
1.427 + const char s = 'R';
1.428 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.429 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
1.430 + double len = ub - lb;
1.431 + CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
1.432 + }
1.433 + }
1.434 +
1.435 + void CplexBase::_setRowLowerBound(int i, Value lb)
1.436 + {
1.437 + LEMON_ASSERT(lb != INF, "Invalid bound");
1.438 + _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
1.439 + }
1.440 +
1.441 + void CplexBase::_setRowUpperBound(int i, Value ub)
1.442 + {
1.443 +
1.444 + LEMON_ASSERT(ub != -INF, "Invalid bound");
1.445 + _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
1.446 + }
1.447 +
1.448 + void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
1.449 + {
1.450 + std::vector<int> indices;
1.451 + std::vector<Value> values;
1.452 + for(ExprIterator it=b; it!=e; ++it) {
1.453 + indices.push_back(it->first);
1.454 + values.push_back(it->second);
1.455 + }
1.456 + CPXchgobj(cplexEnv(), _prob, values.size(),
1.457 + &indices.front(), &values.front());
1.458
1.459 }
1.460
1.461 - LpCplex::Value LpCplex::_getColLowerBound(int i) const
1.462 + void CplexBase::_getObjCoeffs(InsertIterator b) const
1.463 {
1.464 - LpCplex::Value x;
1.465 - CPXgetlb (env, lp, &x, i, i);
1.466 - if (x <= -CPX_INFBOUND) x = -INF;
1.467 - return x;
1.468 - }
1.469 + int num = CPXgetnumcols(cplexEnv(), _prob);
1.470 + std::vector<Value> x(num);
1.471
1.472 - void LpCplex::_setColUpperBound(int i, Value value)
1.473 - {
1.474 - int indices[1];
1.475 - indices[0]=i;
1.476 - char lu[1];
1.477 - lu[0]='U';
1.478 - Value bd[1];
1.479 - bd[0]=value;
1.480 - status = CPXchgbds(env, lp, 1, indices, lu, bd);
1.481 - }
1.482 -
1.483 - LpCplex::Value LpCplex::_getColUpperBound(int i) const
1.484 - {
1.485 - LpCplex::Value x;
1.486 - CPXgetub (env, lp, &x, i, i);
1.487 - if (x >= CPX_INFBOUND) x = INF;
1.488 - return x;
1.489 - }
1.490 -
1.491 - //This will be easier to implement
1.492 - void LpCplex::_setRowBounds(int i, Value lb, Value ub)
1.493 - {
1.494 - //Bad parameter
1.495 - if (lb==INF || ub==-INF) {
1.496 - //FIXME error
1.497 - }
1.498 -
1.499 - int cnt=1;
1.500 - int indices[1];
1.501 - indices[0]=i;
1.502 - char sense[1];
1.503 -
1.504 - if (lb==-INF){
1.505 - sense[0]='L';
1.506 - CPXchgsense(env, lp, cnt, indices, sense);
1.507 - CPXchgcoef(env, lp, i, -1, ub);
1.508 -
1.509 - }
1.510 - else{
1.511 - if (ub==INF){
1.512 - sense[0]='G';
1.513 - CPXchgsense(env, lp, cnt, indices, sense);
1.514 - CPXchgcoef(env, lp, i, -1, lb);
1.515 - }
1.516 - else{
1.517 - if (lb == ub){
1.518 - sense[0]='E';
1.519 - CPXchgsense(env, lp, cnt, indices, sense);
1.520 - CPXchgcoef(env, lp, i, -1, lb);
1.521 - }
1.522 - else{
1.523 - sense[0]='R';
1.524 - CPXchgsense(env, lp, cnt, indices, sense);
1.525 - CPXchgcoef(env, lp, i, -1, lb);
1.526 - CPXchgcoef(env, lp, i, -2, ub-lb);
1.527 - }
1.528 + CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
1.529 + for (int i = 0; i < num; ++i) {
1.530 + if (x[i] != 0.0) {
1.531 + *b = std::make_pair(i, x[i]);
1.532 + ++b;
1.533 }
1.534 }
1.535 }
1.536
1.537 -// void LpCplex::_setRowLowerBound(int i, Value value)
1.538 -// {
1.539 -// //Not implemented, obsolete
1.540 -// }
1.541 -
1.542 -// void LpCplex::_setRowUpperBound(int i, Value value)
1.543 -// {
1.544 -// //Not implemented, obsolete
1.545 -// // //TODO Ezt kell meg megirni
1.546 -// // //type of the problem
1.547 -// // char sense[1];
1.548 -// // status = CPXgetsense(env, lp, sense, i, i);
1.549 -// // Value rhs[1];
1.550 -// // status = CPXgetrhs(env, lp, rhs, i, i);
1.551 -
1.552 -// // switch (sense[0]) {
1.553 -// // case 'L'://<= constraint
1.554 -// // break;
1.555 -// // case 'E'://= constraint
1.556 -// // break;
1.557 -// // case 'G'://>= constraint
1.558 -// // break;
1.559 -// // case 'R'://ranged constraint
1.560 -// // break;
1.561 -// // default: ;
1.562 -// // //FIXME error
1.563 -// // }
1.564 -
1.565 -// // status = CPXchgcoef(env, lp, i, -2, value_rng);
1.566 -// }
1.567 -
1.568 - void LpCplex::_getRowBounds(int i, Value &lb, Value &ub) const
1.569 + void CplexBase::_setObjCoeff(int i, Value obj_coef)
1.570 {
1.571 - char sense;
1.572 - CPXgetsense(env, lp, &sense,i,i);
1.573 - lb=-INF;
1.574 - ub=INF;
1.575 - switch (sense)
1.576 - {
1.577 - case 'L':
1.578 - CPXgetcoef(env, lp, i, -1, &ub);
1.579 - break;
1.580 - case 'G':
1.581 - CPXgetcoef(env, lp, i, -1, &lb);
1.582 - break;
1.583 - case 'E':
1.584 - CPXgetcoef(env, lp, i, -1, &lb);
1.585 - ub=lb;
1.586 - break;
1.587 - case 'R':
1.588 - CPXgetcoef(env, lp, i, -1, &lb);
1.589 - Value x;
1.590 - CPXgetcoef(env, lp, i, -2, &x);
1.591 - ub=lb+x;
1.592 - break;
1.593 - }
1.594 + CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
1.595 }
1.596
1.597 - void LpCplex::_setObjCoeff(int i, Value obj_coef)
1.598 - {
1.599 - CPXchgcoef(env, lp, -1, i, obj_coef);
1.600 - }
1.601 -
1.602 - LpCplex::Value LpCplex::_getObjCoeff(int i) const
1.603 + CplexBase::Value CplexBase::_getObjCoeff(int i) const
1.604 {
1.605 Value x;
1.606 - CPXgetcoef(env, lp, -1, i, &x);
1.607 + CPXgetobj(cplexEnv(), _prob, &x, i, i);
1.608 return x;
1.609 }
1.610
1.611 - void LpCplex::_clearObj()
1.612 - {
1.613 - for (int i=0;i< CPXgetnumcols(env, lp);++i){
1.614 - CPXchgcoef(env, lp, -1, i, 0);
1.615 + void CplexBase::_setSense(CplexBase::Sense sense) {
1.616 + switch (sense) {
1.617 + case MIN:
1.618 + CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
1.619 + break;
1.620 + case MAX:
1.621 + CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
1.622 + break;
1.623 }
1.624 + }
1.625
1.626 + CplexBase::Sense CplexBase::_getSense() const {
1.627 + switch (CPXgetobjsen(cplexEnv(), _prob)) {
1.628 + case CPX_MIN:
1.629 + return MIN;
1.630 + case CPX_MAX:
1.631 + return MAX;
1.632 + default:
1.633 + LEMON_ASSERT(false, "Invalid sense");
1.634 + return CplexBase::Sense();
1.635 + }
1.636 }
1.637 +
1.638 + void CplexBase::_clear() {
1.639 + CPXfreeprob(cplexEnv(),&_prob);
1.640 + int status;
1.641 + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
1.642 + rows.clear();
1.643 + cols.clear();
1.644 + }
1.645 +
1.646 + // LpCplex members
1.647 +
1.648 + LpCplex::LpCplex()
1.649 + : LpBase(), CplexBase(), LpSolver() {}
1.650 +
1.651 + LpCplex::LpCplex(const CplexEnv& env)
1.652 + : LpBase(), CplexBase(env), LpSolver() {}
1.653 +
1.654 + LpCplex::LpCplex(const LpCplex& other)
1.655 + : LpBase(), CplexBase(other), LpSolver() {}
1.656 +
1.657 + LpCplex::~LpCplex() {}
1.658 +
1.659 + LpCplex* LpCplex::_newSolver() const { return new LpCplex; }
1.660 + LpCplex* LpCplex::_cloneSolver() const {return new LpCplex(*this); }
1.661 +
1.662 + const char* LpCplex::_solverName() const { return "LpCplex"; }
1.663 +
1.664 + void LpCplex::_clear_temporals() {
1.665 + _col_status.clear();
1.666 + _row_status.clear();
1.667 + _primal_ray.clear();
1.668 + _dual_ray.clear();
1.669 + }
1.670 +
1.671 // The routine returns zero unless an error occurred during the
1.672 // optimization. Examples of errors include exhausting available
1.673 // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
1.674 @@ -377,32 +472,24 @@
1.675 // value does not necessarily mean that a solution exists. Use query
1.676 // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
1.677 // further information about the status of the optimization.
1.678 - LpCplex::SolveExitStatus LpCplex::_solve()
1.679 - {
1.680 - //CPX_PARAM_LPMETHOD
1.681 - status = CPXlpopt(env, lp);
1.682 - //status = CPXprimopt(env, lp);
1.683 + LpCplex::SolveExitStatus LpCplex::convertStatus(int status) {
1.684 #if CPX_VERSION >= 800
1.685 - if (status)
1.686 - {
1.687 + if (status == 0) {
1.688 + switch (CPXgetstat(cplexEnv(), _prob)) {
1.689 + case CPX_STAT_OPTIMAL:
1.690 + case CPX_STAT_INFEASIBLE:
1.691 + case CPX_STAT_UNBOUNDED:
1.692 + return SOLVED;
1.693 + default:
1.694 + return UNSOLVED;
1.695 + }
1.696 + } else {
1.697 return UNSOLVED;
1.698 }
1.699 - else
1.700 - {
1.701 - switch (CPXgetstat(env, lp))
1.702 - {
1.703 - case CPX_STAT_OPTIMAL:
1.704 - case CPX_STAT_INFEASIBLE:
1.705 - case CPX_STAT_UNBOUNDED:
1.706 - return SOLVED;
1.707 - default:
1.708 - return UNSOLVED;
1.709 - }
1.710 - }
1.711 #else
1.712 - if (status == 0){
1.713 + if (status == 0) {
1.714 //We want to exclude some cases
1.715 - switch (CPXgetstat(env, lp)){
1.716 + switch (CPXgetstat(cplexEnv(), _prob)) {
1.717 case CPX_OBJ_LIM:
1.718 case CPX_IT_LIM_FEAS:
1.719 case CPX_IT_LIM_INFEAS:
1.720 @@ -412,115 +499,179 @@
1.721 default:
1.722 return SOLVED;
1.723 }
1.724 - }
1.725 - else{
1.726 + } else {
1.727 return UNSOLVED;
1.728 }
1.729 #endif
1.730 }
1.731
1.732 - LpCplex::Value LpCplex::_getPrimal(int i) const
1.733 - {
1.734 + LpCplex::SolveExitStatus LpCplex::_solve() {
1.735 + _clear_temporals();
1.736 + return convertStatus(CPXlpopt(cplexEnv(), _prob));
1.737 + }
1.738 +
1.739 + LpCplex::SolveExitStatus LpCplex::solvePrimal() {
1.740 + _clear_temporals();
1.741 + return convertStatus(CPXprimopt(cplexEnv(), _prob));
1.742 + }
1.743 +
1.744 + LpCplex::SolveExitStatus LpCplex::solveDual() {
1.745 + _clear_temporals();
1.746 + return convertStatus(CPXdualopt(cplexEnv(), _prob));
1.747 + }
1.748 +
1.749 + LpCplex::SolveExitStatus LpCplex::solveBarrier() {
1.750 + _clear_temporals();
1.751 + return convertStatus(CPXbaropt(cplexEnv(), _prob));
1.752 + }
1.753 +
1.754 + LpCplex::Value LpCplex::_getPrimal(int i) const {
1.755 Value x;
1.756 - CPXgetx(env, lp, &x, i, i);
1.757 + CPXgetx(cplexEnv(), _prob, &x, i, i);
1.758 return x;
1.759 }
1.760
1.761 - LpCplex::Value LpCplex::_getDual(int i) const
1.762 - {
1.763 + LpCplex::Value LpCplex::_getDual(int i) const {
1.764 Value y;
1.765 - CPXgetpi(env, lp, &y, i, i);
1.766 + CPXgetpi(cplexEnv(), _prob, &y, i, i);
1.767 return y;
1.768 }
1.769
1.770 - LpCplex::Value LpCplex::_getPrimalValue() const
1.771 - {
1.772 + LpCplex::Value LpCplex::_getPrimalValue() const {
1.773 Value objval;
1.774 - //method = CPXgetmethod (env, lp);
1.775 - //printf("CPXgetprobtype %d \n",CPXgetprobtype(env,lp));
1.776 - CPXgetobjval(env, lp, &objval);
1.777 - //printf("Objective value: %g \n",objval);
1.778 + CPXgetobjval(cplexEnv(), _prob, &objval);
1.779 return objval;
1.780 }
1.781 - bool LpCplex::_isBasicCol(int i) const
1.782 - {
1.783 - std::vector<int> cstat(CPXgetnumcols(env, lp));
1.784 - CPXgetbase(env, lp, &*cstat.begin(), NULL);
1.785 - return (cstat[i]==CPX_BASIC);
1.786 +
1.787 + LpCplex::VarStatus LpCplex::_getColStatus(int i) const {
1.788 + if (_col_status.empty()) {
1.789 + _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
1.790 + CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
1.791 + }
1.792 + switch (_col_status[i]) {
1.793 + case CPX_BASIC:
1.794 + return BASIC;
1.795 + case CPX_FREE_SUPER:
1.796 + return FREE;
1.797 + case CPX_AT_LOWER:
1.798 + return LOWER;
1.799 + case CPX_AT_UPPER:
1.800 + return UPPER;
1.801 + default:
1.802 + LEMON_ASSERT(false, "Wrong column status");
1.803 + return LpCplex::VarStatus();
1.804 + }
1.805 }
1.806
1.807 -//7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!)
1.808 -// This table lists the statuses, returned by the CPXgetstat()
1.809 -// routine, for solutions to LP problems or mixed integer problems. If
1.810 -// no solution exists, the return value is zero.
1.811 + LpCplex::VarStatus LpCplex::_getRowStatus(int i) const {
1.812 + if (_row_status.empty()) {
1.813 + _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
1.814 + CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
1.815 + }
1.816 + switch (_row_status[i]) {
1.817 + case CPX_BASIC:
1.818 + return BASIC;
1.819 + case CPX_AT_LOWER:
1.820 + {
1.821 + char s;
1.822 + CPXgetsense(cplexEnv(), _prob, &s, i, i);
1.823 + return s != 'L' ? LOWER : UPPER;
1.824 + }
1.825 + case CPX_AT_UPPER:
1.826 + return UPPER;
1.827 + default:
1.828 + LEMON_ASSERT(false, "Wrong row status");
1.829 + return LpCplex::VarStatus();
1.830 + }
1.831 + }
1.832
1.833 -// For Simplex, Barrier
1.834 -// 1 CPX_OPTIMAL
1.835 -// Optimal solution found
1.836 -// 2 CPX_INFEASIBLE
1.837 -// Problem infeasible
1.838 -// 3 CPX_UNBOUNDED
1.839 -// Problem unbounded
1.840 -// 4 CPX_OBJ_LIM
1.841 -// Objective limit exceeded in Phase II
1.842 -// 5 CPX_IT_LIM_FEAS
1.843 -// Iteration limit exceeded in Phase II
1.844 -// 6 CPX_IT_LIM_INFEAS
1.845 -// Iteration limit exceeded in Phase I
1.846 -// 7 CPX_TIME_LIM_FEAS
1.847 -// Time limit exceeded in Phase II
1.848 -// 8 CPX_TIME_LIM_INFEAS
1.849 -// Time limit exceeded in Phase I
1.850 -// 9 CPX_NUM_BEST_FEAS
1.851 -// Problem non-optimal, singularities in Phase II
1.852 -// 10 CPX_NUM_BEST_INFEAS
1.853 -// Problem non-optimal, singularities in Phase I
1.854 -// 11 CPX_OPTIMAL_INFEAS
1.855 -// Optimal solution found, unscaled infeasibilities
1.856 -// 12 CPX_ABORT_FEAS
1.857 -// Aborted in Phase II
1.858 -// 13 CPX_ABORT_INFEAS
1.859 -// Aborted in Phase I
1.860 -// 14 CPX_ABORT_DUAL_INFEAS
1.861 -// Aborted in barrier, dual infeasible
1.862 -// 15 CPX_ABORT_PRIM_INFEAS
1.863 -// Aborted in barrier, primal infeasible
1.864 -// 16 CPX_ABORT_PRIM_DUAL_INFEAS
1.865 -// Aborted in barrier, primal and dual infeasible
1.866 -// 17 CPX_ABORT_PRIM_DUAL_FEAS
1.867 -// Aborted in barrier, primal and dual feasible
1.868 -// 18 CPX_ABORT_CROSSOVER
1.869 -// Aborted in crossover
1.870 -// 19 CPX_INForUNBD
1.871 -// Infeasible or unbounded
1.872 -// 20 CPX_PIVOT
1.873 -// User pivot used
1.874 -//
1.875 -// Ezeket hova tegyem:
1.876 -// ??case CPX_ABORT_DUAL_INFEAS
1.877 -// ??case CPX_ABORT_CROSSOVER
1.878 -// ??case CPX_INForUNBD
1.879 -// ??case CPX_PIVOT
1.880 + LpCplex::Value LpCplex::_getPrimalRay(int i) const {
1.881 + if (_primal_ray.empty()) {
1.882 + _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
1.883 + CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
1.884 + }
1.885 + return _primal_ray[i];
1.886 + }
1.887
1.888 -//Some more interesting stuff:
1.889 + LpCplex::Value LpCplex::_getDualRay(int i) const {
1.890 + if (_dual_ray.empty()) {
1.891
1.892 -// CPX_PARAM_LPMETHOD 1062 int LPMETHOD
1.893 -// 0 Automatic
1.894 -// 1 Primal Simplex
1.895 -// 2 Dual Simplex
1.896 -// 3 Network Simplex
1.897 -// 4 Standard Barrier
1.898 -// Default: 0
1.899 -// Description: Method for linear optimization.
1.900 -// Determines which algorithm is used when CPXlpopt() (or "optimize"
1.901 -// in the Interactive Optimizer) is called. Currently the behavior of
1.902 -// the "Automatic" setting is that CPLEX simply invokes the dual
1.903 -// simplex method, but this capability may be expanded in the future
1.904 -// so that CPLEX chooses the method based on problem characteristics
1.905 + }
1.906 + return _dual_ray[i];
1.907 + }
1.908 +
1.909 + //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!)
1.910 + // This table lists the statuses, returned by the CPXgetstat()
1.911 + // routine, for solutions to LP problems or mixed integer problems. If
1.912 + // no solution exists, the return value is zero.
1.913 +
1.914 + // For Simplex, Barrier
1.915 + // 1 CPX_OPTIMAL
1.916 + // Optimal solution found
1.917 + // 2 CPX_INFEASIBLE
1.918 + // Problem infeasible
1.919 + // 3 CPX_UNBOUNDED
1.920 + // Problem unbounded
1.921 + // 4 CPX_OBJ_LIM
1.922 + // Objective limit exceeded in Phase II
1.923 + // 5 CPX_IT_LIM_FEAS
1.924 + // Iteration limit exceeded in Phase II
1.925 + // 6 CPX_IT_LIM_INFEAS
1.926 + // Iteration limit exceeded in Phase I
1.927 + // 7 CPX_TIME_LIM_FEAS
1.928 + // Time limit exceeded in Phase II
1.929 + // 8 CPX_TIME_LIM_INFEAS
1.930 + // Time limit exceeded in Phase I
1.931 + // 9 CPX_NUM_BEST_FEAS
1.932 + // Problem non-optimal, singularities in Phase II
1.933 + // 10 CPX_NUM_BEST_INFEAS
1.934 + // Problem non-optimal, singularities in Phase I
1.935 + // 11 CPX_OPTIMAL_INFEAS
1.936 + // Optimal solution found, unscaled infeasibilities
1.937 + // 12 CPX_ABORT_FEAS
1.938 + // Aborted in Phase II
1.939 + // 13 CPX_ABORT_INFEAS
1.940 + // Aborted in Phase I
1.941 + // 14 CPX_ABORT_DUAL_INFEAS
1.942 + // Aborted in barrier, dual infeasible
1.943 + // 15 CPX_ABORT_PRIM_INFEAS
1.944 + // Aborted in barrier, primal infeasible
1.945 + // 16 CPX_ABORT_PRIM_DUAL_INFEAS
1.946 + // Aborted in barrier, primal and dual infeasible
1.947 + // 17 CPX_ABORT_PRIM_DUAL_FEAS
1.948 + // Aborted in barrier, primal and dual feasible
1.949 + // 18 CPX_ABORT_CROSSOVER
1.950 + // Aborted in crossover
1.951 + // 19 CPX_INForUNBD
1.952 + // Infeasible or unbounded
1.953 + // 20 CPX_PIVOT
1.954 + // User pivot used
1.955 + //
1.956 + // Ezeket hova tegyem:
1.957 + // ??case CPX_ABORT_DUAL_INFEAS
1.958 + // ??case CPX_ABORT_CROSSOVER
1.959 + // ??case CPX_INForUNBD
1.960 + // ??case CPX_PIVOT
1.961 +
1.962 + //Some more interesting stuff:
1.963 +
1.964 + // CPX_PARAM_PROBMETHOD 1062 int LPMETHOD
1.965 + // 0 Automatic
1.966 + // 1 Primal Simplex
1.967 + // 2 Dual Simplex
1.968 + // 3 Network Simplex
1.969 + // 4 Standard Barrier
1.970 + // Default: 0
1.971 + // Description: Method for linear optimization.
1.972 + // Determines which algorithm is used when CPXlpopt() (or "optimize"
1.973 + // in the Interactive Optimizer) is called. Currently the behavior of
1.974 + // the "Automatic" setting is that CPLEX simply invokes the dual
1.975 + // simplex method, but this capability may be expanded in the future
1.976 + // so that CPLEX chooses the method based on problem characteristics
1.977 #if CPX_VERSION < 900
1.978 - void statusSwitch(CPXENVptr env,int& stat){
1.979 + void statusSwitch(CPXENVptr cplexEnv(),int& stat){
1.980 int lpmethod;
1.981 - CPXgetintparam (env,CPX_PARAM_LPMETHOD,&lpmethod);
1.982 + CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
1.983 if (lpmethod==2){
1.984 if (stat==CPX_UNBOUNDED){
1.985 stat=CPX_INFEASIBLE;
1.986 @@ -535,8 +686,213 @@
1.987 void statusSwitch(CPXENVptr,int&){}
1.988 #endif
1.989
1.990 - LpCplex::SolutionStatus LpCplex::_getPrimalStatus() const
1.991 - {
1.992 + LpCplex::ProblemType LpCplex::_getPrimalType() const {
1.993 + // Unboundedness not treated well: the following is from cplex 9.0 doc
1.994 + // About Unboundedness
1.995 +
1.996 + // The treatment of models that are unbounded involves a few
1.997 + // subtleties. Specifically, a declaration of unboundedness means that
1.998 + // ILOG CPLEX has determined that the model has an unbounded
1.999 + // ray. Given any feasible solution x with objective z, a multiple of
1.1000 + // the unbounded ray can be added to x to give a feasible solution
1.1001 + // with objective z-1 (or z+1 for maximization models). Thus, if a
1.1002 + // feasible solution exists, then the optimal objective is
1.1003 + // unbounded. Note that ILOG CPLEX has not necessarily concluded that
1.1004 + // a feasible solution exists. Users can call the routine CPXsolninfo
1.1005 + // to determine whether ILOG CPLEX has also concluded that the model
1.1006 + // has a feasible solution.
1.1007 +
1.1008 + int stat = CPXgetstat(cplexEnv(), _prob);
1.1009 +#if CPX_VERSION >= 800
1.1010 + switch (stat)
1.1011 + {
1.1012 + case CPX_STAT_OPTIMAL:
1.1013 + return OPTIMAL;
1.1014 + case CPX_STAT_UNBOUNDED:
1.1015 + return UNBOUNDED;
1.1016 + case CPX_STAT_INFEASIBLE:
1.1017 + return INFEASIBLE;
1.1018 + default:
1.1019 + return UNDEFINED;
1.1020 + }
1.1021 +#else
1.1022 + statusSwitch(cplexEnv(),stat);
1.1023 + //CPXgetstat(cplexEnv(), _prob);
1.1024 + //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL);
1.1025 + switch (stat) {
1.1026 + case 0:
1.1027 + return UNDEFINED; //Undefined
1.1028 + case CPX_OPTIMAL://Optimal
1.1029 + return OPTIMAL;
1.1030 + case CPX_UNBOUNDED://Unbounded
1.1031 + return INFEASIBLE;//In case of dual simplex
1.1032 + //return UNBOUNDED;
1.1033 + case CPX_INFEASIBLE://Infeasible
1.1034 + // case CPX_IT_LIM_INFEAS:
1.1035 + // case CPX_TIME_LIM_INFEAS:
1.1036 + // case CPX_NUM_BEST_INFEAS:
1.1037 + // case CPX_OPTIMAL_INFEAS:
1.1038 + // case CPX_ABORT_INFEAS:
1.1039 + // case CPX_ABORT_PRIM_INFEAS:
1.1040 + // case CPX_ABORT_PRIM_DUAL_INFEAS:
1.1041 + return UNBOUNDED;//In case of dual simplex
1.1042 + //return INFEASIBLE;
1.1043 + // case CPX_OBJ_LIM:
1.1044 + // case CPX_IT_LIM_FEAS:
1.1045 + // case CPX_TIME_LIM_FEAS:
1.1046 + // case CPX_NUM_BEST_FEAS:
1.1047 + // case CPX_ABORT_FEAS:
1.1048 + // case CPX_ABORT_PRIM_DUAL_FEAS:
1.1049 + // return FEASIBLE;
1.1050 + default:
1.1051 + return UNDEFINED; //Everything else comes here
1.1052 + //FIXME error
1.1053 + }
1.1054 +#endif
1.1055 + }
1.1056 +
1.1057 + //9.0-as cplex verzio statusai
1.1058 + // CPX_STAT_ABORT_DUAL_OBJ_LIM
1.1059 + // CPX_STAT_ABORT_IT_LIM
1.1060 + // CPX_STAT_ABORT_OBJ_LIM
1.1061 + // CPX_STAT_ABORT_PRIM_OBJ_LIM
1.1062 + // CPX_STAT_ABORT_TIME_LIM
1.1063 + // CPX_STAT_ABORT_USER
1.1064 + // CPX_STAT_FEASIBLE_RELAXED
1.1065 + // CPX_STAT_INFEASIBLE
1.1066 + // CPX_STAT_INForUNBD
1.1067 + // CPX_STAT_NUM_BEST
1.1068 + // CPX_STAT_OPTIMAL
1.1069 + // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
1.1070 + // CPX_STAT_OPTIMAL_INFEAS
1.1071 + // CPX_STAT_OPTIMAL_RELAXED
1.1072 + // CPX_STAT_UNBOUNDED
1.1073 +
1.1074 + LpCplex::ProblemType LpCplex::_getDualType() const {
1.1075 + int stat = CPXgetstat(cplexEnv(), _prob);
1.1076 +#if CPX_VERSION >= 800
1.1077 + switch (stat) {
1.1078 + case CPX_STAT_OPTIMAL:
1.1079 + return OPTIMAL;
1.1080 + case CPX_STAT_UNBOUNDED:
1.1081 + return INFEASIBLE;
1.1082 + default:
1.1083 + return UNDEFINED;
1.1084 + }
1.1085 +#else
1.1086 + statusSwitch(cplexEnv(),stat);
1.1087 + switch (stat) {
1.1088 + case 0:
1.1089 + return UNDEFINED; //Undefined
1.1090 + case CPX_OPTIMAL://Optimal
1.1091 + return OPTIMAL;
1.1092 + case CPX_UNBOUNDED:
1.1093 + return INFEASIBLE;
1.1094 + default:
1.1095 + return UNDEFINED; //Everything else comes here
1.1096 + //FIXME error
1.1097 + }
1.1098 +#endif
1.1099 + }
1.1100 +
1.1101 + // MipCplex members
1.1102 +
1.1103 + MipCplex::MipCplex()
1.1104 + : LpBase(), CplexBase(), MipSolver() {
1.1105 +
1.1106 +#if CPX_VERSION < 800
1.1107 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
1.1108 +#else
1.1109 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
1.1110 +#endif
1.1111 + }
1.1112 +
1.1113 + MipCplex::MipCplex(const CplexEnv& env)
1.1114 + : LpBase(), CplexBase(env), MipSolver() {
1.1115 +
1.1116 +#if CPX_VERSION < 800
1.1117 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
1.1118 +#else
1.1119 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
1.1120 +#endif
1.1121 +
1.1122 + }
1.1123 +
1.1124 + MipCplex::MipCplex(const MipCplex& other)
1.1125 + : LpBase(), CplexBase(other), MipSolver() {}
1.1126 +
1.1127 + MipCplex::~MipCplex() {}
1.1128 +
1.1129 + MipCplex* MipCplex::_newSolver() const { return new MipCplex; }
1.1130 + MipCplex* MipCplex::_cloneSolver() const {return new MipCplex(*this); }
1.1131 +
1.1132 + const char* MipCplex::_solverName() const { return "MipCplex"; }
1.1133 +
1.1134 + void MipCplex::_setColType(int i, MipCplex::ColTypes col_type) {
1.1135 +
1.1136 + // Note If a variable is to be changed to binary, a call to CPXchgbds
1.1137 + // should also be made to change the bounds to 0 and 1.
1.1138 +
1.1139 + switch (col_type){
1.1140 + case INTEGER: {
1.1141 + const char t = 'I';
1.1142 + CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
1.1143 + } break;
1.1144 + case REAL: {
1.1145 + const char t = 'C';
1.1146 + CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
1.1147 + } break;
1.1148 + default:
1.1149 + break;
1.1150 + }
1.1151 + }
1.1152 +
1.1153 + MipCplex::ColTypes MipCplex::_getColType(int i) const {
1.1154 + char t;
1.1155 + CPXgetctype (cplexEnv(), _prob, &t, i, i);
1.1156 + switch (t) {
1.1157 + case 'I':
1.1158 + return INTEGER;
1.1159 + case 'C':
1.1160 + return REAL;
1.1161 + default:
1.1162 + LEMON_ASSERT(false, "Invalid column type");
1.1163 + return ColTypes();
1.1164 + }
1.1165 +
1.1166 + }
1.1167 +
1.1168 + MipCplex::SolveExitStatus MipCplex::_solve() {
1.1169 + int status;
1.1170 + status = CPXmipopt (cplexEnv(), _prob);
1.1171 + if (status==0)
1.1172 + return SOLVED;
1.1173 + else
1.1174 + return UNSOLVED;
1.1175 +
1.1176 + }
1.1177 +
1.1178 +
1.1179 + MipCplex::ProblemType MipCplex::_getType() const {
1.1180 +
1.1181 + int stat = CPXgetstat(cplexEnv(), _prob);
1.1182 +
1.1183 + //Fortunately, MIP statuses did not change for cplex 8.0
1.1184 + switch (stat) {
1.1185 + case CPXMIP_OPTIMAL:
1.1186 + // Optimal integer solution has been found.
1.1187 + case CPXMIP_OPTIMAL_TOL:
1.1188 + // Optimal soluton with the tolerance defined by epgap or epagap has
1.1189 + // been found.
1.1190 + return OPTIMAL;
1.1191 + //This also exists in later issues
1.1192 + // case CPXMIP_UNBOUNDED:
1.1193 + //return UNBOUNDED;
1.1194 + case CPXMIP_INFEASIBLE:
1.1195 + return INFEASIBLE;
1.1196 + default:
1.1197 + return UNDEFINED;
1.1198 + }
1.1199 //Unboundedness not treated well: the following is from cplex 9.0 doc
1.1200 // About Unboundedness
1.1201
1.1202 @@ -551,148 +907,18 @@
1.1203 // a feasible solution exists. Users can call the routine CPXsolninfo
1.1204 // to determine whether ILOG CPLEX has also concluded that the model
1.1205 // has a feasible solution.
1.1206 -
1.1207 - int stat = CPXgetstat(env, lp);
1.1208 -#if CPX_VERSION >= 800
1.1209 - switch (stat)
1.1210 - {
1.1211 - case CPX_STAT_OPTIMAL:
1.1212 - return OPTIMAL;
1.1213 - case CPX_STAT_UNBOUNDED:
1.1214 - return INFINITE;
1.1215 - case CPX_STAT_INFEASIBLE:
1.1216 - return INFEASIBLE;
1.1217 - default:
1.1218 - return UNDEFINED;
1.1219 - }
1.1220 -#else
1.1221 - statusSwitch(env,stat);
1.1222 - //CPXgetstat(env, lp);
1.1223 - //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL);
1.1224 - switch (stat) {
1.1225 - case 0:
1.1226 - return UNDEFINED; //Undefined
1.1227 - case CPX_OPTIMAL://Optimal
1.1228 - return OPTIMAL;
1.1229 - case CPX_UNBOUNDED://Unbounded
1.1230 - return INFEASIBLE;//In case of dual simplex
1.1231 - //return INFINITE;
1.1232 - case CPX_INFEASIBLE://Infeasible
1.1233 - // case CPX_IT_LIM_INFEAS:
1.1234 -// case CPX_TIME_LIM_INFEAS:
1.1235 -// case CPX_NUM_BEST_INFEAS:
1.1236 -// case CPX_OPTIMAL_INFEAS:
1.1237 -// case CPX_ABORT_INFEAS:
1.1238 -// case CPX_ABORT_PRIM_INFEAS:
1.1239 -// case CPX_ABORT_PRIM_DUAL_INFEAS:
1.1240 - return INFINITE;//In case of dual simplex
1.1241 - //return INFEASIBLE;
1.1242 -// case CPX_OBJ_LIM:
1.1243 -// case CPX_IT_LIM_FEAS:
1.1244 -// case CPX_TIME_LIM_FEAS:
1.1245 -// case CPX_NUM_BEST_FEAS:
1.1246 -// case CPX_ABORT_FEAS:
1.1247 -// case CPX_ABORT_PRIM_DUAL_FEAS:
1.1248 -// return FEASIBLE;
1.1249 - default:
1.1250 - return UNDEFINED; //Everything else comes here
1.1251 - //FIXME error
1.1252 - }
1.1253 -#endif
1.1254 }
1.1255
1.1256 -//9.0-as cplex verzio statusai
1.1257 -// CPX_STAT_ABORT_DUAL_OBJ_LIM
1.1258 -// CPX_STAT_ABORT_IT_LIM
1.1259 -// CPX_STAT_ABORT_OBJ_LIM
1.1260 -// CPX_STAT_ABORT_PRIM_OBJ_LIM
1.1261 -// CPX_STAT_ABORT_TIME_LIM
1.1262 -// CPX_STAT_ABORT_USER
1.1263 -// CPX_STAT_FEASIBLE_RELAXED
1.1264 -// CPX_STAT_INFEASIBLE
1.1265 -// CPX_STAT_INForUNBD
1.1266 -// CPX_STAT_NUM_BEST
1.1267 -// CPX_STAT_OPTIMAL
1.1268 -// CPX_STAT_OPTIMAL_FACE_UNBOUNDED
1.1269 -// CPX_STAT_OPTIMAL_INFEAS
1.1270 -// CPX_STAT_OPTIMAL_RELAXED
1.1271 -// CPX_STAT_UNBOUNDED
1.1272 -
1.1273 - LpCplex::SolutionStatus LpCplex::_getDualStatus() const
1.1274 - {
1.1275 - int stat = CPXgetstat(env, lp);
1.1276 -#if CPX_VERSION >= 800
1.1277 - switch (stat)
1.1278 - {
1.1279 - case CPX_STAT_OPTIMAL:
1.1280 - return OPTIMAL;
1.1281 - case CPX_STAT_UNBOUNDED:
1.1282 - return INFEASIBLE;
1.1283 - default:
1.1284 - return UNDEFINED;
1.1285 - }
1.1286 -#else
1.1287 - statusSwitch(env,stat);
1.1288 - switch (stat) {
1.1289 - case 0:
1.1290 - return UNDEFINED; //Undefined
1.1291 - case CPX_OPTIMAL://Optimal
1.1292 - return OPTIMAL;
1.1293 - case CPX_UNBOUNDED:
1.1294 - return INFEASIBLE;
1.1295 - default:
1.1296 - return UNDEFINED; //Everything else comes here
1.1297 - //FIXME error
1.1298 - }
1.1299 -#endif
1.1300 + MipCplex::Value MipCplex::_getSol(int i) const {
1.1301 + Value x;
1.1302 + CPXgetmipx(cplexEnv(), _prob, &x, i, i);
1.1303 + return x;
1.1304 }
1.1305
1.1306 - LpCplex::ProblemTypes LpCplex::_getProblemType() const
1.1307 - {
1.1308 - int stat = CPXgetstat(env, lp);
1.1309 -#if CPX_VERSION >= 800
1.1310 - switch (stat)
1.1311 - {
1.1312 - case CPX_STAT_OPTIMAL:
1.1313 - return PRIMAL_DUAL_FEASIBLE;
1.1314 - case CPX_STAT_UNBOUNDED:
1.1315 - return PRIMAL_FEASIBLE_DUAL_INFEASIBLE;
1.1316 - default:
1.1317 - return UNKNOWN;
1.1318 - }
1.1319 -#else
1.1320 - switch (stat) {
1.1321 - case CPX_OPTIMAL://Optimal
1.1322 - return PRIMAL_DUAL_FEASIBLE;
1.1323 - case CPX_UNBOUNDED:
1.1324 - return PRIMAL_FEASIBLE_DUAL_INFEASIBLE;
1.1325 -// return PRIMAL_INFEASIBLE_DUAL_FEASIBLE;
1.1326 -// return PRIMAL_DUAL_INFEASIBLE;
1.1327 -
1.1328 -//Seems to be that this is all we can say for sure
1.1329 - default:
1.1330 - //In all other cases
1.1331 - return UNKNOWN;
1.1332 - //FIXME error
1.1333 - }
1.1334 -#endif
1.1335 - }
1.1336 -
1.1337 - void LpCplex::_setMax()
1.1338 - {
1.1339 - CPXchgobjsen(env, lp, CPX_MAX);
1.1340 - }
1.1341 - void LpCplex::_setMin()
1.1342 - {
1.1343 - CPXchgobjsen(env, lp, CPX_MIN);
1.1344 - }
1.1345 -
1.1346 - bool LpCplex::_isMax() const
1.1347 - {
1.1348 - if (CPXgetobjsen(env, lp)==CPX_MAX)
1.1349 - return true;
1.1350 - else
1.1351 - return false;
1.1352 + MipCplex::Value MipCplex::_getSolValue() const {
1.1353 + Value objval;
1.1354 + CPXgetmipobjval(cplexEnv(), _prob, &objval);
1.1355 + return objval;
1.1356 }
1.1357
1.1358 } //namespace lemon