COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 1181:d32e4453b48c

Last change on this file since 1181:d32e4453b48c was 1181:d32e4453b48c, checked in by Alpar Juttner <alpar@…>, 12 years ago

Fix missing initialization in CplexEnv::CplexEnv?() (#445)

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