1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lemon/cplex.cc Thu Nov 05 15:50:01 2009 +0100
1.3 @@ -0,0 +1,984 @@
1.4 +/* -*- mode: C++; indent-tabs-mode: nil; -*-
1.5 + *
1.6 + * This file is a part of LEMON, a generic C++ optimization library.
1.7 + *
1.8 + * Copyright (C) 2003-2009
1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.11 + *
1.12 + * Permission to use, modify and distribute this software is granted
1.13 + * provided that this copyright notice appears in all copies. For
1.14 + * precise terms see the accompanying LICENSE file.
1.15 + *
1.16 + * This software is provided "AS IS" with no warranty of any kind,
1.17 + * express or implied, and with no claim as to its suitability for any
1.18 + * purpose.
1.19 + *
1.20 + */
1.21 +
1.22 +#include <iostream>
1.23 +#include <vector>
1.24 +#include <cstring>
1.25 +
1.26 +#include <lemon/cplex.h>
1.27 +
1.28 +extern "C" {
1.29 +#include <ilcplex/cplex.h>
1.30 +}
1.31 +
1.32 +
1.33 +///\file
1.34 +///\brief Implementation of the LEMON-CPLEX lp solver interface.
1.35 +namespace lemon {
1.36 +
1.37 + CplexEnv::LicenseError::LicenseError(int status) {
1.38 + if (!CPXgeterrorstring(0, status, _message)) {
1.39 + std::strcpy(_message, "Cplex unknown error");
1.40 + }
1.41 + }
1.42 +
1.43 + CplexEnv::CplexEnv() {
1.44 + int status;
1.45 + _cnt = new int;
1.46 + _env = CPXopenCPLEX(&status);
1.47 + if (_env == 0) {
1.48 + delete _cnt;
1.49 + _cnt = 0;
1.50 + throw LicenseError(status);
1.51 + }
1.52 + }
1.53 +
1.54 + CplexEnv::CplexEnv(const CplexEnv& other) {
1.55 + _env = other._env;
1.56 + _cnt = other._cnt;
1.57 + ++(*_cnt);
1.58 + }
1.59 +
1.60 + CplexEnv& CplexEnv::operator=(const CplexEnv& other) {
1.61 + _env = other._env;
1.62 + _cnt = other._cnt;
1.63 + ++(*_cnt);
1.64 + return *this;
1.65 + }
1.66 +
1.67 + CplexEnv::~CplexEnv() {
1.68 + --(*_cnt);
1.69 + if (*_cnt == 0) {
1.70 + delete _cnt;
1.71 + CPXcloseCPLEX(&_env);
1.72 + }
1.73 + }
1.74 +
1.75 + CplexBase::CplexBase() : LpBase() {
1.76 + int status;
1.77 + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
1.78 + messageLevel(MESSAGE_NOTHING);
1.79 + }
1.80 +
1.81 + CplexBase::CplexBase(const CplexEnv& env)
1.82 + : LpBase(), _env(env) {
1.83 + int status;
1.84 + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
1.85 + messageLevel(MESSAGE_NOTHING);
1.86 + }
1.87 +
1.88 + CplexBase::CplexBase(const CplexBase& cplex)
1.89 + : LpBase() {
1.90 + int status;
1.91 + _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status);
1.92 + rows = cplex.rows;
1.93 + cols = cplex.cols;
1.94 + messageLevel(MESSAGE_NOTHING);
1.95 + }
1.96 +
1.97 + CplexBase::~CplexBase() {
1.98 + CPXfreeprob(cplexEnv(),&_prob);
1.99 + }
1.100 +
1.101 + int CplexBase::_addCol() {
1.102 + int i = CPXgetnumcols(cplexEnv(), _prob);
1.103 + double lb = -INF, ub = INF;
1.104 + CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0);
1.105 + return i;
1.106 + }
1.107 +
1.108 +
1.109 + int CplexBase::_addRow() {
1.110 + int i = CPXgetnumrows(cplexEnv(), _prob);
1.111 + const double ub = INF;
1.112 + const char s = 'L';
1.113 + CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
1.114 + return i;
1.115 + }
1.116 +
1.117 + int CplexBase::_addRow(Value lb, ExprIterator b,
1.118 + ExprIterator e, Value ub) {
1.119 + int i = CPXgetnumrows(cplexEnv(), _prob);
1.120 + if (lb == -INF) {
1.121 + const char s = 'L';
1.122 + CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0);
1.123 + } else if (ub == INF) {
1.124 + const char s = 'G';
1.125 + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0);
1.126 + } else if (lb == ub){
1.127 + const char s = 'E';
1.128 + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0);
1.129 + } else {
1.130 + const char s = 'R';
1.131 + double len = ub - lb;
1.132 + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, &len, 0);
1.133 + }
1.134 +
1.135 + std::vector<int> indices;
1.136 + std::vector<int> rowlist;
1.137 + std::vector<Value> values;
1.138 +
1.139 + for(ExprIterator it=b; it!=e; ++it) {
1.140 + indices.push_back(it->first);
1.141 + values.push_back(it->second);
1.142 + rowlist.push_back(i);
1.143 + }
1.144 +
1.145 + CPXchgcoeflist(cplexEnv(), _prob, values.size(),
1.146 + &rowlist.front(), &indices.front(), &values.front());
1.147 +
1.148 + return i;
1.149 + }
1.150 +
1.151 + void CplexBase::_eraseCol(int i) {
1.152 + CPXdelcols(cplexEnv(), _prob, i, i);
1.153 + }
1.154 +
1.155 + void CplexBase::_eraseRow(int i) {
1.156 + CPXdelrows(cplexEnv(), _prob, i, i);
1.157 + }
1.158 +
1.159 + void CplexBase::_eraseColId(int i) {
1.160 + cols.eraseIndex(i);
1.161 + cols.shiftIndices(i);
1.162 + }
1.163 + void CplexBase::_eraseRowId(int i) {
1.164 + rows.eraseIndex(i);
1.165 + rows.shiftIndices(i);
1.166 + }
1.167 +
1.168 + void CplexBase::_getColName(int col, std::string &name) const {
1.169 + int size;
1.170 + CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col);
1.171 + if (size == 0) {
1.172 + name.clear();
1.173 + return;
1.174 + }
1.175 +
1.176 + size *= -1;
1.177 + std::vector<char> buf(size);
1.178 + char *cname;
1.179 + int tmp;
1.180 + CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size,
1.181 + &tmp, col, col);
1.182 + name = cname;
1.183 + }
1.184 +
1.185 + void CplexBase::_setColName(int col, const std::string &name) {
1.186 + char *cname;
1.187 + cname = const_cast<char*>(name.c_str());
1.188 + CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname);
1.189 + }
1.190 +
1.191 + int CplexBase::_colByName(const std::string& name) const {
1.192 + int index;
1.193 + if (CPXgetcolindex(cplexEnv(), _prob,
1.194 + const_cast<char*>(name.c_str()), &index) == 0) {
1.195 + return index;
1.196 + }
1.197 + return -1;
1.198 + }
1.199 +
1.200 + void CplexBase::_getRowName(int row, std::string &name) const {
1.201 + int size;
1.202 + CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row);
1.203 + if (size == 0) {
1.204 + name.clear();
1.205 + return;
1.206 + }
1.207 +
1.208 + size *= -1;
1.209 + std::vector<char> buf(size);
1.210 + char *cname;
1.211 + int tmp;
1.212 + CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size,
1.213 + &tmp, row, row);
1.214 + name = cname;
1.215 + }
1.216 +
1.217 + void CplexBase::_setRowName(int row, const std::string &name) {
1.218 + char *cname;
1.219 + cname = const_cast<char*>(name.c_str());
1.220 + CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname);
1.221 + }
1.222 +
1.223 + int CplexBase::_rowByName(const std::string& name) const {
1.224 + int index;
1.225 + if (CPXgetrowindex(cplexEnv(), _prob,
1.226 + const_cast<char*>(name.c_str()), &index) == 0) {
1.227 + return index;
1.228 + }
1.229 + return -1;
1.230 + }
1.231 +
1.232 + void CplexBase::_setRowCoeffs(int i, ExprIterator b,
1.233 + ExprIterator e)
1.234 + {
1.235 + std::vector<int> indices;
1.236 + std::vector<int> rowlist;
1.237 + std::vector<Value> values;
1.238 +
1.239 + for(ExprIterator it=b; it!=e; ++it) {
1.240 + indices.push_back(it->first);
1.241 + values.push_back(it->second);
1.242 + rowlist.push_back(i);
1.243 + }
1.244 +
1.245 + CPXchgcoeflist(cplexEnv(), _prob, values.size(),
1.246 + &rowlist.front(), &indices.front(), &values.front());
1.247 + }
1.248 +
1.249 + void CplexBase::_getRowCoeffs(int i, InsertIterator b) const {
1.250 + int tmp1, tmp2, tmp3, length;
1.251 + CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
1.252 +
1.253 + length = -length;
1.254 + std::vector<int> indices(length);
1.255 + std::vector<double> values(length);
1.256 +
1.257 + CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2,
1.258 + &indices.front(), &values.front(),
1.259 + length, &tmp3, i, i);
1.260 +
1.261 + for (int i = 0; i < length; ++i) {
1.262 + *b = std::make_pair(indices[i], values[i]);
1.263 + ++b;
1.264 + }
1.265 + }
1.266 +
1.267 + void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) {
1.268 + std::vector<int> indices;
1.269 + std::vector<int> collist;
1.270 + std::vector<Value> values;
1.271 +
1.272 + for(ExprIterator it=b; it!=e; ++it) {
1.273 + indices.push_back(it->first);
1.274 + values.push_back(it->second);
1.275 + collist.push_back(i);
1.276 + }
1.277 +
1.278 + CPXchgcoeflist(cplexEnv(), _prob, values.size(),
1.279 + &indices.front(), &collist.front(), &values.front());
1.280 + }
1.281 +
1.282 + void CplexBase::_getColCoeffs(int i, InsertIterator b) const {
1.283 +
1.284 + int tmp1, tmp2, tmp3, length;
1.285 + CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i);
1.286 +
1.287 + length = -length;
1.288 + std::vector<int> indices(length);
1.289 + std::vector<double> values(length);
1.290 +
1.291 + CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2,
1.292 + &indices.front(), &values.front(),
1.293 + length, &tmp3, i, i);
1.294 +
1.295 + for (int i = 0; i < length; ++i) {
1.296 + *b = std::make_pair(indices[i], values[i]);
1.297 + ++b;
1.298 + }
1.299 +
1.300 + }
1.301 +
1.302 + void CplexBase::_setCoeff(int row, int col, Value value) {
1.303 + CPXchgcoef(cplexEnv(), _prob, row, col, value);
1.304 + }
1.305 +
1.306 + CplexBase::Value CplexBase::_getCoeff(int row, int col) const {
1.307 + CplexBase::Value value;
1.308 + CPXgetcoef(cplexEnv(), _prob, row, col, &value);
1.309 + return value;
1.310 + }
1.311 +
1.312 + void CplexBase::_setColLowerBound(int i, Value value) {
1.313 + const char s = 'L';
1.314 + CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
1.315 + }
1.316 +
1.317 + CplexBase::Value CplexBase::_getColLowerBound(int i) const {
1.318 + CplexBase::Value res;
1.319 + CPXgetlb(cplexEnv(), _prob, &res, i, i);
1.320 + return res <= -CPX_INFBOUND ? -INF : res;
1.321 + }
1.322 +
1.323 + void CplexBase::_setColUpperBound(int i, Value value)
1.324 + {
1.325 + const char s = 'U';
1.326 + CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value);
1.327 + }
1.328 +
1.329 + CplexBase::Value CplexBase::_getColUpperBound(int i) const {
1.330 + CplexBase::Value res;
1.331 + CPXgetub(cplexEnv(), _prob, &res, i, i);
1.332 + return res >= CPX_INFBOUND ? INF : res;
1.333 + }
1.334 +
1.335 + CplexBase::Value CplexBase::_getRowLowerBound(int i) const {
1.336 + char s;
1.337 + CPXgetsense(cplexEnv(), _prob, &s, i, i);
1.338 + CplexBase::Value res;
1.339 +
1.340 + switch (s) {
1.341 + case 'G':
1.342 + case 'R':
1.343 + case 'E':
1.344 + CPXgetrhs(cplexEnv(), _prob, &res, i, i);
1.345 + return res <= -CPX_INFBOUND ? -INF : res;
1.346 + default:
1.347 + return -INF;
1.348 + }
1.349 + }
1.350 +
1.351 + CplexBase::Value CplexBase::_getRowUpperBound(int i) const {
1.352 + char s;
1.353 + CPXgetsense(cplexEnv(), _prob, &s, i, i);
1.354 + CplexBase::Value res;
1.355 +
1.356 + switch (s) {
1.357 + case 'L':
1.358 + case 'E':
1.359 + CPXgetrhs(cplexEnv(), _prob, &res, i, i);
1.360 + return res >= CPX_INFBOUND ? INF : res;
1.361 + case 'R':
1.362 + CPXgetrhs(cplexEnv(), _prob, &res, i, i);
1.363 + {
1.364 + double rng;
1.365 + CPXgetrngval(cplexEnv(), _prob, &rng, i, i);
1.366 + res += rng;
1.367 + }
1.368 + return res >= CPX_INFBOUND ? INF : res;
1.369 + default:
1.370 + return INF;
1.371 + }
1.372 + }
1.373 +
1.374 + //This is easier to implement
1.375 + void CplexBase::_set_row_bounds(int i, Value lb, Value ub) {
1.376 + if (lb == -INF) {
1.377 + const char s = 'L';
1.378 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.379 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub);
1.380 + } else if (ub == INF) {
1.381 + const char s = 'G';
1.382 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.383 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
1.384 + } else if (lb == ub){
1.385 + const char s = 'E';
1.386 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.387 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
1.388 + } else {
1.389 + const char s = 'R';
1.390 + CPXchgsense(cplexEnv(), _prob, 1, &i, &s);
1.391 + CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb);
1.392 + double len = ub - lb;
1.393 + CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
1.394 + }
1.395 + }
1.396 +
1.397 + void CplexBase::_setRowLowerBound(int i, Value lb)
1.398 + {
1.399 + LEMON_ASSERT(lb != INF, "Invalid bound");
1.400 + _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i));
1.401 + }
1.402 +
1.403 + void CplexBase::_setRowUpperBound(int i, Value ub)
1.404 + {
1.405 +
1.406 + LEMON_ASSERT(ub != -INF, "Invalid bound");
1.407 + _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub);
1.408 + }
1.409 +
1.410 + void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e)
1.411 + {
1.412 + std::vector<int> indices;
1.413 + std::vector<Value> values;
1.414 + for(ExprIterator it=b; it!=e; ++it) {
1.415 + indices.push_back(it->first);
1.416 + values.push_back(it->second);
1.417 + }
1.418 + CPXchgobj(cplexEnv(), _prob, values.size(),
1.419 + &indices.front(), &values.front());
1.420 +
1.421 + }
1.422 +
1.423 + void CplexBase::_getObjCoeffs(InsertIterator b) const
1.424 + {
1.425 + int num = CPXgetnumcols(cplexEnv(), _prob);
1.426 + std::vector<Value> x(num);
1.427 +
1.428 + CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1);
1.429 + for (int i = 0; i < num; ++i) {
1.430 + if (x[i] != 0.0) {
1.431 + *b = std::make_pair(i, x[i]);
1.432 + ++b;
1.433 + }
1.434 + }
1.435 + }
1.436 +
1.437 + void CplexBase::_setObjCoeff(int i, Value obj_coef)
1.438 + {
1.439 + CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef);
1.440 + }
1.441 +
1.442 + CplexBase::Value CplexBase::_getObjCoeff(int i) const
1.443 + {
1.444 + Value x;
1.445 + CPXgetobj(cplexEnv(), _prob, &x, i, i);
1.446 + return x;
1.447 + }
1.448 +
1.449 + void CplexBase::_setSense(CplexBase::Sense sense) {
1.450 + switch (sense) {
1.451 + case MIN:
1.452 + CPXchgobjsen(cplexEnv(), _prob, CPX_MIN);
1.453 + break;
1.454 + case MAX:
1.455 + CPXchgobjsen(cplexEnv(), _prob, CPX_MAX);
1.456 + break;
1.457 + }
1.458 + }
1.459 +
1.460 + CplexBase::Sense CplexBase::_getSense() const {
1.461 + switch (CPXgetobjsen(cplexEnv(), _prob)) {
1.462 + case CPX_MIN:
1.463 + return MIN;
1.464 + case CPX_MAX:
1.465 + return MAX;
1.466 + default:
1.467 + LEMON_ASSERT(false, "Invalid sense");
1.468 + return CplexBase::Sense();
1.469 + }
1.470 + }
1.471 +
1.472 + void CplexBase::_clear() {
1.473 + CPXfreeprob(cplexEnv(),&_prob);
1.474 + int status;
1.475 + _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem");
1.476 + rows.clear();
1.477 + cols.clear();
1.478 + }
1.479 +
1.480 + void CplexBase::_messageLevel(MessageLevel level) {
1.481 + switch (level) {
1.482 + case MESSAGE_NOTHING:
1.483 + _message_enabled = false;
1.484 + break;
1.485 + case MESSAGE_ERROR:
1.486 + case MESSAGE_WARNING:
1.487 + case MESSAGE_NORMAL:
1.488 + case MESSAGE_VERBOSE:
1.489 + _message_enabled = true;
1.490 + break;
1.491 + }
1.492 + }
1.493 +
1.494 + void CplexBase::_applyMessageLevel() {
1.495 + CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND,
1.496 + _message_enabled ? CPX_ON : CPX_OFF);
1.497 + }
1.498 +
1.499 + // CplexLp members
1.500 +
1.501 + CplexLp::CplexLp()
1.502 + : LpBase(), LpSolver(), CplexBase() {}
1.503 +
1.504 + CplexLp::CplexLp(const CplexEnv& env)
1.505 + : LpBase(), LpSolver(), CplexBase(env) {}
1.506 +
1.507 + CplexLp::CplexLp(const CplexLp& other)
1.508 + : LpBase(), LpSolver(), CplexBase(other) {}
1.509 +
1.510 + CplexLp::~CplexLp() {}
1.511 +
1.512 + CplexLp* CplexLp::newSolver() const { return new CplexLp; }
1.513 + CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
1.514 +
1.515 + const char* CplexLp::_solverName() const { return "CplexLp"; }
1.516 +
1.517 + void CplexLp::_clear_temporals() {
1.518 + _col_status.clear();
1.519 + _row_status.clear();
1.520 + _primal_ray.clear();
1.521 + _dual_ray.clear();
1.522 + }
1.523 +
1.524 + // The routine returns zero unless an error occurred during the
1.525 + // optimization. Examples of errors include exhausting available
1.526 + // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
1.527 + // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
1.528 + // user-specified CPLEX limit, or proving the model infeasible or
1.529 + // unbounded, are not considered errors. Note that a zero return
1.530 + // value does not necessarily mean that a solution exists. Use query
1.531 + // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
1.532 + // further information about the status of the optimization.
1.533 + CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
1.534 +#if CPX_VERSION >= 800
1.535 + if (status == 0) {
1.536 + switch (CPXgetstat(cplexEnv(), _prob)) {
1.537 + case CPX_STAT_OPTIMAL:
1.538 + case CPX_STAT_INFEASIBLE:
1.539 + case CPX_STAT_UNBOUNDED:
1.540 + return SOLVED;
1.541 + default:
1.542 + return UNSOLVED;
1.543 + }
1.544 + } else {
1.545 + return UNSOLVED;
1.546 + }
1.547 +#else
1.548 + if (status == 0) {
1.549 + //We want to exclude some cases
1.550 + switch (CPXgetstat(cplexEnv(), _prob)) {
1.551 + case CPX_OBJ_LIM:
1.552 + case CPX_IT_LIM_FEAS:
1.553 + case CPX_IT_LIM_INFEAS:
1.554 + case CPX_TIME_LIM_FEAS:
1.555 + case CPX_TIME_LIM_INFEAS:
1.556 + return UNSOLVED;
1.557 + default:
1.558 + return SOLVED;
1.559 + }
1.560 + } else {
1.561 + return UNSOLVED;
1.562 + }
1.563 +#endif
1.564 + }
1.565 +
1.566 + CplexLp::SolveExitStatus CplexLp::_solve() {
1.567 + _clear_temporals();
1.568 + _applyMessageLevel();
1.569 + return convertStatus(CPXlpopt(cplexEnv(), _prob));
1.570 + }
1.571 +
1.572 + CplexLp::SolveExitStatus CplexLp::solvePrimal() {
1.573 + _clear_temporals();
1.574 + _applyMessageLevel();
1.575 + return convertStatus(CPXprimopt(cplexEnv(), _prob));
1.576 + }
1.577 +
1.578 + CplexLp::SolveExitStatus CplexLp::solveDual() {
1.579 + _clear_temporals();
1.580 + _applyMessageLevel();
1.581 + return convertStatus(CPXdualopt(cplexEnv(), _prob));
1.582 + }
1.583 +
1.584 + CplexLp::SolveExitStatus CplexLp::solveBarrier() {
1.585 + _clear_temporals();
1.586 + _applyMessageLevel();
1.587 + return convertStatus(CPXbaropt(cplexEnv(), _prob));
1.588 + }
1.589 +
1.590 + CplexLp::Value CplexLp::_getPrimal(int i) const {
1.591 + Value x;
1.592 + CPXgetx(cplexEnv(), _prob, &x, i, i);
1.593 + return x;
1.594 + }
1.595 +
1.596 + CplexLp::Value CplexLp::_getDual(int i) const {
1.597 + Value y;
1.598 + CPXgetpi(cplexEnv(), _prob, &y, i, i);
1.599 + return y;
1.600 + }
1.601 +
1.602 + CplexLp::Value CplexLp::_getPrimalValue() const {
1.603 + Value objval;
1.604 + CPXgetobjval(cplexEnv(), _prob, &objval);
1.605 + return objval;
1.606 + }
1.607 +
1.608 + CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
1.609 + if (_col_status.empty()) {
1.610 + _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
1.611 + CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
1.612 + }
1.613 + switch (_col_status[i]) {
1.614 + case CPX_BASIC:
1.615 + return BASIC;
1.616 + case CPX_FREE_SUPER:
1.617 + return FREE;
1.618 + case CPX_AT_LOWER:
1.619 + return LOWER;
1.620 + case CPX_AT_UPPER:
1.621 + return UPPER;
1.622 + default:
1.623 + LEMON_ASSERT(false, "Wrong column status");
1.624 + return CplexLp::VarStatus();
1.625 + }
1.626 + }
1.627 +
1.628 + CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
1.629 + if (_row_status.empty()) {
1.630 + _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
1.631 + CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
1.632 + }
1.633 + switch (_row_status[i]) {
1.634 + case CPX_BASIC:
1.635 + return BASIC;
1.636 + case CPX_AT_LOWER:
1.637 + {
1.638 + char s;
1.639 + CPXgetsense(cplexEnv(), _prob, &s, i, i);
1.640 + return s != 'L' ? LOWER : UPPER;
1.641 + }
1.642 + case CPX_AT_UPPER:
1.643 + return UPPER;
1.644 + default:
1.645 + LEMON_ASSERT(false, "Wrong row status");
1.646 + return CplexLp::VarStatus();
1.647 + }
1.648 + }
1.649 +
1.650 + CplexLp::Value CplexLp::_getPrimalRay(int i) const {
1.651 + if (_primal_ray.empty()) {
1.652 + _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
1.653 + CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
1.654 + }
1.655 + return _primal_ray[i];
1.656 + }
1.657 +
1.658 + CplexLp::Value CplexLp::_getDualRay(int i) const {
1.659 + if (_dual_ray.empty()) {
1.660 +
1.661 + }
1.662 + return _dual_ray[i];
1.663 + }
1.664 +
1.665 + // Cplex 7.0 status values
1.666 + // This table lists the statuses, returned by the CPXgetstat()
1.667 + // routine, for solutions to LP problems or mixed integer problems. If
1.668 + // no solution exists, the return value is zero.
1.669 +
1.670 + // For Simplex, Barrier
1.671 + // 1 CPX_OPTIMAL
1.672 + // Optimal solution found
1.673 + // 2 CPX_INFEASIBLE
1.674 + // Problem infeasible
1.675 + // 3 CPX_UNBOUNDED
1.676 + // Problem unbounded
1.677 + // 4 CPX_OBJ_LIM
1.678 + // Objective limit exceeded in Phase II
1.679 + // 5 CPX_IT_LIM_FEAS
1.680 + // Iteration limit exceeded in Phase II
1.681 + // 6 CPX_IT_LIM_INFEAS
1.682 + // Iteration limit exceeded in Phase I
1.683 + // 7 CPX_TIME_LIM_FEAS
1.684 + // Time limit exceeded in Phase II
1.685 + // 8 CPX_TIME_LIM_INFEAS
1.686 + // Time limit exceeded in Phase I
1.687 + // 9 CPX_NUM_BEST_FEAS
1.688 + // Problem non-optimal, singularities in Phase II
1.689 + // 10 CPX_NUM_BEST_INFEAS
1.690 + // Problem non-optimal, singularities in Phase I
1.691 + // 11 CPX_OPTIMAL_INFEAS
1.692 + // Optimal solution found, unscaled infeasibilities
1.693 + // 12 CPX_ABORT_FEAS
1.694 + // Aborted in Phase II
1.695 + // 13 CPX_ABORT_INFEAS
1.696 + // Aborted in Phase I
1.697 + // 14 CPX_ABORT_DUAL_INFEAS
1.698 + // Aborted in barrier, dual infeasible
1.699 + // 15 CPX_ABORT_PRIM_INFEAS
1.700 + // Aborted in barrier, primal infeasible
1.701 + // 16 CPX_ABORT_PRIM_DUAL_INFEAS
1.702 + // Aborted in barrier, primal and dual infeasible
1.703 + // 17 CPX_ABORT_PRIM_DUAL_FEAS
1.704 + // Aborted in barrier, primal and dual feasible
1.705 + // 18 CPX_ABORT_CROSSOVER
1.706 + // Aborted in crossover
1.707 + // 19 CPX_INForUNBD
1.708 + // Infeasible or unbounded
1.709 + // 20 CPX_PIVOT
1.710 + // User pivot used
1.711 + //
1.712 + // Pending return values
1.713 + // ??case CPX_ABORT_DUAL_INFEAS
1.714 + // ??case CPX_ABORT_CROSSOVER
1.715 + // ??case CPX_INForUNBD
1.716 + // ??case CPX_PIVOT
1.717 +
1.718 + //Some more interesting stuff:
1.719 +
1.720 + // CPX_PARAM_PROBMETHOD 1062 int LPMETHOD
1.721 + // 0 Automatic
1.722 + // 1 Primal Simplex
1.723 + // 2 Dual Simplex
1.724 + // 3 Network Simplex
1.725 + // 4 Standard Barrier
1.726 + // Default: 0
1.727 + // Description: Method for linear optimization.
1.728 + // Determines which algorithm is used when CPXlpopt() (or "optimize"
1.729 + // in the Interactive Optimizer) is called. Currently the behavior of
1.730 + // the "Automatic" setting is that CPLEX simply invokes the dual
1.731 + // simplex method, but this capability may be expanded in the future
1.732 + // so that CPLEX chooses the method based on problem characteristics
1.733 +#if CPX_VERSION < 900
1.734 + void statusSwitch(CPXENVptr cplexEnv(),int& stat){
1.735 + int lpmethod;
1.736 + CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
1.737 + if (lpmethod==2){
1.738 + if (stat==CPX_UNBOUNDED){
1.739 + stat=CPX_INFEASIBLE;
1.740 + }
1.741 + else{
1.742 + if (stat==CPX_INFEASIBLE)
1.743 + stat=CPX_UNBOUNDED;
1.744 + }
1.745 + }
1.746 + }
1.747 +#else
1.748 + void statusSwitch(CPXENVptr,int&){}
1.749 +#endif
1.750 +
1.751 + CplexLp::ProblemType CplexLp::_getPrimalType() const {
1.752 + // Unboundedness not treated well: the following is from cplex 9.0 doc
1.753 + // About Unboundedness
1.754 +
1.755 + // The treatment of models that are unbounded involves a few
1.756 + // subtleties. Specifically, a declaration of unboundedness means that
1.757 + // ILOG CPLEX has determined that the model has an unbounded
1.758 + // ray. Given any feasible solution x with objective z, a multiple of
1.759 + // the unbounded ray can be added to x to give a feasible solution
1.760 + // with objective z-1 (or z+1 for maximization models). Thus, if a
1.761 + // feasible solution exists, then the optimal objective is
1.762 + // unbounded. Note that ILOG CPLEX has not necessarily concluded that
1.763 + // a feasible solution exists. Users can call the routine CPXsolninfo
1.764 + // to determine whether ILOG CPLEX has also concluded that the model
1.765 + // has a feasible solution.
1.766 +
1.767 + int stat = CPXgetstat(cplexEnv(), _prob);
1.768 +#if CPX_VERSION >= 800
1.769 + switch (stat)
1.770 + {
1.771 + case CPX_STAT_OPTIMAL:
1.772 + return OPTIMAL;
1.773 + case CPX_STAT_UNBOUNDED:
1.774 + return UNBOUNDED;
1.775 + case CPX_STAT_INFEASIBLE:
1.776 + return INFEASIBLE;
1.777 + default:
1.778 + return UNDEFINED;
1.779 + }
1.780 +#else
1.781 + statusSwitch(cplexEnv(),stat);
1.782 + //CPXgetstat(cplexEnv(), _prob);
1.783 + switch (stat) {
1.784 + case 0:
1.785 + return UNDEFINED; //Undefined
1.786 + case CPX_OPTIMAL://Optimal
1.787 + return OPTIMAL;
1.788 + case CPX_UNBOUNDED://Unbounded
1.789 + return INFEASIBLE;//In case of dual simplex
1.790 + //return UNBOUNDED;
1.791 + case CPX_INFEASIBLE://Infeasible
1.792 + // case CPX_IT_LIM_INFEAS:
1.793 + // case CPX_TIME_LIM_INFEAS:
1.794 + // case CPX_NUM_BEST_INFEAS:
1.795 + // case CPX_OPTIMAL_INFEAS:
1.796 + // case CPX_ABORT_INFEAS:
1.797 + // case CPX_ABORT_PRIM_INFEAS:
1.798 + // case CPX_ABORT_PRIM_DUAL_INFEAS:
1.799 + return UNBOUNDED;//In case of dual simplex
1.800 + //return INFEASIBLE;
1.801 + // case CPX_OBJ_LIM:
1.802 + // case CPX_IT_LIM_FEAS:
1.803 + // case CPX_TIME_LIM_FEAS:
1.804 + // case CPX_NUM_BEST_FEAS:
1.805 + // case CPX_ABORT_FEAS:
1.806 + // case CPX_ABORT_PRIM_DUAL_FEAS:
1.807 + // return FEASIBLE;
1.808 + default:
1.809 + return UNDEFINED; //Everything else comes here
1.810 + //FIXME error
1.811 + }
1.812 +#endif
1.813 + }
1.814 +
1.815 + // Cplex 9.0 status values
1.816 + // CPX_STAT_ABORT_DUAL_OBJ_LIM
1.817 + // CPX_STAT_ABORT_IT_LIM
1.818 + // CPX_STAT_ABORT_OBJ_LIM
1.819 + // CPX_STAT_ABORT_PRIM_OBJ_LIM
1.820 + // CPX_STAT_ABORT_TIME_LIM
1.821 + // CPX_STAT_ABORT_USER
1.822 + // CPX_STAT_FEASIBLE_RELAXED
1.823 + // CPX_STAT_INFEASIBLE
1.824 + // CPX_STAT_INForUNBD
1.825 + // CPX_STAT_NUM_BEST
1.826 + // CPX_STAT_OPTIMAL
1.827 + // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
1.828 + // CPX_STAT_OPTIMAL_INFEAS
1.829 + // CPX_STAT_OPTIMAL_RELAXED
1.830 + // CPX_STAT_UNBOUNDED
1.831 +
1.832 + CplexLp::ProblemType CplexLp::_getDualType() const {
1.833 + int stat = CPXgetstat(cplexEnv(), _prob);
1.834 +#if CPX_VERSION >= 800
1.835 + switch (stat) {
1.836 + case CPX_STAT_OPTIMAL:
1.837 + return OPTIMAL;
1.838 + case CPX_STAT_UNBOUNDED:
1.839 + return INFEASIBLE;
1.840 + default:
1.841 + return UNDEFINED;
1.842 + }
1.843 +#else
1.844 + statusSwitch(cplexEnv(),stat);
1.845 + switch (stat) {
1.846 + case 0:
1.847 + return UNDEFINED; //Undefined
1.848 + case CPX_OPTIMAL://Optimal
1.849 + return OPTIMAL;
1.850 + case CPX_UNBOUNDED:
1.851 + return INFEASIBLE;
1.852 + default:
1.853 + return UNDEFINED; //Everything else comes here
1.854 + //FIXME error
1.855 + }
1.856 +#endif
1.857 + }
1.858 +
1.859 + // CplexMip members
1.860 +
1.861 + CplexMip::CplexMip()
1.862 + : LpBase(), MipSolver(), CplexBase() {
1.863 +
1.864 +#if CPX_VERSION < 800
1.865 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
1.866 +#else
1.867 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
1.868 +#endif
1.869 + }
1.870 +
1.871 + CplexMip::CplexMip(const CplexEnv& env)
1.872 + : LpBase(), MipSolver(), CplexBase(env) {
1.873 +
1.874 +#if CPX_VERSION < 800
1.875 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP);
1.876 +#else
1.877 + CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP);
1.878 +#endif
1.879 +
1.880 + }
1.881 +
1.882 + CplexMip::CplexMip(const CplexMip& other)
1.883 + : LpBase(), MipSolver(), CplexBase(other) {}
1.884 +
1.885 + CplexMip::~CplexMip() {}
1.886 +
1.887 + CplexMip* CplexMip::newSolver() const { return new CplexMip; }
1.888 + CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
1.889 +
1.890 + const char* CplexMip::_solverName() const { return "CplexMip"; }
1.891 +
1.892 + void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
1.893 +
1.894 + // Note If a variable is to be changed to binary, a call to CPXchgbds
1.895 + // should also be made to change the bounds to 0 and 1.
1.896 +
1.897 + switch (col_type){
1.898 + case INTEGER: {
1.899 + const char t = 'I';
1.900 + CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
1.901 + } break;
1.902 + case REAL: {
1.903 + const char t = 'C';
1.904 + CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
1.905 + } break;
1.906 + default:
1.907 + break;
1.908 + }
1.909 + }
1.910 +
1.911 + CplexMip::ColTypes CplexMip::_getColType(int i) const {
1.912 + char t;
1.913 + CPXgetctype (cplexEnv(), _prob, &t, i, i);
1.914 + switch (t) {
1.915 + case 'I':
1.916 + return INTEGER;
1.917 + case 'C':
1.918 + return REAL;
1.919 + default:
1.920 + LEMON_ASSERT(false, "Invalid column type");
1.921 + return ColTypes();
1.922 + }
1.923 +
1.924 + }
1.925 +
1.926 + CplexMip::SolveExitStatus CplexMip::_solve() {
1.927 + int status;
1.928 + _applyMessageLevel();
1.929 + status = CPXmipopt (cplexEnv(), _prob);
1.930 + if (status==0)
1.931 + return SOLVED;
1.932 + else
1.933 + return UNSOLVED;
1.934 +
1.935 + }
1.936 +
1.937 +
1.938 + CplexMip::ProblemType CplexMip::_getType() const {
1.939 +
1.940 + int stat = CPXgetstat(cplexEnv(), _prob);
1.941 +
1.942 + //Fortunately, MIP statuses did not change for cplex 8.0
1.943 + switch (stat) {
1.944 + case CPXMIP_OPTIMAL:
1.945 + // Optimal integer solution has been found.
1.946 + case CPXMIP_OPTIMAL_TOL:
1.947 + // Optimal soluton with the tolerance defined by epgap or epagap has
1.948 + // been found.
1.949 + return OPTIMAL;
1.950 + //This also exists in later issues
1.951 + // case CPXMIP_UNBOUNDED:
1.952 + //return UNBOUNDED;
1.953 + case CPXMIP_INFEASIBLE:
1.954 + return INFEASIBLE;
1.955 + default:
1.956 + return UNDEFINED;
1.957 + }
1.958 + //Unboundedness not treated well: the following is from cplex 9.0 doc
1.959 + // About Unboundedness
1.960 +
1.961 + // The treatment of models that are unbounded involves a few
1.962 + // subtleties. Specifically, a declaration of unboundedness means that
1.963 + // ILOG CPLEX has determined that the model has an unbounded
1.964 + // ray. Given any feasible solution x with objective z, a multiple of
1.965 + // the unbounded ray can be added to x to give a feasible solution
1.966 + // with objective z-1 (or z+1 for maximization models). Thus, if a
1.967 + // feasible solution exists, then the optimal objective is
1.968 + // unbounded. Note that ILOG CPLEX has not necessarily concluded that
1.969 + // a feasible solution exists. Users can call the routine CPXsolninfo
1.970 + // to determine whether ILOG CPLEX has also concluded that the model
1.971 + // has a feasible solution.
1.972 + }
1.973 +
1.974 + CplexMip::Value CplexMip::_getSol(int i) const {
1.975 + Value x;
1.976 + CPXgetmipx(cplexEnv(), _prob, &x, i, i);
1.977 + return x;
1.978 + }
1.979 +
1.980 + CplexMip::Value CplexMip::_getSolValue() const {
1.981 + Value objval;
1.982 + CPXgetmipobjval(cplexEnv(), _prob, &objval);
1.983 + return objval;
1.984 + }
1.985 +
1.986 +} //namespace lemon
1.987 +