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