COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 1141:c3a7ca108705

1.1
Last change on this file since 1141:c3a7ca108705 was 1141:c3a7ca108705, checked in by Alpar Juttner <alpar@…>, 8 years ago

Merge bugfix #441 to branch 1.1

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