COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 1336:0759d974de81

Last change on this file since 1336:0759d974de81 was 1336:0759d974de81, checked in by Gabor Gevay <ggab90@…>, 6 years ago

STL style iterators (#325)

For

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