COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 810:93cd93e82f9b

Last change on this file since 810:93cd93e82f9b was 623:745e182d0139, checked in by Balazs Dezso <deba@…>, 16 years ago

Unified message handling for LP and MIP solvers (#9)

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    _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    rows.clear();
441    cols.clear();
442  }
443
444  void CplexBase::_messageLevel(MessageLevel level) {
445    switch (level) {
446    case MESSAGE_NOTHING:
447      _message_enabled = false;
448      break;
449    case MESSAGE_ERROR:
450    case MESSAGE_WARNING:
451    case MESSAGE_NORMAL:
452    case MESSAGE_VERBOSE:
453      _message_enabled = true;
454      break;
455    }
456  }
457
458  void CplexBase::_applyMessageLevel() {
459    CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND,
460                   _message_enabled ? CPX_ON : CPX_OFF);
461  }
462
463  // CplexLp members
464
465  CplexLp::CplexLp()
466    : LpBase(), LpSolver(), CplexBase() {}
467
468  CplexLp::CplexLp(const CplexEnv& env)
469    : LpBase(), LpSolver(), CplexBase(env) {}
470
471  CplexLp::CplexLp(const CplexLp& other)
472    : LpBase(), LpSolver(), CplexBase(other) {}
473
474  CplexLp::~CplexLp() {}
475
476  CplexLp* CplexLp::newSolver() const { return new CplexLp; }
477  CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); }
478
479  const char* CplexLp::_solverName() const { return "CplexLp"; }
480
481  void CplexLp::_clear_temporals() {
482    _col_status.clear();
483    _row_status.clear();
484    _primal_ray.clear();
485    _dual_ray.clear();
486  }
487
488  // The routine returns zero unless an error occurred during the
489  // optimization. Examples of errors include exhausting available
490  // memory (CPXERR_NO_MEMORY) or encountering invalid data in the
491  // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a
492  // user-specified CPLEX limit, or proving the model infeasible or
493  // unbounded, are not considered errors. Note that a zero return
494  // value does not necessarily mean that a solution exists. Use query
495  // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain
496  // further information about the status of the optimization.
497  CplexLp::SolveExitStatus CplexLp::convertStatus(int status) {
498#if CPX_VERSION >= 800
499    if (status == 0) {
500      switch (CPXgetstat(cplexEnv(), _prob)) {
501      case CPX_STAT_OPTIMAL:
502      case CPX_STAT_INFEASIBLE:
503      case CPX_STAT_UNBOUNDED:
504        return SOLVED;
505      default:
506        return UNSOLVED;
507      }
508    } else {
509      return UNSOLVED;
510    }
511#else
512    if (status == 0) {
513      //We want to exclude some cases
514      switch (CPXgetstat(cplexEnv(), _prob)) {
515      case CPX_OBJ_LIM:
516      case CPX_IT_LIM_FEAS:
517      case CPX_IT_LIM_INFEAS:
518      case CPX_TIME_LIM_FEAS:
519      case CPX_TIME_LIM_INFEAS:
520        return UNSOLVED;
521      default:
522        return SOLVED;
523      }
524    } else {
525      return UNSOLVED;
526    }
527#endif
528  }
529
530  CplexLp::SolveExitStatus CplexLp::_solve() {
531    _clear_temporals();
532    _applyMessageLevel();
533    return convertStatus(CPXlpopt(cplexEnv(), _prob));
534  }
535
536  CplexLp::SolveExitStatus CplexLp::solvePrimal() {
537    _clear_temporals();
538    _applyMessageLevel();
539    return convertStatus(CPXprimopt(cplexEnv(), _prob));
540  }
541
542  CplexLp::SolveExitStatus CplexLp::solveDual() {
543    _clear_temporals();
544    _applyMessageLevel();
545    return convertStatus(CPXdualopt(cplexEnv(), _prob));
546  }
547
548  CplexLp::SolveExitStatus CplexLp::solveBarrier() {
549    _clear_temporals();
550    _applyMessageLevel();
551    return convertStatus(CPXbaropt(cplexEnv(), _prob));
552  }
553
554  CplexLp::Value CplexLp::_getPrimal(int i) const {
555    Value x;
556    CPXgetx(cplexEnv(), _prob, &x, i, i);
557    return x;
558  }
559
560  CplexLp::Value CplexLp::_getDual(int i) const {
561    Value y;
562    CPXgetpi(cplexEnv(), _prob, &y, i, i);
563    return y;
564  }
565
566  CplexLp::Value CplexLp::_getPrimalValue() const {
567    Value objval;
568    CPXgetobjval(cplexEnv(), _prob, &objval);
569    return objval;
570  }
571
572  CplexLp::VarStatus CplexLp::_getColStatus(int i) const {
573    if (_col_status.empty()) {
574      _col_status.resize(CPXgetnumcols(cplexEnv(), _prob));
575      CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0);
576    }
577    switch (_col_status[i]) {
578    case CPX_BASIC:
579      return BASIC;
580    case CPX_FREE_SUPER:
581      return FREE;
582    case CPX_AT_LOWER:
583      return LOWER;
584    case CPX_AT_UPPER:
585      return UPPER;
586    default:
587      LEMON_ASSERT(false, "Wrong column status");
588      return CplexLp::VarStatus();
589    }
590  }
591
592  CplexLp::VarStatus CplexLp::_getRowStatus(int i) const {
593    if (_row_status.empty()) {
594      _row_status.resize(CPXgetnumrows(cplexEnv(), _prob));
595      CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front());
596    }
597    switch (_row_status[i]) {
598    case CPX_BASIC:
599      return BASIC;
600    case CPX_AT_LOWER:
601      {
602        char s;
603        CPXgetsense(cplexEnv(), _prob, &s, i, i);
604        return s != 'L' ? LOWER : UPPER;
605      }
606    case CPX_AT_UPPER:
607      return UPPER;
608    default:
609      LEMON_ASSERT(false, "Wrong row status");
610      return CplexLp::VarStatus();
611    }
612  }
613
614  CplexLp::Value CplexLp::_getPrimalRay(int i) const {
615    if (_primal_ray.empty()) {
616      _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob));
617      CPXgetray(cplexEnv(), _prob, &_primal_ray.front());
618    }
619    return _primal_ray[i];
620  }
621
622  CplexLp::Value CplexLp::_getDualRay(int i) const {
623    if (_dual_ray.empty()) {
624
625    }
626    return _dual_ray[i];
627  }
628
629  // Cplex 7.0 status values
630  // This table lists the statuses, returned by the CPXgetstat()
631  // routine, for solutions to LP problems or mixed integer problems. If
632  // no solution exists, the return value is zero.
633
634  // For Simplex, Barrier
635  // 1          CPX_OPTIMAL
636  //          Optimal solution found
637  // 2          CPX_INFEASIBLE
638  //          Problem infeasible
639  // 3    CPX_UNBOUNDED
640  //          Problem unbounded
641  // 4          CPX_OBJ_LIM
642  //          Objective limit exceeded in Phase II
643  // 5          CPX_IT_LIM_FEAS
644  //          Iteration limit exceeded in Phase II
645  // 6          CPX_IT_LIM_INFEAS
646  //          Iteration limit exceeded in Phase I
647  // 7          CPX_TIME_LIM_FEAS
648  //          Time limit exceeded in Phase II
649  // 8          CPX_TIME_LIM_INFEAS
650  //          Time limit exceeded in Phase I
651  // 9          CPX_NUM_BEST_FEAS
652  //          Problem non-optimal, singularities in Phase II
653  // 10         CPX_NUM_BEST_INFEAS
654  //          Problem non-optimal, singularities in Phase I
655  // 11         CPX_OPTIMAL_INFEAS
656  //          Optimal solution found, unscaled infeasibilities
657  // 12         CPX_ABORT_FEAS
658  //          Aborted in Phase II
659  // 13         CPX_ABORT_INFEAS
660  //          Aborted in Phase I
661  // 14          CPX_ABORT_DUAL_INFEAS
662  //          Aborted in barrier, dual infeasible
663  // 15          CPX_ABORT_PRIM_INFEAS
664  //          Aborted in barrier, primal infeasible
665  // 16          CPX_ABORT_PRIM_DUAL_INFEAS
666  //          Aborted in barrier, primal and dual infeasible
667  // 17          CPX_ABORT_PRIM_DUAL_FEAS
668  //          Aborted in barrier, primal and dual feasible
669  // 18          CPX_ABORT_CROSSOVER
670  //          Aborted in crossover
671  // 19          CPX_INForUNBD
672  //          Infeasible or unbounded
673  // 20   CPX_PIVOT
674  //       User pivot used
675  //
676  // Pending return values
677  // ??case CPX_ABORT_DUAL_INFEAS
678  // ??case CPX_ABORT_CROSSOVER
679  // ??case CPX_INForUNBD
680  // ??case CPX_PIVOT
681
682  //Some more interesting stuff:
683
684  // CPX_PARAM_PROBMETHOD  1062  int  LPMETHOD
685  // 0 Automatic
686  // 1 Primal Simplex
687  // 2 Dual Simplex
688  // 3 Network Simplex
689  // 4 Standard Barrier
690  // Default: 0
691  // Description: Method for linear optimization.
692  // Determines which algorithm is used when CPXlpopt() (or "optimize"
693  // in the Interactive Optimizer) is called. Currently the behavior of
694  // the "Automatic" setting is that CPLEX simply invokes the dual
695  // simplex method, but this capability may be expanded in the future
696  // so that CPLEX chooses the method based on problem characteristics
697#if CPX_VERSION < 900
698  void statusSwitch(CPXENVptr cplexEnv(),int& stat){
699    int lpmethod;
700    CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod);
701    if (lpmethod==2){
702      if (stat==CPX_UNBOUNDED){
703        stat=CPX_INFEASIBLE;
704      }
705      else{
706        if (stat==CPX_INFEASIBLE)
707          stat=CPX_UNBOUNDED;
708      }
709    }
710  }
711#else
712  void statusSwitch(CPXENVptr,int&){}
713#endif
714
715  CplexLp::ProblemType CplexLp::_getPrimalType() const {
716    // Unboundedness not treated well: the following is from cplex 9.0 doc
717    // About Unboundedness
718
719    // The treatment of models that are unbounded involves a few
720    // subtleties. Specifically, a declaration of unboundedness means that
721    // ILOG CPLEX has determined that the model has an unbounded
722    // ray. Given any feasible solution x with objective z, a multiple of
723    // the unbounded ray can be added to x to give a feasible solution
724    // with objective z-1 (or z+1 for maximization models). Thus, if a
725    // feasible solution exists, then the optimal objective is
726    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
727    // a feasible solution exists. Users can call the routine CPXsolninfo
728    // to determine whether ILOG CPLEX has also concluded that the model
729    // has a feasible solution.
730
731    int stat = CPXgetstat(cplexEnv(), _prob);
732#if CPX_VERSION >= 800
733    switch (stat)
734      {
735      case CPX_STAT_OPTIMAL:
736        return OPTIMAL;
737      case CPX_STAT_UNBOUNDED:
738        return UNBOUNDED;
739      case CPX_STAT_INFEASIBLE:
740        return INFEASIBLE;
741      default:
742        return UNDEFINED;
743      }
744#else
745    statusSwitch(cplexEnv(),stat);
746    //CPXgetstat(cplexEnv(), _prob);
747    switch (stat) {
748    case 0:
749      return UNDEFINED; //Undefined
750    case CPX_OPTIMAL://Optimal
751      return OPTIMAL;
752    case CPX_UNBOUNDED://Unbounded
753      return INFEASIBLE;//In case of dual simplex
754      //return UNBOUNDED;
755    case CPX_INFEASIBLE://Infeasible
756      //    case CPX_IT_LIM_INFEAS:
757      //     case CPX_TIME_LIM_INFEAS:
758      //     case CPX_NUM_BEST_INFEAS:
759      //     case CPX_OPTIMAL_INFEAS:
760      //     case CPX_ABORT_INFEAS:
761      //     case CPX_ABORT_PRIM_INFEAS:
762      //     case CPX_ABORT_PRIM_DUAL_INFEAS:
763      return UNBOUNDED;//In case of dual simplex
764      //return INFEASIBLE;
765      //     case CPX_OBJ_LIM:
766      //     case CPX_IT_LIM_FEAS:
767      //     case CPX_TIME_LIM_FEAS:
768      //     case CPX_NUM_BEST_FEAS:
769      //     case CPX_ABORT_FEAS:
770      //     case CPX_ABORT_PRIM_DUAL_FEAS:
771      //       return FEASIBLE;
772    default:
773      return UNDEFINED; //Everything else comes here
774      //FIXME error
775    }
776#endif
777  }
778
779  // Cplex 9.0 status values
780  // CPX_STAT_ABORT_DUAL_OBJ_LIM
781  // CPX_STAT_ABORT_IT_LIM
782  // CPX_STAT_ABORT_OBJ_LIM
783  // CPX_STAT_ABORT_PRIM_OBJ_LIM
784  // CPX_STAT_ABORT_TIME_LIM
785  // CPX_STAT_ABORT_USER
786  // CPX_STAT_FEASIBLE_RELAXED
787  // CPX_STAT_INFEASIBLE
788  // CPX_STAT_INForUNBD
789  // CPX_STAT_NUM_BEST
790  // CPX_STAT_OPTIMAL
791  // CPX_STAT_OPTIMAL_FACE_UNBOUNDED
792  // CPX_STAT_OPTIMAL_INFEAS
793  // CPX_STAT_OPTIMAL_RELAXED
794  // CPX_STAT_UNBOUNDED
795
796  CplexLp::ProblemType CplexLp::_getDualType() const {
797    int stat = CPXgetstat(cplexEnv(), _prob);
798#if CPX_VERSION >= 800
799    switch (stat) {
800    case CPX_STAT_OPTIMAL:
801      return OPTIMAL;
802    case CPX_STAT_UNBOUNDED:
803      return INFEASIBLE;
804    default:
805      return UNDEFINED;
806    }
807#else
808    statusSwitch(cplexEnv(),stat);
809    switch (stat) {
810    case 0:
811      return UNDEFINED; //Undefined
812    case CPX_OPTIMAL://Optimal
813      return OPTIMAL;
814    case CPX_UNBOUNDED:
815      return INFEASIBLE;
816    default:
817      return UNDEFINED; //Everything else comes here
818      //FIXME error
819    }
820#endif
821  }
822
823  // CplexMip members
824
825  CplexMip::CplexMip()
826    : LpBase(), MipSolver(), CplexBase() {
827
828#if CPX_VERSION < 800
829    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
830#else
831    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
832#endif
833  }
834
835  CplexMip::CplexMip(const CplexEnv& env)
836    : LpBase(), MipSolver(), CplexBase(env) {
837
838#if CPX_VERSION < 800
839    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MIP);
840#else
841    CPXchgprobtype(cplexEnv(),  _prob, CPXPROB_MILP);
842#endif
843
844  }
845
846  CplexMip::CplexMip(const CplexMip& other)
847    : LpBase(), MipSolver(), CplexBase(other) {}
848
849  CplexMip::~CplexMip() {}
850
851  CplexMip* CplexMip::newSolver() const { return new CplexMip; }
852  CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); }
853
854  const char* CplexMip::_solverName() const { return "CplexMip"; }
855
856  void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) {
857
858    // Note If a variable is to be changed to binary, a call to CPXchgbds
859    // should also be made to change the bounds to 0 and 1.
860
861    switch (col_type){
862    case INTEGER: {
863      const char t = 'I';
864      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
865    } break;
866    case REAL: {
867      const char t = 'C';
868      CPXchgctype (cplexEnv(), _prob, 1, &i, &t);
869    } break;
870    default:
871      break;
872    }
873  }
874
875  CplexMip::ColTypes CplexMip::_getColType(int i) const {
876    char t;
877    CPXgetctype (cplexEnv(), _prob, &t, i, i);
878    switch (t) {
879    case 'I':
880      return INTEGER;
881    case 'C':
882      return REAL;
883    default:
884      LEMON_ASSERT(false, "Invalid column type");
885      return ColTypes();
886    }
887
888  }
889
890  CplexMip::SolveExitStatus CplexMip::_solve() {
891    int status;
892    _applyMessageLevel();
893    status = CPXmipopt (cplexEnv(), _prob);
894    if (status==0)
895      return SOLVED;
896    else
897      return UNSOLVED;
898
899  }
900
901
902  CplexMip::ProblemType CplexMip::_getType() const {
903
904    int stat = CPXgetstat(cplexEnv(), _prob);
905
906    //Fortunately, MIP statuses did not change for cplex 8.0
907    switch (stat) {
908    case CPXMIP_OPTIMAL:
909      // Optimal integer solution has been found.
910    case CPXMIP_OPTIMAL_TOL:
911      // Optimal soluton with the tolerance defined by epgap or epagap has
912      // been found.
913      return OPTIMAL;
914      //This also exists in later issues
915      //    case CPXMIP_UNBOUNDED:
916      //return UNBOUNDED;
917      case CPXMIP_INFEASIBLE:
918        return INFEASIBLE;
919    default:
920      return UNDEFINED;
921    }
922    //Unboundedness not treated well: the following is from cplex 9.0 doc
923    // About Unboundedness
924
925    // The treatment of models that are unbounded involves a few
926    // subtleties. Specifically, a declaration of unboundedness means that
927    // ILOG CPLEX has determined that the model has an unbounded
928    // ray. Given any feasible solution x with objective z, a multiple of
929    // the unbounded ray can be added to x to give a feasible solution
930    // with objective z-1 (or z+1 for maximization models). Thus, if a
931    // feasible solution exists, then the optimal objective is
932    // unbounded. Note that ILOG CPLEX has not necessarily concluded that
933    // a feasible solution exists. Users can call the routine CPXsolninfo
934    // to determine whether ILOG CPLEX has also concluded that the model
935    // has a feasible solution.
936  }
937
938  CplexMip::Value CplexMip::_getSol(int i) const {
939    Value x;
940    CPXgetmipx(cplexEnv(), _prob, &x, i, i);
941    return x;
942  }
943
944  CplexMip::Value CplexMip::_getSolValue() const {
945    Value objval;
946    CPXgetmipobjval(cplexEnv(), _prob, &objval);
947    return objval;
948  }
949
950} //namespace lemon
951
Note: See TracBrowser for help on using the repository browser.