COIN-OR::LEMON - Graph Library

source: lemon/lemon/lp_cplex.cc @ 482:ed54c0d13df0

Last change on this file since 482:ed54c0d13df0 was 482:ed54c0d13df0, checked in by Balazs Dezso <deba@…>, 10 years ago

Thorough redesign of the LP/MIP interface (#44)

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