COIN-OR::LEMON - Graph Library

source: lemon/lemon/cplex.cc @ 1210:d450a02728d0

1.2
Last change on this file since 1210:d450a02728d0 was 1183:2c48ba00fccd, checked in by Alpar Juttner <alpar@…>, 11 years ago

Merge bugfix #445 to branch 1.2

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